]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fusefs/mockfs.cc
zfs: merge openzfs/zfs@9cd71c860 (master)
[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_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_expected_write_errno = 0;
435         m_kernel_minor_version = kernel_minor_version;
436         m_maxreadahead = max_readahead;
437         m_maxwrite = MIN(max_write, max_max_write);
438         m_nready = -1;
439         m_pm = pm;
440         m_time_gran = time_gran;
441         m_quit = false;
442         m_last_unique = 0;
443         if (m_pm == KQ)
444                 m_kq = kqueue();
445         else
446                 m_kq = -1;
447
448         /*
449          * Kyua sets pwd to a testcase-unique tempdir; no need to use
450          * mkdtemp
451          */
452         /*
453          * googletest doesn't allow ASSERT_ in constructors, so we must throw
454          * instead.
455          */
456         if (mkdir("mountpoint" , 0755) && errno != EEXIST)
457                 throw(std::system_error(errno, std::system_category(),
458                         "Couldn't make mountpoint directory"));
459
460         switch (m_pm) {
461         case BLOCKING:
462                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR);
463                 break;
464         default:
465                 m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK);
466                 break;
467         }
468         if (m_fuse_fd < 0)
469                 throw(std::system_error(errno, std::system_category(),
470                         "Couldn't open /dev/fuse"));
471
472         m_pid = getpid();
473         m_child_pid = -1;
474
475         build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
476         build_iovec(&iov, &iovlen, "fspath",
477                     __DECONST(void *, "mountpoint"), -1);
478         build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1);
479         sprintf(fdstr, "%d", m_fuse_fd);
480         build_iovec(&iov, &iovlen, "fd", fdstr, -1);
481         if (allow_other) {
482                 build_iovec(&iov, &iovlen, "allow_other",
483                         __DECONST(void*, &trueval), sizeof(bool));
484         }
485         if (default_permissions) {
486                 build_iovec(&iov, &iovlen, "default_permissions",
487                         __DECONST(void*, &trueval), sizeof(bool));
488         }
489         if (push_symlinks_in) {
490                 build_iovec(&iov, &iovlen, "push_symlinks_in",
491                         __DECONST(void*, &trueval), sizeof(bool));
492         }
493         if (ro) {
494                 build_iovec(&iov, &iovlen, "ro",
495                         __DECONST(void*, &trueval), sizeof(bool));
496         }
497         if (async) {
498                 build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval),
499                         sizeof(bool));
500         }
501         if (noatime) {
502                 build_iovec(&iov, &iovlen, "noatime",
503                         __DECONST(void*, &trueval), sizeof(bool));
504         }
505         if (noclusterr) {
506                 build_iovec(&iov, &iovlen, "noclusterr",
507                         __DECONST(void*, &trueval), sizeof(bool));
508         }
509         if (nointr) {
510                 build_iovec(&iov, &iovlen, "nointr",
511                         __DECONST(void*, &trueval), sizeof(bool));
512         } else {
513                 build_iovec(&iov, &iovlen, "intr",
514                         __DECONST(void*, &trueval), sizeof(bool));
515         }
516         if (*fsname) {
517                 build_iovec(&iov, &iovlen, "fsname=",
518                         __DECONST(void*, fsname), -1);
519         }
520         if (*subtype) {
521                 build_iovec(&iov, &iovlen, "subtype=",
522                         __DECONST(void*, subtype), -1);
523         }
524         if (nmount(iov, iovlen, 0))
525                 throw(std::system_error(errno, std::system_category(),
526                         "Couldn't mount filesystem"));
527
528         // Setup default handler
529         ON_CALL(*this, process(_, _))
530                 .WillByDefault(Invoke(this, &MockFS::process_default));
531
532         init(flags);
533         bzero(&sa, sizeof(sa));
534         sa.sa_handler = sigint_handler;
535         sa.sa_flags = 0;        /* Don't set SA_RESTART! */
536         if (0 != sigaction(SIGUSR1, &sa, NULL))
537                 throw(std::system_error(errno, std::system_category(),
538                         "Couldn't handle SIGUSR1"));
539         if (pthread_create(&m_daemon_id, NULL, service, (void*)this))
540                 throw(std::system_error(errno, std::system_category(),
541                         "Couldn't Couldn't start fuse thread"));
542 }
543
544 MockFS::~MockFS() {
545         kill_daemon();
546         if (m_daemon_id != NULL) {
547                 pthread_join(m_daemon_id, NULL);
548                 m_daemon_id = NULL;
549         }
550         ::unmount("mountpoint", MNT_FORCE);
551         rmdir("mountpoint");
552         if (m_kq >= 0)
553                 close(m_kq);
554 }
555
556 void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) {
557         uint32_t inlen = in.header.len;
558         size_t fih = sizeof(in.header);
559         switch (in.header.opcode) {
560         case FUSE_LOOKUP:
561         case FUSE_RMDIR:
562         case FUSE_SYMLINK:
563         case FUSE_UNLINK:
564                 EXPECT_GT(inlen, fih) << "Missing request filename";
565                 // No redundant information for checking buflen
566                 break;
567         case FUSE_FORGET:
568                 EXPECT_EQ(inlen, fih + sizeof(in.body.forget));
569                 EXPECT_EQ((size_t)buflen, inlen);
570                 break;
571         case FUSE_GETATTR:
572                 EXPECT_EQ(inlen, fih + sizeof(in.body.getattr));
573                 EXPECT_EQ((size_t)buflen, inlen);
574                 break;
575         case FUSE_SETATTR:
576                 EXPECT_EQ(inlen, fih + sizeof(in.body.setattr));
577                 EXPECT_EQ((size_t)buflen, inlen);
578                 break;
579         case FUSE_READLINK:
580                 EXPECT_EQ(inlen, fih) << "Unexpected request body";
581                 EXPECT_EQ((size_t)buflen, inlen);
582                 break;
583         case FUSE_MKNOD:
584                 {
585                         size_t s;
586                         if (m_kernel_minor_version >= 12)
587                                 s = sizeof(in.body.mknod);
588                         else
589                                 s = FUSE_COMPAT_MKNOD_IN_SIZE;
590                         EXPECT_GE(inlen, fih + s) << "Missing request body";
591                         EXPECT_GT(inlen, fih + s) << "Missing request filename";
592                         // No redundant information for checking buflen
593                         break;
594                 }
595         case FUSE_MKDIR:
596                 EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) <<
597                         "Missing request body";
598                 EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) <<
599                         "Missing request filename";
600                 // No redundant information for checking buflen
601                 break;
602         case FUSE_RENAME:
603                 EXPECT_GE(inlen, fih + sizeof(in.body.rename)) <<
604                         "Missing request body";
605                 EXPECT_GT(inlen, fih + sizeof(in.body.rename)) <<
606                         "Missing request filename";
607                 // No redundant information for checking buflen
608                 break;
609         case FUSE_LINK:
610                 EXPECT_GE(inlen, fih + sizeof(in.body.link)) <<
611                         "Missing request body";
612                 EXPECT_GT(inlen, fih + sizeof(in.body.link)) <<
613                         "Missing request filename";
614                 // No redundant information for checking buflen
615                 break;
616         case FUSE_OPEN:
617                 EXPECT_EQ(inlen, fih + sizeof(in.body.open));
618                 EXPECT_EQ((size_t)buflen, inlen);
619                 break;
620         case FUSE_READ:
621                 EXPECT_EQ(inlen, fih + sizeof(in.body.read));
622                 EXPECT_EQ((size_t)buflen, inlen);
623                 break;
624         case FUSE_WRITE:
625                 {
626                         size_t s;
627
628                         if (m_kernel_minor_version >= 9)
629                                 s = sizeof(in.body.write);
630                         else
631                                 s = FUSE_COMPAT_WRITE_IN_SIZE;
632                         // I suppose a 0-byte write should be allowed
633                         EXPECT_GE(inlen, fih + s) << "Missing request body";
634                         EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size);
635                         break;
636                 }
637         case FUSE_DESTROY:
638         case FUSE_STATFS:
639                 EXPECT_EQ(inlen, fih);
640                 EXPECT_EQ((size_t)buflen, inlen);
641                 break;
642         case FUSE_RELEASE:
643                 EXPECT_EQ(inlen, fih + sizeof(in.body.release));
644                 EXPECT_EQ((size_t)buflen, inlen);
645                 break;
646         case FUSE_FSYNC:
647         case FUSE_FSYNCDIR:
648                 EXPECT_EQ(inlen, fih + sizeof(in.body.fsync));
649                 EXPECT_EQ((size_t)buflen, inlen);
650                 break;
651         case FUSE_SETXATTR:
652                 EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) <<
653                         "Missing request body";
654                 EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) <<
655                         "Missing request attribute name";
656                 // No redundant information for checking buflen
657                 break;
658         case FUSE_GETXATTR:
659                 EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) <<
660                         "Missing request body";
661                 EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) <<
662                         "Missing request attribute name";
663                 // No redundant information for checking buflen
664                 break;
665         case FUSE_LISTXATTR:
666                 EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr));
667                 EXPECT_EQ((size_t)buflen, inlen);
668                 break;
669         case FUSE_REMOVEXATTR:
670                 EXPECT_GT(inlen, fih) << "Missing request attribute name";
671                 // No redundant information for checking buflen
672                 break;
673         case FUSE_FLUSH:
674                 EXPECT_EQ(inlen, fih + sizeof(in.body.flush));
675                 EXPECT_EQ((size_t)buflen, inlen);
676                 break;
677         case FUSE_INIT:
678                 EXPECT_EQ(inlen, fih + sizeof(in.body.init));
679                 EXPECT_EQ((size_t)buflen, inlen);
680                 break;
681         case FUSE_OPENDIR:
682                 EXPECT_EQ(inlen, fih + sizeof(in.body.opendir));
683                 EXPECT_EQ((size_t)buflen, inlen);
684                 break;
685         case FUSE_READDIR:
686                 EXPECT_EQ(inlen, fih + sizeof(in.body.readdir));
687                 EXPECT_EQ((size_t)buflen, inlen);
688                 break;
689         case FUSE_RELEASEDIR:
690                 EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir));
691                 EXPECT_EQ((size_t)buflen, inlen);
692                 break;
693         case FUSE_GETLK:
694                 EXPECT_EQ(inlen, fih + sizeof(in.body.getlk));
695                 EXPECT_EQ((size_t)buflen, inlen);
696                 break;
697         case FUSE_SETLK:
698         case FUSE_SETLKW:
699                 EXPECT_EQ(inlen, fih + sizeof(in.body.setlk));
700                 EXPECT_EQ((size_t)buflen, inlen);
701                 break;
702         case FUSE_ACCESS:
703                 EXPECT_EQ(inlen, fih + sizeof(in.body.access));
704                 EXPECT_EQ((size_t)buflen, inlen);
705                 break;
706         case FUSE_CREATE:
707                 EXPECT_GE(inlen, fih + sizeof(in.body.create)) <<
708                         "Missing request body";
709                 EXPECT_GT(inlen, fih + sizeof(in.body.create)) <<
710                         "Missing request filename";
711                 // No redundant information for checking buflen
712                 break;
713         case FUSE_INTERRUPT:
714                 EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt));
715                 EXPECT_EQ((size_t)buflen, inlen);
716                 break;
717         case FUSE_FALLOCATE:
718                 EXPECT_EQ(inlen, fih + sizeof(in.body.fallocate));
719                 EXPECT_EQ((size_t)buflen, inlen);
720                 break;
721         case FUSE_BMAP:
722                 EXPECT_EQ(inlen, fih + sizeof(in.body.bmap));
723                 EXPECT_EQ((size_t)buflen, inlen);
724                 break;
725         case FUSE_LSEEK:
726                 EXPECT_EQ(inlen, fih + sizeof(in.body.lseek));
727                 EXPECT_EQ((size_t)buflen, inlen);
728                 break;
729         case FUSE_COPY_FILE_RANGE:
730                 EXPECT_EQ(inlen, fih + sizeof(in.body.copy_file_range));
731                 EXPECT_EQ(0ul, in.body.copy_file_range.flags);
732                 EXPECT_EQ((size_t)buflen, inlen);
733                 break;
734         case FUSE_NOTIFY_REPLY:
735         case FUSE_BATCH_FORGET:
736         case FUSE_IOCTL:
737         case FUSE_POLL:
738         case FUSE_READDIRPLUS:
739                 FAIL() << "Unsupported opcode?";
740         default:
741                 FAIL() << "Unknown opcode " << in.header.opcode;
742         }
743         /*
744          * Check that the ticket's unique value is sequential.  Technically it
745          * doesn't need to be sequential, merely unique.  But the current
746          * fusefs driver _does_ make it sequential, and that's easy to check
747          * for.
748          */
749         if (in.header.unique != ++m_last_unique)
750                 FAIL() << "Non-sequential unique value";
751 }
752
753 void MockFS::init(uint32_t flags) {
754         ssize_t buflen;
755
756         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
757         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
758
759         read_request(*in, buflen);
760         if (verbosity > 0)
761                 debug_request(*in, buflen);
762         audit_request(*in, buflen);
763         ASSERT_EQ(FUSE_INIT, in->header.opcode);
764
765         out->header.unique = in->header.unique;
766         out->header.error = 0;
767         out->body.init.major = FUSE_KERNEL_VERSION;
768         out->body.init.minor = m_kernel_minor_version;;
769         out->body.init.flags = in->body.init.flags & flags;
770         out->body.init.max_write = m_maxwrite;
771         out->body.init.max_readahead = m_maxreadahead;
772
773         if (m_kernel_minor_version < 23) {
774                 SET_OUT_HEADER_LEN(*out, init_7_22);
775         } else {
776                 out->body.init.time_gran = m_time_gran;
777                 SET_OUT_HEADER_LEN(*out, init);
778         }
779
780         write(m_fuse_fd, out.get(), out->header.len);
781 }
782
783 void MockFS::kill_daemon() {
784         m_quit = true;
785         if (m_daemon_id != NULL)
786                 pthread_kill(m_daemon_id, SIGUSR1);
787         // Closing the /dev/fuse file descriptor first allows unmount to
788         // succeed even if the daemon doesn't correctly respond to commands
789         // during the unmount sequence.
790         close(m_fuse_fd);
791         m_fuse_fd = -1;
792 }
793
794 void MockFS::loop() {
795         std::vector<std::unique_ptr<mockfs_buf_out>> out;
796
797         std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in);
798         ASSERT_TRUE(in != NULL);
799         while (!m_quit) {
800                 ssize_t buflen;
801
802                 bzero(in.get(), sizeof(*in));
803                 read_request(*in, buflen);
804                 m_expected_write_errno = 0;
805                 if (m_quit)
806                         break;
807                 if (verbosity > 0)
808                         debug_request(*in, buflen);
809                 audit_request(*in, buflen);
810                 if (pid_ok((pid_t)in->header.pid)) {
811                         process(*in, out);
812                 } else {
813                         /* 
814                          * Reject any requests from unknown processes.  Because
815                          * we actually do mount a filesystem, plenty of
816                          * unrelated system daemons may try to access it.
817                          */
818                         if (verbosity > 1)
819                                 printf("\tREJECTED (wrong pid %d)\n",
820                                         in->header.pid);
821                         process_default(*in, out);
822                 }
823                 for (auto &it: out)
824                         write_response(*it);
825                 out.clear();
826         }
827 }
828
829 int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen)
830 {
831         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
832
833         out->header.unique = 0; /* 0 means asynchronous notification */
834         out->header.error = FUSE_NOTIFY_INVAL_ENTRY;
835         out->body.inval_entry.parent = parent;
836         out->body.inval_entry.namelen = namelen;
837         strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry),
838                 name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry));
839         out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) +
840                 namelen;
841         debug_response(*out);
842         write_response(*out);
843         return 0;
844 }
845
846 int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len)
847 {
848         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
849
850         out->header.unique = 0; /* 0 means asynchronous notification */
851         out->header.error = FUSE_NOTIFY_INVAL_INODE;
852         out->body.inval_inode.ino = ino;
853         out->body.inval_inode.off = off;
854         out->body.inval_inode.len = len;
855         out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode);
856         debug_response(*out);
857         write_response(*out);
858         return 0;
859 }
860
861 int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size)
862 {
863         std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out);
864
865         out->header.unique = 0; /* 0 means asynchronous notification */
866         out->header.error = FUSE_NOTIFY_STORE;
867         out->body.store.nodeid = ino;
868         out->body.store.offset = off;
869         out->body.store.size = size;
870         bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size);
871         out->header.len = sizeof(out->header) + sizeof(out->body.store) + size;
872         debug_response(*out);
873         write_response(*out);
874         return 0;
875 }
876
877 bool MockFS::pid_ok(pid_t pid) {
878         if (pid == m_pid) {
879                 return (true);
880         } else if (pid == m_child_pid) {
881                 return (true);
882         } else {
883                 struct kinfo_proc *ki;
884                 bool ok = false;
885
886                 ki = kinfo_getproc(pid);
887                 if (ki == NULL)
888                         return (false);
889                 /* 
890                  * Allow access by the aio daemon processes so that our tests
891                  * can use aio functions
892                  */
893                 if (0 == strncmp("aiod", ki->ki_comm, 4))
894                         ok = true;
895                 free(ki);
896                 return (ok);
897         }
898 }
899
900 void MockFS::process_default(const mockfs_buf_in& in,
901                 std::vector<std::unique_ptr<mockfs_buf_out>> &out)
902 {
903         std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out);
904         out0->header.unique = in.header.unique;
905         out0->header.error = -EOPNOTSUPP;
906         out0->header.len = sizeof(out0->header);
907         out.push_back(std::move(out0));
908 }
909
910 void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) {
911         int nready = 0;
912         fd_set readfds;
913         pollfd fds[1];
914         struct kevent changes[1];
915         struct kevent events[1];
916         struct timespec timeout_ts;
917         struct timeval timeout_tv;
918         const int timeout_ms = 999;
919         int timeout_int, nfds;
920         int fuse_fd;
921
922         switch (m_pm) {
923         case BLOCKING:
924                 break;
925         case KQ:
926                 timeout_ts.tv_sec = 0;
927                 timeout_ts.tv_nsec = timeout_ms * 1'000'000;
928                 while (nready == 0) {
929                         EV_SET(&changes[0], m_fuse_fd, EVFILT_READ,
930                                 EV_ADD | EV_ONESHOT, 0, 0, 0);
931                         nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
932                                 &timeout_ts);
933                         if (m_quit)
934                                 return;
935                 }
936                 ASSERT_LE(0, nready) << strerror(errno);
937                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
938                 if (events[0].flags & EV_ERROR)
939                         FAIL() << strerror(events[0].data);
940                 else if (events[0].flags & EV_EOF)
941                         FAIL() << strerror(events[0].fflags);
942                 m_nready = events[0].data;
943                 break;
944         case POLL:
945                 timeout_int = timeout_ms;
946                 fds[0].fd = m_fuse_fd;
947                 fds[0].events = POLLIN;
948                 while (nready == 0) {
949                         nready = poll(fds, 1, timeout_int);
950                         if (m_quit)
951                                 return;
952                 }
953                 ASSERT_LE(0, nready) << strerror(errno);
954                 ASSERT_TRUE(fds[0].revents & POLLIN);
955                 break;
956         case SELECT:
957                 fuse_fd = m_fuse_fd;
958                 if (fuse_fd < 0)
959                         break;
960                 timeout_tv.tv_sec = 0;
961                 timeout_tv.tv_usec = timeout_ms * 1'000;
962                 nfds = fuse_fd + 1;
963                 while (nready == 0) {
964                         FD_ZERO(&readfds);
965                         FD_SET(fuse_fd, &readfds);
966                         nready = select(nfds, &readfds, NULL, NULL,
967                                 &timeout_tv);
968                         if (m_quit)
969                                 return;
970                 }
971                 ASSERT_LE(0, nready) << strerror(errno);
972                 ASSERT_TRUE(FD_ISSET(fuse_fd, &readfds));
973                 break;
974         default:
975                 FAIL() << "not yet implemented";
976         }
977         res = read(m_fuse_fd, &in, sizeof(in));
978
979         if (res < 0 && !m_quit) {
980                 m_quit = true;
981                 FAIL() << "read: " << strerror(errno);
982         }
983         ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit);
984         /*
985          * Inconsistently, fuse_in_header.len is the size of the entire
986          * request,including header, even though fuse_out_header.len excludes
987          * the size of the header.
988          */
989         ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit);
990 }
991
992 void MockFS::write_response(const mockfs_buf_out &out) {
993         fd_set writefds;
994         pollfd fds[1];
995         struct kevent changes[1];
996         struct kevent events[1];
997         int nready, nfds;
998         ssize_t r;
999
1000         switch (m_pm) {
1001         case BLOCKING:
1002                 break;
1003         case KQ:
1004                 EV_SET(&changes[0], m_fuse_fd, EVFILT_WRITE,
1005                         EV_ADD | EV_ONESHOT, 0, 0, 0);
1006                 nready = kevent(m_kq, &changes[0], 1, &events[0], 1,
1007                         NULL);
1008                 ASSERT_LE(0, nready) << strerror(errno);
1009                 ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd);
1010                 if (events[0].flags & EV_ERROR)
1011                         FAIL() << strerror(events[0].data);
1012                 else if (events[0].flags & EV_EOF)
1013                         FAIL() << strerror(events[0].fflags);
1014                 m_nready = events[0].data;
1015                 break;
1016         case POLL:
1017                 fds[0].fd = m_fuse_fd;
1018                 fds[0].events = POLLOUT;
1019                 nready = poll(fds, 1, INFTIM);
1020                 ASSERT_LE(0, nready) << strerror(errno);
1021                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1022                 ASSERT_TRUE(fds[0].revents & POLLOUT);
1023                 break;
1024         case SELECT:
1025                 FD_ZERO(&writefds);
1026                 FD_SET(m_fuse_fd, &writefds);
1027                 nfds = m_fuse_fd + 1;
1028                 nready = select(nfds, NULL, &writefds, NULL, NULL);
1029                 ASSERT_LE(0, nready) << strerror(errno);
1030                 ASSERT_EQ(1, nready) << "NULL timeout expired?";
1031                 ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds));
1032                 break;
1033         default:
1034                 FAIL() << "not yet implemented";
1035         }
1036         r = write(m_fuse_fd, &out, out.header.len);
1037         if (m_expected_write_errno) {
1038                 ASSERT_EQ(-1, r);
1039                 ASSERT_EQ(m_expected_write_errno, errno) << strerror(errno);
1040         } else {
1041                 ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno);
1042         }
1043 }
1044
1045 void* MockFS::service(void *pthr_data) {
1046         MockFS *mock_fs = (MockFS*)pthr_data;
1047
1048         mock_fs->loop();
1049
1050         return (NULL);
1051 }
1052
1053 void MockFS::unmount() {
1054         ::unmount("mountpoint", 0);
1055 }