text: // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef LIBRARIES_NACL_IO_FUSE_H_
  #define LIBRARIES_NACL_IO_FUSE_H_
  
  #include "osinttypes.h"
  #include "ostypes.h"
  
  // These interfaces are copied from the FUSE library.
  //
  // FUSE has two interfaces that can be implemented: low-level and high-level.
  // In nacl_io, we only support the high-level interface.
  //
  // See http://fuse.sourceforge.net/ for more information.
  
  // This struct is typically passed to functions that would normally use return
  // or receive an fd; that is, operations to open/create a node, or operations
  // that act on an already opened node.
  struct fuse_file_info {
    // This is filled with the flags passed to open()
    int flags;
    // Deprecated in FUSE. Use fh instead.
    unsigned long fh_old;
    int writepage;
    // Currently unsupported
    unsigned int direct_io : 1;
    // Currently unsupported
    unsigned int keep_cache : 1;
    // Currently unsupported
    unsigned int flush : 1;
    // Currently unsupported
    unsigned int nonseekable : 1;
    // Currently unsupported
    unsigned int padding : 27;
    // This value is not used by nacl_io. It can be filled by the developer when
    // open() is called, and reused for subsequent calls on the same node.
    uint64_t fh;
    // Currently unsupported
    uint64_t lock_owner;
    // Currently unsupported
    uint32_t poll_events;
  };
  
  // A dummy structure that currently exists only to match the FUSE interface.
  struct fuse_conn_info {};
  
  // A function of this type will be passed to readdir (see below). The developer
  // should call this function once for each directory entry.
  //
  // See the documentation for readdir() below for more information on how to use
  // this function.
  typedef int (*fuse_fill_dir_t)(void* buf,
                                 const char* name,
                                 const struct stat* stbuf,
                                 off_t off);
  
  // This structure defines the interface to create a user mount. Pass this to
  // nacl_io_register_mount_type(). (see nacl_io.h)
  //
  // Example:
  //
  //     struct fuse_operations g_my_fuse_operations = { ... };
  //     ...
  //     nacl_io_register_mount_type("myfusefs", &g_my_fuse_operations);
  //     ...
  //     mount("", "/mnt/fuse", "myfusefs", 0, NULL);
  //
  // It is not necessary to implement every function -- nacl_io will first check
  // if the function pointer is NULL before calling it. If it is NULL and
  // required by the current operation, the call will fail and return ENOSYS in
  // errno.
  //
  // Except where specified below, each function should return one of the
  // following values:
  // == 0: operation completed successfully.
  // <  0: operation failed. The error is a negative errno. e.g. -EACCES, -EPERM,
  //       etc. The sign will be flipped when the error is actually set.
  //
  // Some functions (e.g. read, write) also return a positive count, which is the
  // number of bytes read/written.
  //
  struct fuse_operations {
    // Currently unsupported
    unsigned int flag_nopath : 1;
    unsigned int flag_reserved : 31;
  
    // Called when a mount of this type is initialized.
    void* (*init)(struct fuse_conn_info* conn);
    // Called when a mount of this type is unmounted.
    void (*destroy)(void*);
    // Called by access()
    int (*access)(const char* path, int mode);
    // Called when O_CREAT is passed to open()
    int (*create)(const char* path, mode_t mode, struct fuse_file_info*);
    // Called by stat()/fstat(). If this function pointer is non-NULL, it is
    // called, otherwise fuse_operations.getattr will be called.
    int (*fgetattr)(const char* path, struct stat*, struct fuse_file_info*);
    // Called by fsync(). The datasync paramater is not currently supported.
    int (*fsync)(const char* path, int datasync, struct fuse_file_info*);
    // Called by ftruncate()
    int (*ftruncate)(const char* path, off_t, struct fuse_file_info*);
    // Called by stat()/fstat(), but only when fuse_operations.fgetattr is NULL.
    // Also called by open() to determine if the path is a directory or a regular
    // file.
    int (*getattr)(const char* path, struct stat*);
    // Called by mkdir()
    int (*mkdir)(const char* path, mode_t);
    // Called when O_CREAT is passed to open(), but only if fuse_operations.create
    // is non-NULL.
    int (*mknod)(const char* path, mode_t, dev_t);
    // Called by open()
    int (*open)(const char* path, struct fuse_file_info*);
    // Called by getdents(), which is called by the more standard functions
    // opendir()/readdir().
    int (*opendir)(const char* path, struct fuse_file_info*);
    // Called by read(). Note that FUSE specifies that all reads will fill the
    // entire requested buffer. If this function returns less than that, the
    // remainder of the buffer is zeroed.
    int (*read)(const char* path, char* buf, size_t count, off_t,
                struct fuse_file_info*);
    // Called by getdents(), which is called by the more standard function
    // readdir().
    //
    // NOTE: it is the responsibility of this function to add the "." and ".."
    // entries.
    //
    // This function can be implemented one of two ways:
    // 1) Ignore the offset, and always write every entry in a given directory.
    //    In this case, you should always call filler() with an offset of 0. You
    //    can ignore the return value of the filler.
    //
    //   int my_readdir(const char* path, void* buf, fuse_fill_dir_t filler,
    //                  off_t offset, struct fuse_file_info*) {
    //     ...
    //     filler(buf, ".", NULL, 0);
    //     filler(buf, "..", NULL, 0);
    //     filler(buf, "file1", &file1stat, 0);
    //     filler(buf, "file2", &file2stat, 0);
    //     return 0;
    //   }
    //
    // 2) Only write entries starting from offset. Always pass the correct offset
    //    to the filler function. When the filler function returns 1, the buffer
    //    is full so you can exit readdir.
    //
    //   int my_readdir(const char* path, void* buf, fuse_fill_dir_t filler,
    //                  off_t offset, struct fuse_file_info*) {
    //     ...
    //     size_t kNumEntries = 4;
    //     const char* my_entries[] = { ".", "..", "file1", "file2" };
    //     int entry_index = offset / sizeof(dirent);
    //     offset = entry_index * sizeof(dirent);
    //     while (entry_index < kNumEntries) {
    //       int result = filler(buf, my_entries[entry_index], NULL, offset);
    //       if (filler == 1) {
    //         // buffer filled, we're done.
    //         return 0;
    //       }
    //       offset += sizeof(dirent);
    //       entry_index++;
    //     }
    //
    //     // No more entries, we're done.
    //     return 0;
    //   }
    //
    int (*readdir)(const char* path, void* buf, fuse_fill_dir_t filldir, off_t,
                   struct fuse_file_info*);
    // Called when the last reference to this node is released. This is only
    // called for regular files. For directories, fuse_operations.releasedir is
    // called instead.
    int (*release)(const char* path, struct fuse_file_info*);
    // Called when the last reference to this node is released. This is only
    // called for directories. For regular files, fuse_operations.release is
    // called instead.
    int (*releasedir)(const char* path, struct fuse_file_info*);
    // Called by rename()
    int (*rename)(const char* path, const char* new_path);
    // Called by rmdir()
    int (*rmdir)(const char* path);
    // Called by truncate(), as well as open() when O_TRUNC is passed.
    int (*truncate)(const char* path, off_t);
    // Called by unlink()
    int (*unlink)(const char* path);
    // Called by write(). Note that FUSE specifies that a write should always
    // return the full count, unless an error occurs.
    int (*write)(const char* path, const char* buf, size_t count, off_t,
                 struct fuse_file_info*);
  
    // The following functions are not currently called by the nacl_io
    // implementation of FUSE.
    int (*bmap)(const char*, size_t blocksize, uint64_t* idx);
    int (*chmod)(const char*, mode_t);
    int (*chown)(const char*, uid_t, gid_t);
    int (*fallocate)(const char*, int, off_t, off_t, struct fuse_file_info*);
    int (*flock)(const char*, struct fuse_file_info*, int op);
    int (*flush)(const char*, struct fuse_file_info*);
    int (*fsyncdir)(const char*, int, struct fuse_file_info*);
    int (*getxattr)(const char*, const char*, char*, size_t);
    int (*ioctl)(const char*, int cmd, void* arg, struct fuse_file_info*,
                 unsigned int flags, void* data);
    int (*link)(const char*, const char*);
    int (*listxattr)(const char*, char*, size_t);
    int (*lock)(const char*, struct fuse_file_info*, int cmd, struct flock*);
    int (*poll)(const char*, struct fuse_file_info*, struct fuse_pollhandle* ph,
                unsigned* reventsp);
    int (*read_buf)(const char*, struct fuse_bufvec** bufp, size_t size,
                    off_t off, struct fuse_file_info*);
    int (*readlink)(const char*, char*, size_t);
    int (*removexattr)(const char*, const char*);
    int (*setxattr)(const char*, const char*, const char*, size_t, int);
    int (*statfs)(const char*, struct statvfs*);
    int (*symlink)(const char*, const char*);
    int (*utimens)(const char*, const struct timespec tv[2]);
    int (*write_buf)(const char*, struct fuse_bufvec* buf, off_t off,
                     struct fuse_file_info*);
  };
  
  #endif  // LIBRARIES_NACL_IO_FUSE_H_
  