]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fusefs/mockfs.cc
zfs: merge openzfs/zfs@10e36e176
[FreeBSD/FreeBSD.git] / tests / sys / fs / fusefs / mockfs.cc
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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_GETLK:
233                         printf(" fh=%#" PRIx64
234                                 " type=%u pid=%u",
235                                 in.body.getlk.fh,
236                                 in.body.getlk.lk.type,
237                                 in.body.getlk.lk.pid);
238                         if (verbosity >= 2) {
239                                 printf(" range=[%" PRIi64 ":%" PRIi64 "]",
240                                         in.body.getlk.lk.start,
241                                         in.body.getlk.lk.end);
242                         }
243                         break;
244                 case FUSE_INTERRUPT:
245                         printf(" unique=%" PRIu64, in.body.interrupt.unique);
246                         break;
247                 case FUSE_LINK:
248                         printf(" oldnodeid=%" PRIu64, in.body.link.oldnodeid);
249                         break;
250                 case FUSE_LISTXATTR:
251                         printf(" size=%" PRIu32, in.body.listxattr.size);
252                         break;
253                 case FUSE_LOOKUP:
254                         printf(" %s", in.body.lookup);
255                         break;
256                 case FUSE_LSEEK:
257                         switch (in.body.lseek.whence) {
258                         case SEEK_HOLE:
259                                 printf(" SEEK_HOLE offset=%jd",
260                                     in.body.lseek.offset);
261                                 break;
262                         case SEEK_DATA:
263                                 printf(" SEEK_DATA offset=%jd",
264                                     in.body.lseek.offset);
265                                 break;
266                         default:
267                                 printf(" whence=%u offset=%jd",
268                                     in.body.lseek.whence, in.body.lseek.offset);
269                                 break;
270                         }
271                         break;
272                 case FUSE_MKDIR:
273                         name = (const char*)in.body.bytes +
274                                 sizeof(fuse_mkdir_in);
275                         printf(" name=%s mode=%#o umask=%#o", name,
276                                 in.body.mkdir.mode, in.body.mkdir.umask);
277                         break;
278                 case FUSE_MKNOD:
279                         if (m_kernel_minor_version >= 12)
280                                 name = (const char*)in.body.bytes +
281                                         sizeof(fuse_mknod_in);
282                         else
283                                 name = (const char*)in.body.bytes +
284                                         FUSE_COMPAT_MKNOD_IN_SIZE;
285                         printf(" mode=%#o rdev=%x umask=%#o name=%s",
286                                 in.body.mknod.mode, in.body.mknod.rdev,
287                                 in.body.mknod.umask, name);
288                         break;
289                 case FUSE_OPEN:
290                         printf(" flags=%#x", in.body.open.flags);
291                         break;
292                 case FUSE_OPENDIR:
293                         printf(" flags=%#x", in.body.opendir.flags);
294                         break;
295                 case FUSE_READ:
296                         printf(" offset=%" PRIu64 " size=%u",
297                                 in.body.read.offset,
298                                 in.body.read.size);
299                         if (verbosity > 1)
300                                 printf(" flags=%#x", in.body.read.flags);
301                         break;
302                 case FUSE_READDIR:
303                         printf(" fh=%#" PRIx64 " offset=%" PRIu64 " size=%u",
304                                 in.body.readdir.fh, in.body.readdir.offset,
305                                 in.body.readdir.size);
306                         break;
307                 case FUSE_RELEASE:
308                         printf(" fh=%#" PRIx64 " flags=%#x lock_owner=%" PRIu64,
309                                 in.body.release.fh,
310                                 in.body.release.flags,
311                                 in.body.release.lock_owner);
312                         break;
313                 case FUSE_RENAME:
314                         {
315                                 const char *src = (const char*)in.body.bytes +
316                                         sizeof(fuse_rename_in);
317                                 const char *dst = src + strlen(src) + 1;
318                                 printf(" src=%s newdir=%" PRIu64 " dst=%s",
319                                         src, in.body.rename.newdir, dst);
320                         }
321                         break;
322                 case FUSE_SETATTR:
323                         if (verbosity <= 1) {
324                                 printf(" valid=%#x", in.body.setattr.valid);
325                                 break;
326                         }
327                         if (in.body.setattr.valid & FATTR_MODE)
328                                 printf(" mode=%#o", in.body.setattr.mode);
329                         if (in.body.setattr.valid & FATTR_UID)
330                                 printf(" uid=%u", in.body.setattr.uid);
331                         if (in.body.setattr.valid & FATTR_GID)
332                                 printf(" gid=%u", in.body.setattr.gid);
333                         if (in.body.setattr.valid & FATTR_SIZE)
334                                 printf(" size=%" PRIu64, in.body.setattr.size);
335                         if (in.body.setattr.valid & FATTR_ATIME)
336                                 printf(" atime=%" PRIu64 ".%u",
337                                         in.body.setattr.atime,
338                                         in.body.setattr.atimensec);
339                         if (in.body.setattr.valid & FATTR_MTIME)
340                                 printf(" mtime=%" PRIu64 ".%u",
341                                         in.body.setattr.mtime,
342                                         in.body.setattr.mtimensec);
343                         if (in.body.setattr.valid & FATTR_FH)
344                                 printf(" fh=%" PRIu64 "", in.body.setattr.fh);
345                         break;
346                 case FUSE_SETLK:
347                         printf(" fh=%#" PRIx64 " owner=%" PRIu64
348                                 " type=%u pid=%u",
349                                 in.body.setlk.fh, in.body.setlk.owner,
350                                 in.body.setlk.lk.type,
351                                 in.body.setlk.lk.pid);
352                         if (verbosity >= 2) {
353                                 printf(" range=[%" PRIi64 ":%" PRIi64 "]",
354                                         in.body.setlk.lk.start,
355                                         in.body.setlk.lk.end);
356                         }
357                         break;
358                 case FUSE_SETXATTR:
359                         /* 
360                          * In theory neither the xattr name and value need be
361                          * ASCII, but in this test suite they always are.
362                          */
363                         name = (const char*)in.body.bytes +
364                                 sizeof(fuse_setxattr_in);
365                         value = name + strlen(name) + 1;
366                         printf(" %s=%s", name, value);
367                         break;
368                 case FUSE_WRITE:
369                         printf(" fh=%#" PRIx64 " offset=%" PRIu64
370                                 " size=%u write_flags=%u",
371                                 in.body.write.fh,
372                                 in.body.write.offset, in.body.write.size,
373                                 in.body.write.write_flags);
374                         if (verbosity > 1)
375                                 printf(" flags=%#x", in.body.write.flags);
376                         break;
377                 default:
378                         break;
379         }
380         printf("\n");
381 }
382
383 /* 
384  * Debug a FUSE response.
385  *
386  * This is mostly useful for asynchronous notifications, which don't correspond
387  * to any request
388  */
389 void MockFS::debug_response(const mockfs_buf_out &out) {
390         const char *name;
391
392         if (verbosity == 0)
393                 return;
394
395         switch (out.header.error) {
396                 case FUSE_NOTIFY_INVAL_ENTRY:
397                         name = (const char*)out.body.bytes +
398                                 sizeof(fuse_notify_inval_entry_out);
399                         printf("<- INVAL_ENTRY parent=%" PRIu64 " %s\n",
400                                 out.body.inval_entry.parent, name);
401                         break;
402                 case FUSE_NOTIFY_INVAL_INODE:
403                         printf("<- INVAL_INODE ino=%" PRIu64 " off=%" PRIi64
404                                 " len=%" PRIi64 "\n",
405                                 out.body.inval_inode.ino,
406                                 out.body.inval_inode.off,
407                                 out.body.inval_inode.len);
408                         break;
409                 case FUSE_NOTIFY_STORE:
410                         printf("<- STORE ino=%" PRIu64 " off=%" PRIu64
411                                 " size=%" PRIu32 "\n",
412                                 out.body.store.nodeid,
413                                 out.body.store.offset,
414                                 out.body.store.size);
415                         break;
416                 default:
417                         break;
418         }
419 }
420
421 MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
422         bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags,
423         uint32_t kernel_minor_version, uint32_t max_write, bool async,
424         bool noclusterr, unsigned time_gran, bool nointr, bool noatime,
425         const char *fsname, const char *subtype)
426 {
427         struct sigaction sa;
428         struct iovec *iov = NULL;
429         int iovlen = 0;
430         char fdstr[15];
431         const bool trueval = true;
432
433         m_daemon_id = NULL;
434         m_kernel_minor_version = kernel_minor_version;
435         m_maxreadahead = max_readahead;
436         m_maxwrite = MIN(max_write, max_max_write);
437         m_nready = -1;
438         m_pm = pm;
439         m_time_gran = time_gran;
440         m_quit = false;
441         m_last_unique = 0;
442         if (m_pm == KQ)
443                 m_kq = kqueue();
444         else
445                 m_kq = -1;
446
447         /*
448          * Kyua sets pwd to a testcase-unique tempdir; no need to use
449          * mkdtemp
450          */
451         /*
452          * googletest doesn't allow ASSERT_ in constructors, so we must throw
453          * instead.
454          */
455         if (mkdir("mountpoint" , 0755) && errno != EEXIST)
456                 throw(std::system_error(errno, std::system_category(),
457                         "Couldn't make mountpoint directory"));
458
459         switch (m_pm) {
460         case BLOCKING:
461                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR);
462                 break;
463         default:
464                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK);
465                 break;
466         }
467         if (m_fuse_fd < 0)
468                 throw(std::system_error(errno, std::system_category(),
469                         "Couldn't open /dev/fuse"));
470
471         m_pid = getpid();
472         m_child_pid = -1;
473
474         build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
475         build_iovec(&iov, &iovlen, "fspath",
476                     __DECONST(void *, "mountpoint"), -1);
477         build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
478         sprintf(fdstr, "%d", m_fuse_fd);
479         build_iovec(&iov, &iovlen, "fd", fdstr, -1);
480         if (allow_other) {
481                 build_iovec(&iov, &iovlen, "allow_other",
482                         __DECONST(void*, &trueval), sizeof(bool));
483         }
484         if (default_permissions) {
485                 build_iovec(&iov, &iovlen, "default_permissions",
486                         __DECONST(void*, &trueval), sizeof(bool));
487         }
488         if (push_symlinks_in) {
489                 build_iovec(&iov, &iovlen, "push_symlinks_in",
490                         __DECONST(void*, &trueval), sizeof(bool));
491         }
492         if (ro) {
493                 build_iovec(&iov, &iovlen, "ro",
494                         __DECONST(void*, &trueval), sizeof(bool));
495         }
496         if (async) {
497                 build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval),
498                         sizeof(bool));
499         }
500         if (noatime) {
501                 build_iovec(&iov, &iovlen, "noatime",
502                         __DECONST(void*, &trueval), sizeof(bool));
503         }
504         if (noclusterr) {
505                 build_iovec(&iov, &iovlen, "noclusterr",
506                         __DECONST(void*, &trueval), sizeof(bool));
507         }
508         if (nointr) {
509                 build_iovec(&iov, &iovlen, "nointr",
510                         __DECONST(void*, &trueval), sizeof(bool));
511         } else {
512                 build_iovec(&iov, &iovlen, "intr",
513                         __DECONST(void*, &trueval), sizeof(bool));
514         }
515         if (*fsname) {
516                 build_iovec(&iov, &iovlen, "fsname=",
517                         __DECONST(void*, fsname), -1);
518         }
519         if (*subtype) {
520                 build_iovec(&iov, &iovlen, "subtype=",
521                         __DECONST(void*, subtype), -1);
522         }
523         if (nmount(iov, iovlen, 0))
524                 throw(std::system_error(errno, std::system_category(),
525                         "Couldn't mount filesystem"));
526
527         // Setup default handler
528         ON_CALL(*this, process(_, _))
529                 .WillByDefault(Invoke(this, &MockFS::process_default));
530
531         init(flags);
532         bzero(&sa, sizeof(sa));
533         sa.sa_handler = sigint_handler;
534         sa.sa_flags = 0;        /* Don't set SA_RESTART! */
535         if (0 != sigaction(SIGUSR1, &sa, NULL))
536                 throw(std::system_error(errno, std::system_category(),
537                         "Couldn't handle SIGUSR1"));
538         if (pthread_create(&m_daemon_id, NULL, service, (void*)this))
539                 throw(std::system_error(errno, std::system_category(),
540                         "Couldn't Couldn't start fuse thread"));
541 }
542
543 MockFS::~MockFS() {
544         kill_daemon();
545         if (m_daemon_id != NULL) {
546                 pthread_join(m_daemon_id, NULL);
547                 m_daemon_id = NULL;
548         }
549         ::unmount("mountpoint", MNT_FORCE);
550         rmdir("mountpoint");
551         if (m_kq >= 0)
552                 close(m_kq);
553 }
554
555 void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) {
556         uint32_t inlen = in.header.len;
557         size_t fih = sizeof(in.header);
558         switch (in.header.opcode) {
559         case FUSE_LOOKUP:
560         case FUSE_RMDIR:
561         case FUSE_SYMLINK:
562         case FUSE_UNLINK:
563                 EXPECT_GT(inlen, fih) << "Missing request filename";
564                 // No redundant information for checking buflen
565                 break;
566         case FUSE_FORGET:
567                 EXPECT_EQ(inlen, fih + sizeof(in.body.forget));
568                 EXPECT_EQ((size_t)buflen, inlen);
569                 break;
570         case FUSE_GETATTR:
571                 EXPECT_EQ(inlen, fih + sizeof(in.body.getattr));
572                 EXPECT_EQ((size_t)buflen, inlen);
573                 break;
574         case FUSE_SETATTR:
575                 EXPECT_EQ(inlen, fih + sizeof(in.body.setattr));
576                 EXPECT_EQ((size_t)buflen, inlen);
577                 break;
578         case FUSE_READLINK:
579                 EXPECT_EQ(inlen, fih) << "Unexpected request body";
580                 EXPECT_EQ((size_t)buflen, inlen);
581                 break;
582         case FUSE_MKNOD:
583                 {
584                         size_t s;
585                         if (m_kernel_minor_version >= 12)
586                                 s = sizeof(in.body.mknod);
587                         else
588                                 s = FUSE_COMPAT_MKNOD_IN_SIZE;
589                         EXPECT_GE(inlen, fih + s) << "Missing request body";
590                         EXPECT_GT(inlen, fih + s) << "Missing request filename";
591                         // No redundant information for checking buflen
592                         break;
593                 }
594         case FUSE_MKDIR:
595                 EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) <<
596                         "Missing request body";
597                 EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) <<
598                         "Missing request filename";
599                 // No redundant information for checking buflen
600                 break;
601         case FUSE_RENAME:
602                 EXPECT_GE(inlen, fih + sizeof(in.body.rename)) <<
603                         "Missing request body";
604                 EXPECT_GT(inlen, fih + sizeof(in.body.rename)) <<
605                         "Missing request filename";
606                 // No redundant information for checking buflen
607                 break;
608         case FUSE_LINK:
609                 EXPECT_GE(inlen, fih + sizeof(in.body.link)) <<
610                         "Missing request body";
611                 EXPECT_GT(inlen, fih + sizeof(in.body.link)) <<
612                         "Missing request filename";
613                 // No redundant information for checking buflen
614                 break;
615         case FUSE_OPEN:
616                 EXPECT_EQ(inlen, fih + sizeof(in.body.open));
617                 EXPECT_EQ((size_t)buflen, inlen);
618                 break;
619         case FUSE_READ:
620                 EXPECT_EQ(inlen, fih + sizeof(in.body.read));
621                 EXPECT_EQ((size_t)buflen, inlen);
622                 break;
623         case FUSE_WRITE:
624                 {
625                         size_t s;
626
627                         if (m_kernel_minor_version >= 9)
628                                 s = sizeof(in.body.write);
629                         else
630                                 s = FUSE_COMPAT_WRITE_IN_SIZE;
631                         // I suppose a 0-byte write should be allowed
632                         EXPECT_GE(inlen, fih + s) << "Missing request body";
633                         EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size);
634                         break;
635                 }
636         case FUSE_DESTROY:
637         case FUSE_STATFS:
638                 EXPECT_EQ(inlen, fih);
639                 EXPECT_EQ((size_t)buflen, inlen);
640                 break;
641         case FUSE_RELEASE:
642                 EXPECT_EQ(inlen, fih + sizeof(in.body.release));
643                 EXPECT_EQ((size_t)buflen, inlen);
644                 break;
645         case FUSE_FSYNC:
646         case FUSE_FSYNCDIR:
647                 EXPECT_EQ(inlen, fih + sizeof(in.body.fsync));
648                 EXPECT_EQ((size_t)buflen, inlen);
649                 break;
650         case FUSE_SETXATTR:
651                 EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) <<
652                         "Missing request body";
653                 EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) <<
654                         "Missing request attribute name";
655                 // No redundant information for checking buflen
656                 break;
657         case FUSE_GETXATTR:
658                 EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) <<
659                         "Missing request body";
660                 EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) <<
661                         "Missing request attribute name";
662                 // No redundant information for checking buflen
663                 break;
664         case FUSE_LISTXATTR:
665                 EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr));
666                 EXPECT_EQ((size_t)buflen, inlen);
667                 break;
668         case FUSE_REMOVEXATTR:
669                 EXPECT_GT(inlen, fih) << "Missing request attribute name";
670                 // No redundant information for checking buflen
671                 break;
672         case FUSE_FLUSH:
673                 EXPECT_EQ(inlen, fih + sizeof(in.body.flush));
674                 EXPECT_EQ((size_t)buflen, inlen);
675                 break;
676         case FUSE_INIT:
677                 EXPECT_EQ(inlen, fih + sizeof(in.body.init));
678                 EXPECT_EQ((size_t)buflen, inlen);
679                 break;
680         case FUSE_OPENDIR:
681                 EXPECT_EQ(inlen, fih + sizeof(in.body.opendir));
682                 EXPECT_EQ((size_t)buflen, inlen);
683                 break;
684         case FUSE_READDIR:
685                 EXPECT_EQ(inlen, fih + sizeof(in.body.readdir));
686                 EXPECT_EQ((size_t)buflen, inlen);
687                 break;
688         case FUSE_RELEASEDIR:
689                 EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir));
690                 EXPECT_EQ((size_t)buflen, inlen);
691                 break;
692         case FUSE_GETLK:
693                 EXPECT_EQ(inlen, fih + sizeof(in.body.getlk));
694                 EXPECT_EQ((size_t)buflen, inlen);
695                 break;
696         case FUSE_SETLK:
697         case FUSE_SETLKW:
698                 EXPECT_EQ(inlen, fih + sizeof(in.body.setlk));
699                 EXPECT_EQ((size_t)buflen, inlen);
700                 break;
701         case FUSE_ACCESS:
702                 EXPECT_EQ(inlen, fih + sizeof(in.body.access));
703                 EXPECT_EQ((size_t)buflen, inlen);
704                 break;
705         case FUSE_CREATE:
706                 EXPECT_GE(inlen, fih + sizeof(in.body.create)) <<
707                         "Missing request body";
708                 EXPECT_GT(inlen, fih + sizeof(in.body.create)) <<
709                         "Missing request filename";
710                 // No redundant information for checking buflen
711                 break;
712         case FUSE_INTERRUPT:
713                 EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt));
714                 EXPECT_EQ((size_t)buflen, inlen);
715                 break;
716         case FUSE_FALLOCATE:
717                 EXPECT_EQ(inlen, fih + sizeof(in.body.fallocate));
718                 EXPECT_EQ((size_t)buflen, inlen);
719                 break;
720         case FUSE_BMAP:
721                 EXPECT_EQ(inlen, fih + sizeof(in.body.bmap));
722                 EXPECT_EQ((size_t)buflen, inlen);
723                 break;
724         case FUSE_LSEEK:
725                 EXPECT_EQ(inlen, fih + sizeof(in.body.lseek));
726                 EXPECT_EQ((size_t)buflen, inlen);
727                 break;
728         case FUSE_COPY_FILE_RANGE:
729                 EXPECT_EQ(inlen, fih + sizeof(in.body.copy_file_range));
730                 EXPECT_EQ(0ul, in.body.copy_file_range.flags);
731                 EXPECT_EQ((size_t)buflen, inlen);
732                 break;
733         case FUSE_NOTIFY_REPLY:
734         case FUSE_BATCH_FORGET:
735         case FUSE_IOCTL:
736         case FUSE_POLL:
737         case FUSE_READDIRPLUS:
738                 FAIL() << "Unsupported opcode?";
739         default:
740                 FAIL() << "Unknown opcode " << in.header.opcode;
741         }
742         /*
743          * Check that the ticket's unique value is sequential.  Technically it
744          * doesn't need to be sequential, merely unique.  But the current
745          * fusefs driver _does_ make it sequential, and that's easy to check
746          * for.
747          */
748         if (in.header.unique != ++m_last_unique)
749                 FAIL() << "Non-sequential unique value";
750 }
751
752 void MockFS::init(uint32_t flags) {
753         ssize_t buflen;
754
755         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
756         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
757
758         read_request(*in, buflen);
759         if (verbosity > 0)
760                 debug_request(*in, buflen);
761         audit_request(*in, buflen);
762         ASSERT_EQ(FUSE_INIT, in->header.opcode);
763
764         out->header.unique = in->header.unique;
765         out->header.error = 0;
766         out->body.init.major = FUSE_KERNEL_VERSION;
767         out->body.init.minor = m_kernel_minor_version;;
768         out->body.init.flags = in->body.init.flags & flags;
769         out->body.init.max_write = m_maxwrite;
770         out->body.init.max_readahead = m_maxreadahead;
771
772         if (m_kernel_minor_version < 23) {
773                 SET_OUT_HEADER_LEN(*out, init_7_22);
774         } else {
775                 out->body.init.time_gran = m_time_gran;
776                 SET_OUT_HEADER_LEN(*out, init);
777         }
778
779         write(m_fuse_fd, out.get(), out->header.len);
780 }
781
782 void MockFS::kill_daemon() {
783         m_quit = true;
784         if (m_daemon_id != NULL)
785                 pthread_kill(m_daemon_id, SIGUSR1);
786         // Closing the /dev/fuse file descriptor first allows unmount to
787         // succeed even if the daemon doesn't correctly respond to commands
788         // during the unmount sequence.
789         close(m_fuse_fd);
790         m_fuse_fd = -1;
791 }
792
793 void MockFS::loop() {
794         std::vector<std::unique_ptr<mockfs_buf_out>> out;
795
796         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
797         ASSERT_TRUE(in != NULL);
798         while (!m_quit) {
799                 ssize_t buflen;
800
801                 bzero(in.get(), sizeof(*in));
802                 read_request(*in, buflen);
803                 if (m_quit)
804                         break;
805                 if (verbosity > 0)
806                         debug_request(*in, buflen);
807                 audit_request(*in, buflen);
808                 if (pid_ok((pid_t)in->header.pid)) {
809                         process(*in, out);
810                 } else {
811                         /* 
812                          * Reject any requests from unknown processes.  Because
813                          * we actually do mount a filesystem, plenty of
814                          * unrelated system daemons may try to access it.
815                          */
816                         if (verbosity > 1)
817                                 printf("\tREJECTED (wrong pid %d)\n",
818                                         in->header.pid);
819                         process_default(*in, out);
820                 }
821                 for (auto &it: out)
822                         write_response(*it);
823                 out.clear();
824         }
825 }
826
827 int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen)
828 {
829         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
830
831         out->header.unique = 0; /* 0 means asynchronous notification */
832         out->header.error = FUSE_NOTIFY_INVAL_ENTRY;
833         out->body.inval_entry.parent = parent;
834         out->body.inval_entry.namelen = namelen;
835         strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry),
836                 name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry));
837         out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) +
838                 namelen;
839         debug_response(*out);
840         write_response(*out);
841         return 0;
842 }
843
844 int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len)
845 {
846         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
847
848         out->header.unique = 0; /* 0 means asynchronous notification */
849         out->header.error = FUSE_NOTIFY_INVAL_INODE;
850         out->body.inval_inode.ino = ino;
851         out->body.inval_inode.off = off;
852         out->body.inval_inode.len = len;
853         out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode);
854         debug_response(*out);
855         write_response(*out);
856         return 0;
857 }
858
859 int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size)
860 {
861         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
862
863         out->header.unique = 0; /* 0 means asynchronous notification */
864         out->header.error = FUSE_NOTIFY_STORE;
865         out->body.store.nodeid = ino;
866         out->body.store.offset = off;
867         out->body.store.size = size;
868         bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size);
869         out->header.len = sizeof(out->header) + sizeof(out->body.store) + size;
870         debug_response(*out);
871         write_response(*out);
872         return 0;
873 }
874
875 bool MockFS::pid_ok(pid_t pid) {
876         if (pid == m_pid) {
877                 return (true);
878         } else if (pid == m_child_pid) {
879                 return (true);
880         } else {
881                 struct kinfo_proc *ki;
882                 bool ok = false;
883
884                 ki = kinfo_getproc(pid);
885                 if (ki == NULL)
886                         return (false);
887                 /* 
888                  * Allow access by the aio daemon processes so that our tests
889                  * can use aio functions
890                  */
891                 if (0 == strncmp("aiod", ki->ki_comm, 4))
892                         ok = true;
893                 free(ki);
894                 return (ok);
895         }
896 }
897
898 void MockFS::process_default(const mockfs_buf_in& in,
899                 std::vector<std::unique_ptr<mockfs_buf_out>> &out)
900 {
901         std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
902         out0->header.unique = in.header.unique;
903         out0->header.error = -EOPNOTSUPP;
904         out0->header.len = sizeof(out0->header);
905         out.push_back(std::move(out0));
906 }
907
908 void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) {
909         int nready = 0;
910         fd_set readfds;
911         pollfd fds[1];
912         struct kevent changes[1];
913         struct kevent events[1];
914         struct timespec timeout_ts;
915         struct timeval timeout_tv;
916         const int timeout_ms = 999;
917         int timeout_int, nfds;
918         int fuse_fd;
919
920         switch (m_pm) {
921         case BLOCKING:
922                 break;
923         case KQ:
924                 timeout_ts.tv_sec = 0;
925                 timeout_ts.tv_nsec = timeout_ms * 1'000'000;
926                 while (nready == 0) {
927                         EV_SET(&changes[0], m_fuse_fd, EVFILT_READ,
928                                 EV_ADD | EV_ONESHOT, 0, 0, 0);
929                         nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
930                                 &timeout_ts);
931                         if (m_quit)
932                                 return;
933                 }
934                 ASSERT_LE(0, nready) << strerror(errno);
935                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
936                 if (events[0].flags & EV_ERROR)
937                         FAIL() << strerror(events[0].data);
938                 else if (events[0].flags & EV_EOF)
939                         FAIL() << strerror(events[0].fflags);
940                 m_nready = events[0].data;
941                 break;
942         case POLL:
943                 timeout_int = timeout_ms;
944                 fds[0].fd = m_fuse_fd;
945                 fds[0].events = POLLIN;
946                 while (nready == 0) {
947                         nready = poll(fds, 1, timeout_int);
948                         if (m_quit)
949                                 return;
950                 }
951                 ASSERT_LE(0, nready) << strerror(errno);
952                 ASSERT_TRUE(fds[0].revents & POLLIN);
953                 break;
954         case SELECT:
955                 fuse_fd = m_fuse_fd;
956                 if (fuse_fd < 0)
957                         break;
958                 timeout_tv.tv_sec = 0;
959                 timeout_tv.tv_usec = timeout_ms * 1'000;
960                 nfds = fuse_fd + 1;
961                 while (nready == 0) {
962                         FD_ZERO(&readfds);
963                         FD_SET(fuse_fd, &readfds);
964                         nready = select(nfds, &readfds, NULL, NULL,
965                                 &timeout_tv);
966                         if (m_quit)
967                                 return;
968                 }
969                 ASSERT_LE(0, nready) << strerror(errno);
970                 ASSERT_TRUE(FD_ISSET(fuse_fd, &readfds));
971                 break;
972         default:
973                 FAIL() << "not yet implemented";
974         }
975         res = read(m_fuse_fd, &in, sizeof(in));
976
977         if (res < 0 && !m_quit) {
978                 m_quit = true;
979                 FAIL() << "read: " << strerror(errno);
980         }
981         ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit);
982         /*
983          * Inconsistently, fuse_in_header.len is the size of the entire
984          * request,including header, even though fuse_out_header.len excludes
985          * the size of the header.
986          */
987         ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit);
988 }
989
990 void MockFS::write_response(const mockfs_buf_out &out) {
991         fd_set writefds;
992         pollfd fds[1];
993         struct kevent changes[1];
994         struct kevent events[1];
995         int nready, nfds;
996         ssize_t r;
997
998         switch (m_pm) {
999         case BLOCKING:
1000                 break;
1001         case KQ:
1002                 EV_SET(&changes[0], m_fuse_fd, EVFILT_WRITE,
1003                         EV_ADD | EV_ONESHOT, 0, 0, 0);
1004                 nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
1005                         NULL);
1006                 ASSERT_LE(0, nready) << strerror(errno);
1007                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
1008                 if (events[0].flags & EV_ERROR)
1009                         FAIL() << strerror(events[0].data);
1010                 else if (events[0].flags & EV_EOF)
1011                         FAIL() << strerror(events[0].fflags);
1012                 m_nready = events[0].data;
1013                 break;
1014         case POLL:
1015                 fds[0].fd = m_fuse_fd;
1016                 fds[0].events = POLLOUT;
1017                 nready = poll(fds, 1, INFTIM);
1018                 ASSERT_LE(0, nready) << strerror(errno);
1019                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1020                 ASSERT_TRUE(fds[0].revents & POLLOUT);
1021                 break;
1022         case SELECT:
1023                 FD_ZERO(&writefds);
1024                 FD_SET(m_fuse_fd, &writefds);
1025                 nfds = m_fuse_fd + 1;
1026                 nready = select(nfds, NULL, &writefds, NULL, NULL);
1027                 ASSERT_LE(0, nready) << strerror(errno);
1028                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1029                 ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds));
1030                 break;
1031         default:
1032                 FAIL() << "not yet implemented";
1033         }
1034         r = write(m_fuse_fd, &out, out.header.len);
1035         if (out.expected_errno) {
1036                 ASSERT_EQ(-1, r);
1037                 ASSERT_EQ(out.expected_errno, errno) << strerror(errno);
1038         } else {
1039                 ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno);
1040         }
1041 }
1042
1043 void* MockFS::service(void *pthr_data) {
1044         MockFS *mock_fs = (MockFS*)pthr_data;
1045
1046         mock_fs->loop();
1047
1048         return (NULL);
1049 }
1050
1051 void MockFS::unmount() {
1052         ::unmount("mountpoint", 0);
1053 }