15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <fcntl.h>
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <gtest/gtest.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/fuse.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/fusefs/fuse_fs.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/kernel_handle.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/kernel_intercept.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/kernel_proxy.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "nacl_io/ostime.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using namespace nacl_io;
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class FuseFsForTesting : public FuseFs {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit FuseFsForTesting(fuse_operations* fuse_ops) {
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FsInitArgs args;
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    args.fuse_ops = fuse_ops;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(0, Init(args));
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Implementation of a simple flat memory filesystem.
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct File {
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  File() : mode(0666) { memset(&times, 0, sizeof(times)); }
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string name;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<uint8_t> data;
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  mode_t mode;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  timespec times[2];
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::vector<File> Files;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Files g_files;
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool IsValidPath(const char* path) {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path == NULL)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (strlen(path) <= 1)
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (path[0] != '/')
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)File* FindFile(const char* path) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!IsValidPath(path))
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (Files::iterator iter = g_files.begin(); iter != g_files.end(); ++iter) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (iter->name == &path[1])
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return &*iter;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NULL;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int testfs_getattr(const char* path, struct stat* stbuf) {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(stbuf, 0, sizeof(struct stat));
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (strcmp(path, "/") == 0) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    stbuf->st_mode = S_IFDIR | 0755;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  File* file = FindFile(path);
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (file == NULL)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -ENOENT;
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stbuf->st_mode = S_IFREG | file->mode;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stbuf->st_size = file->data.size();
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stbuf->st_atime = file->times[0].tv_sec;
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stbuf->st_atimensec = file->times[0].tv_nsec;
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stbuf->st_mtime = file->times[1].tv_sec;
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stbuf->st_mtimensec = file->times[1].tv_nsec;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 0;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int testfs_readdir(const char* path,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   void* buf,
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   fuse_fill_dir_t filler,
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   off_t offset,
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   struct fuse_file_info*) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (strcmp(path, "/") != 0)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -ENOENT;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  filler(buf, ".", NULL, 0);
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  filler(buf, "..", NULL, 0);
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (Files::iterator iter = g_files.begin(); iter != g_files.end(); ++iter) {
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    filler(buf, iter->name.c_str(), NULL, 0);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 0;
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint testfs_create(const char* path, mode_t mode, struct fuse_file_info* fi) {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!IsValidPath(path))
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -ENOENT;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  File* file = FindFile(path);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (file != NULL) {
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (fi->flags & O_EXCL)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return -EEXIST;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    g_files.push_back(File());
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    file = &g_files.back();
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    file->name = &path[1];  // Skip initial /
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file->mode = mode;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return 0;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int testfs_open(const char* path, struct fuse_file_info*) {
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // open is only called to open an existing file, otherwise create is
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // called. We don't need to do any additional work here, the path will be
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // passed to any other operations.
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return FindFile(path) != NULL;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int testfs_read(const char* path,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                char* buf,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                size_t size,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                off_t offset,
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                struct fuse_file_info* fi) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  File* file = FindFile(path);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (file == NULL)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -ENOENT;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t filesize = file->data.size();
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Trying to read past the end of the file.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (offset >= filesize)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (offset + size > filesize)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    size = filesize - offset;
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memcpy(buf, file->data.data() + offset, size);
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return size;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int testfs_write(const char* path,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 const char* buf,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 size_t size,
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 off_t offset,
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 struct fuse_file_info*) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  File* file = FindFile(path);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (file == NULL)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return -ENOENT;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t filesize = file->data.size();
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (offset + size > filesize)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    file->data.resize(offset + size);
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memcpy(file->data.data() + offset, buf, size);
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return size;
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint testfs_utimens(const char* path, const struct timespec times[2]) {
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  File* file = FindFile(path);
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (file == NULL)
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return -ENOENT;
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file->times[0] = times[0];
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file->times[1] = times[1];
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 0;
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint testfs_chmod(const char* path, mode_t mode) {
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  File* file = FindFile(path);
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (file == NULL)
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return -ENOENT;
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file->mode = mode;
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 0;
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char hello_world[] = "Hello, World!\n";
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)fuse_operations g_fuse_operations = {
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    0,               // flag_nopath
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    0,               // flag_reserved
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_getattr,  // getattr
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // readlink
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // mknod
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // mkdir
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // unlink
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // rmdir
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // symlink
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // rename
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // link
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_chmod,    // chmod
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // chown
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // truncate
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_open,     // open
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_read,     // read
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_write,    // write
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // statfs
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // flush
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // release
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // fsync
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // setxattr
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // getxattr
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // listxattr
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // removexattr
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // opendir
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_readdir,  // readdir
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // releasedir
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // fsyncdir
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // init
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // destroy
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // access
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_create,   // create
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // ftruncate
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // fgetattr
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // lock
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    testfs_utimens,  // utimens
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // bmap
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // ioctl
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // poll
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // write_buf
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // read_buf
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // flock
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NULL,            // fallocate
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class FuseFsTest : public ::testing::Test {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FuseFsTest();
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetUp();
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FuseFsForTesting fs_;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FuseFsTest::FuseFsTest() : fs_(&g_fuse_operations) {}
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FuseFsTest::SetUp() {
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Reset the filesystem.
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_files.clear();
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add a built-in file.
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t hello_len = strlen(hello_world);
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  File hello;
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  hello.name = "hello";
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  hello.data.resize(hello_len);
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memcpy(hello.data.data(), hello_world, hello_len);
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_files.push_back(hello);
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(FuseFsTest, OpenAndRead) {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode node;
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node));
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  char buffer[15] = {0};
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bytes_read = 0;
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HandleAttr attr;
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(strlen(hello_world), bytes_read);
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_STREQ(hello_world, buffer);
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Try to read past the end of the file.
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  attr.offs = strlen(hello_world) - 7;
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(7, bytes_read);
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_STREQ("World!\n", buffer);
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(FuseFsTest, CreateWithMode) {
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedNode node;
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  struct stat statbuf;
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, fs_.OpenWithMode(Path("/hello"),
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                O_RDWR | O_CREAT, 0723, &node));
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0, node->GetStat(&statbuf));
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(S_IFREG, statbuf.st_mode & S_IFMT);
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0723, statbuf.st_mode & ~S_IFMT);
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(FuseFsTest, CreateAndWrite) {
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode node;
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/foobar"), O_RDWR | O_CREAT, &node));
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HandleAttr attr;
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char message[] = "Something interesting";
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bytes_written;
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, node->Write(attr, &message[0], strlen(message), &bytes_written));
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(bytes_written, strlen(message));
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Now try to read the data back.
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  char buffer[40] = {0};
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bytes_read = 0;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, node->Read(attr, &buffer[0], sizeof(buffer), &bytes_read));
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(strlen(message), bytes_read);
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_STREQ(message, buffer);
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(FuseFsTest, GetStat) {
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct stat statbuf;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode node;
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node));
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, node->GetStat(&statbuf));
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(S_IFREG, statbuf.st_mode & S_IFMT);
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0666, statbuf.st_mode & ~S_IFMT);
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(strlen(hello_world), statbuf.st_size);
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/"), O_RDONLY, &node));
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, node->GetStat(&statbuf));
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(S_IFDIR, statbuf.st_mode & S_IFMT);
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0755, statbuf.st_mode & ~S_IFMT);
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Create a file and stat.
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/foobar"), O_RDWR | O_CREAT, &node));
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, node->GetStat(&statbuf));
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(S_IFREG, statbuf.st_mode & S_IFMT);
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0666, statbuf.st_mode & ~S_IFMT);
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, statbuf.st_size);
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(FuseFsTest, GetDents) {
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode root;
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/"), O_RDONLY, &root));
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct dirent entries[4];
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int bytes_read;
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try reading everything.
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, root->GetDents(0, &entries[0], sizeof(entries), &bytes_read));
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(3 * sizeof(dirent), bytes_read);
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ(".", entries[0].d_name);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("..", entries[1].d_name);
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("hello", entries[2].d_name);
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Try reading from an offset.
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&entries, 0, sizeof(entries));
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, root->GetDents(sizeof(dirent), &entries[0], 2 * sizeof(dirent),
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              &bytes_read));
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(2 * sizeof(dirent), bytes_read);
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("..", entries[0].d_name);
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("hello", entries[1].d_name);
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add a file and read again.
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedNode node;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, fs_.Open(Path("/foobar"), O_RDWR | O_CREAT, &node));
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0, root->GetDents(0, &entries[0], sizeof(entries), &bytes_read));
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(4 * sizeof(dirent), bytes_read);
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ(".", entries[0].d_name);
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("..", entries[1].d_name);
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("hello", entries[2].d_name);
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ("foobar", entries[3].d_name);
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(FuseFsTest, Utimens) {
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  struct stat statbuf;
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedNode node;
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  struct timespec times[2];
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  times[0].tv_sec = 1000;
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  times[0].tv_nsec = 2000;
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  times[1].tv_sec = 3000;
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  times[1].tv_nsec = 4000;
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node));
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0, node->Futimens(times));
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0, node->GetStat(&statbuf));
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(times[0].tv_sec, statbuf.st_atime);
3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(times[0].tv_nsec, statbuf.st_atimensec);
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(times[1].tv_sec, statbuf.st_mtime);
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(times[1].tv_nsec, statbuf.st_mtimensec);
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(FuseFsTest, Fchmod) {
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  struct stat statbuf;
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedNode node;
3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node));
3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, node->GetStat(&statbuf));
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0666, statbuf.st_mode & ~S_IFMT);
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, node->Fchmod(0777));
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(0, node->GetStat(&statbuf));
4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(0777, statbuf.st_mode & ~S_IFMT);
4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class KernelProxyFuseTest : public ::testing::Test {
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  KernelProxyFuseTest() {}
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetUp();
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void TearDown();
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  KernelProxy kp_;
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KernelProxyFuseTest::SetUp() {
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ASSERT_EQ(0, ki_push_state_for_testing());
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ASSERT_EQ(0, ki_init(&kp_));
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Register a fuse filesystem.
423effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  nacl_io_register_fs_type("flatfs", &g_fuse_operations);
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Unmount the passthrough FS and mount our fuse filesystem.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, kp_.umount("/"));
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, kp_.mount("", "/", "flatfs", 0, NULL));
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KernelProxyFuseTest::TearDown() {
431effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  nacl_io_unregister_fs_type("flatfs");
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ki_uninit();
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(KernelProxyFuseTest, Basic) {
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Write a file.
4391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int fd = ki_open("/hello", O_WRONLY | O_CREAT, 0777);
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_GT(fd, -1);
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(sizeof(hello_world),
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            ki_write(fd, hello_world, sizeof(hello_world)));
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, ki_close(fd));
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Then read it back in.
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  fd = ki_open("/hello", O_RDONLY, 0);
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_GT(fd, -1);
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  char buffer[30];
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(buffer, 0, sizeof(buffer));
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_EQ(sizeof(hello_world), ki_read(fd, buffer, sizeof(buffer)));
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_STREQ(hello_world, buffer);
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(0, ki_close(fd));
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
455