blob: 322f37141ecab47299a9d88e13df4a6bddb606de [file] [log] [blame]
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPL.
See the file COPYING.LIB.
*/
#ifndef _FUSE_LOWLEVEL_H_
#define _FUSE_LOWLEVEL_H_
/* ----------------------------------------------------------- *
* Low level API *
* ----------------------------------------------------------- */
#include "fuse_common.h"
#include <utime.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/uio.h>
#ifdef __cplusplus
extern "C" {
#endif
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
typedef unsigned long fuse_ino_t;
typedef struct fuse_req *fuse_req_t;
struct fuse_session;
struct fuse_chan;
struct fuse_entry_param {
fuse_ino_t ino;
unsigned long generation;
struct stat attr;
double attr_timeout;
double entry_timeout;
};
struct fuse_ctx {
/** User ID of the calling process */
uid_t uid;
/** Group ID of the calling process */
gid_t gid;
/** Thread ID of the calling process */
pid_t pid;
};
/* 'to_set' flags in setattr */
#define FUSE_SET_ATTR_MODE (1 << 0)
#define FUSE_SET_ATTR_UID (1 << 1)
#define FUSE_SET_ATTR_GID (1 << 2)
#define FUSE_SET_ATTR_SIZE (1 << 3)
#define FUSE_SET_ATTR_ATIME (1 << 4)
#define FUSE_SET_ATTR_MTIME (1 << 5)
#define FUSE_SET_ATTR_CTIME (1 << 6)
/** Low level filesystem operations */
struct fuse_lowlevel_ops {
/** Initialize filesystem
*
* Called before any other filesystem method
*
* 'userdata' from fuse_lowlevel_new() is passed to this function
*
* There's no reply to this function
*/
void (*init) (void *);
/** Clean up filesystem
*
* Called on filesystem exit
*
* 'userdata' from fuse_lowlevel_new() is passed to this function
*
* There's no reply to this function
*/
void (*destroy)(void *);
/** Look up a directory entry by name
*
* Valid replies:
* fuse_reply_entry()
* fuse_reply_err()
*/
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
/**
* Forget about an inode
*
* The nlookup parameter indicates the number of lookups
* previously performed on this inode.
*
* If the filesystem implements inode lifetimes, it is recommended
* that inodes acquire a single reference on each lookup, and lose
* nlookup references on each forget.
*
* The filesystem may ignore forget calls, if the inodes don't
* need to have a limited lifetime.
*
* On unmount it is not guaranteed, that all referenced inodes
* will receive a forget message.
*
* Valid replies:
* fuse_reply_none()
*/
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
/** Get file attributes
*
* Valid replies:
* fuse_reply_attr()
* fuse_reply_err()
*/
void (*getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
/** Set file attributes
*
* Valid replies:
* fuse_reply_attr()
* fuse_reply_err()
*/
void (*setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
/** Read symbolic link
*
* Valid replies:
* fuse_reply_readlink
* fuse_reply_err
*/
void (*readlink)(fuse_req_t req, fuse_ino_t ino);
/** Create file node
*
* Create a regular file, character device, block device, fifo or
* socket node.
*
* Valid replies:
* fuse_reply_entry
* fuse_reply_err
*/
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
/** Create a directory
*
* Valid replies:
* fuse_reply_entry
* fuse_reply_err
*/
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
/** Remove a file
*
* Valid replies:
* fuse_reply_err
*/
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
/** Remove a directory
*
* Valid replies:
* fuse_reply_err
*/
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
/** Create a symbolic link
*
* Valid replies:
* fuse_reply_entry
* fuse_reply_err
*/
void (*symlink)(fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
/** Rename a file
*
* Valid replies:
* fuse_reply_err
*/
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
/** Create a hard link
*
* Valid replies:
* fuse_reply_entry
* fuse_reply_err
*/
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
/** Open a file
*
* Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and
* O_TRUNC) are available in fi->flags.
*
* Filesystem may store an arbitrary file handle (pointer, index,
* etc) in fi->fh, and use this in other all other file operations
* (read, write, flush, release, fsync).
*
* Filesystem may also implement stateless file I/O and not store
* anything in fi->fh.
*
* There are also some flags (direct_io, keep_cache) which the
* filesystem may set in fi, to change the way the file is opened.
* See fuse_file_info structure in <fuse_common.h> for more details.
*
* Valid replies:
* fuse_reply_open
* fuse_reply_err
*/
void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
/** Read data
*
* Read should send exactly the number of bytes requested except
* on EOF or error, otherwise the rest of the data will be
* substituted with zeroes. An exception to this is when the file
* has been opened in 'direct_io' mode, in which case the return
* value of the read system call will reflect the return value of
* this operation.
*
* fi->fh will contain the value set by the open method, or will
* be undefined if the open method didn't set any value.
*
* Valid replies:
* fuse_reply_buf
* fuse_reply_err
*/
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
/** Write data
*
* Write should return exactly the number of bytes requested
* except on error. An exception to this is when the file has
* been opened in 'direct_io' mode, in which case the return value
* of the write system call will reflect the return value of this
* operation.
*
* fi->fh will contain the value set by the open method, or will
* be undefined if the open method didn't set any value.
*
* Valid replies:
* fuse_reply_write
* fuse_reply_err
*/
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
/** Flush method
*
* This is called on each close() of the opened file.
*
* Since file descriptors can be duplicated (dup, dup2, fork), for
* one open call there may be many flush calls.
*
* fi->fh will contain the value set by the open method, or will
* be undefined if the open method didn't set any value.
*
* NOTE: the name of the method is misleading, since (unlike
* fsync) the filesystem is not forced to flush pending writes.
* One reason to flush data, is if the filesystem wants to return
* write errors.
*
* Valid replies:
* fuse_reply_err
*/
void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
/** Release an open file
*
* Release is called when there are no more references to an open
* file: all file descriptors are closed and all memory mappings
* are unmapped.
*
* For every open call there will be exactly one release call.
*
* The filesystem may reply with an error, but error values are
* not returned to close() or munmap() which triggered the
* release.
*
* fi->fh will contain the value set by the open method, or will
* be undefined if the open method didn't set any value.
* fi->flags will contain the same flags as for open.
*
* Valid replies:
* fuse_reply_err
*/
void (*release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
/** Synchronize file contents
*
* If the datasync parameter is non-zero, then only the user data
* should be flushed, not the meta data.
*
* Valid replies:
* fuse_reply_err
*/
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
/** Open a directory
*
* Filesystem may store an arbitrary file handle (pointer, index,
* etc) in fi->fh, and use this in other all other directory
* stream operations (readdir, releasedir, fsyncdir).
*
* Filesystem may also implement stateless directory I/O and not
* store anything in fi->fh, though that makes it impossible to
* implement standard conforming directory stream operations in
* case the contents of the directory can change between opendir
* and releasedir.
*
* Valid replies:
* fuse_reply_open
* fuse_reply_err
*/
void (*opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
/** Read directory
*
* Send a buffer filled using fuse_add_dirent(), with size not
* exceeding the requested size. Send an empty buffer on end of
* stream.
*
* fi->fh will contain the value set by the opendir method, or
* will be undefined if the opendir method didn't set any value.
*
* Valid replies:
* fuse_reply_buf
* fuse_reply_err
*/
void (*readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
/** Release an open directory
*
* For every opendir call there will be exactly one releasedir
* call.
*
* Any errors sent by releasedir will be ignored.
*
* fi->fh will contain the value set by the opendir method, or
* will be undefined if the opendir method didn't set any value.
*
* Valid replies:
* fuse_reply_err
*/
void (*releasedir)(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
/** Synchronize directory contents
*
* If the datasync parameter is non-zero, then only the directory
* contents should be flushed, not the meta data.
*
* fi->fh will contain the value set by the opendir method, or
* will be undefined if the opendir method didn't set any value.
*
* Valid replies:
* fuse_reply_err
*/
void (*fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
/** Get file system statistics
*
* Valid replies:
* fuse_reply_statfs
* fuse_reply_err
*/
void (*statfs) (fuse_req_t req);
/** Set an extended attribute
*
* Valid replies:
* fuse_reply_err
*/
void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
/** Get an extended attribute
*
* If size is zero, the size of the value should be sent with
* fuse_reply_xattr.
*
* If the size is non-zero, and the value fits in the buffer, the
* value should be sent with fuse_reply_buf.
*
* If the size is too small for the value, the ERANGE error should
* be sent.
*
* Valid replies:
* fuse_reply_buf
* fuse_reply_xattr
* fuse_reply_err
*/
void (*getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
/** List extended attribute names
*
* If size is zero, the total size of the attribute list should be
* sent with fuse_reply_xattr.
*
* If the size is non-zero, and the null charater separated
* attribute list fits in the buffer, the list should be sent with
* fuse_reply_buf.
*
* If the size is too small for the list, the ERANGE error should
* be sent.
*
* Valid replies:
* fuse_reply_buf
* fuse_reply_xattr
* fuse_reply_err
*/
void (*listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size);
/** Remove an extended attribute
*
* Valid replies:
* fuse_reply_err
*/
void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name);
};
/** Reply with an error code or success (zero)
*
* all except forget may send an error
*
* unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr
* and removexattr may send a succes code
*/
int fuse_reply_err(fuse_req_t req, int err);
/* forget */
int fuse_reply_none(fuse_req_t req);
/* lookup, mknod, mkdir, symlink, link */
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
/* getattr, setattr */
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
double attr_timeout);
/* readlink */
int fuse_reply_readlink(fuse_req_t req, const char *link);
/* open, opendir */
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
/* write */
int fuse_reply_write(fuse_req_t req, size_t count);
/* read, readdir, getxattr, listxattr */
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
/* statfs */
int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf);
/* getxattr, listxattr */
int fuse_reply_xattr(fuse_req_t req, size_t count);
/* ------------------------------------------ */
/* return the size of a directory entry */
size_t fuse_dirent_size(size_t namelen);
/* add a directory entry to the buffer */
char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
off_t off);
/* ------------------------------------------ */
void *fuse_req_userdata(fuse_req_t req);
const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
/* ------------------------------------------ */
int fuse_lowlevel_is_lib_option(const char *opt);
struct fuse_session *fuse_lowlevel_new(const char *opts,
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata);
struct fuse_chan *fuse_kern_chan_new(int fd);
/* ------------------------------------------ */
struct fuse_session_ops {
void (*process) (void *data, const char *buf, size_t len,
struct fuse_chan *ch);
void (*exit) (void *data, int val);
int (*exited) (void *data);
void (*destroy) (void *data);
};
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data);
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch);
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
struct fuse_chan *ch);
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
struct fuse_chan *ch);
void fuse_session_destroy(struct fuse_session *se);
void fuse_session_exit(struct fuse_session *se);
void fuse_session_reset(struct fuse_session *se);
int fuse_session_exited(struct fuse_session *se);
int fuse_session_loop(struct fuse_session *se);
int fuse_session_loop_mt(struct fuse_session *se);
/* ------------------------------------------ */
struct fuse_chan_ops {
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
size_t count);
void (*destroy)(struct fuse_chan *ch);
};
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data);
int fuse_chan_fd(struct fuse_chan *ch);
size_t fuse_chan_bufsize(struct fuse_chan *ch);
void *fuse_chan_data(struct fuse_chan *ch);
struct fuse_session *fuse_chan_session(struct fuse_chan *ch);
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count);
void fuse_chan_destroy(struct fuse_chan *ch);
/* ------------------------------------------ */
#ifdef __cplusplus
}
#endif
#endif /* _FUSE_LOWLEVEL_H_ */