bkmeneguello
6/28/2013 - 12:58 PM

FUSE implementation skelekton

FUSE implementation skelekton

/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2013  Bruno Meneguello

  This program can be distributed under the terms of the GNU GPL.

  gcc -Wall skelfs.c `pkg-config fuse --cflags --libs` -o skelfs
*/

#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

/** Get file attributes.
 *
 * Similar to stat().  The 'st_dev' and 'st_blksize' fields are
 * ignored.	 The 'st_ino' field is ignored except if the 'use_ino'
 * mount option is given.
 */
static int fs_getattr(const char *path, struct stat *buf) {
	return 0;
}

/** Read the target of a symbolic link
 *
 * The buffer should be filled with a null terminated string.  The
 * buffer size argument includes the space for the terminating
 * null character.	If the linkname is too long to fit in the
 * buffer, it should be truncated.	The return value should be 0
 * for success.
 */
static int fs_readlink(const char *path, char *buf, size_t len) {
	return 0;
}

/* Deprecated, use readdir() instead */
//static int fs_getdir(const char *, fuse_dirh_t, fuse_dirfil_t) {
//	return 0;
//}

/** Create a file node
 *
 * This is called for creation of all non-directory, non-symlink
 * nodes.  If the filesystem defines a create() method, then for
 * regular files that will be called instead.
 */
static int fs_mknod(const char *path, mode_t mode, dev_t rdev) {
	return 0;
}

/** Create a directory 
 *
 * Note that the mode argument may not have the type specification
 * bits set, i.e. S_ISDIR(mode) can be false.  To obtain the
 * correct directory type bits use  mode|S_IFDIR
 * */
static int fs_mkdir(const char *path, mode_t mode) {
	return 0;
}

/** Remove a file */
static int fs_unlink(const char *path) {
	return 0;
}

/** Remove a directory */
static int fs_rmdir(const char *path) {
	return 0;
}

/** Create a symbolic link */
static int fs_symlink(const char *linkname, const char *path) {
	return 0;
}

/** Rename a file */
static int fs_rename(const char *oldpath, const char *newpath) {
	return 0;
}

/** Create a hard link to a file */
static int fs_link(const char *oldpath, const char *newpath) {
	return 0;
}

/** Change the permission bits of a file */
static int fs_chmod(const char *path, mode_t mode) {
	return 0;
}

/** Change the owner and group of a file */
static int fs_chown(const char *path, uid_t uid, gid_t gid) {
	return 0;
}

/** Change the size of a file */
static int fs_truncate(const char *path, off_t size) {
	return 0;
}

/** Change the access and/or modification times of a file
 *
 * Deprecated, use utimens() instead.
 */
//static int fs_utime(const char *, struct utimbuf *) {
//	return 0;
//}

/** File open operation
 *
 * No creation (O_CREAT, O_EXCL) and by default also no
 * truncation (O_TRUNC) flags will be passed to open(). If an
 * application specifies O_TRUNC, fuse first calls truncate()
 * and then open(). Only if 'atomic_o_trunc' has been
 * specified and kernel version is 2.6.24 or later, O_TRUNC is
 * passed on to open.
 *
 * Unless the 'default_permissions' mount option is given,
 * open should check if the operation is permitted for the
 * given flags. Optionally open may also return an arbitrary
 * filehandle in the fuse_file_info structure, which will be
 * passed to all file operations.
 *
 * Changed in version 2.2
 */
static int fs_open(const char *path, struct fuse_file_info *fi) {
	return 0;
}

/** Read data from an open file
 *
 * Read should return 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
 * 'direct_io' mount option is specified, in which case the return
 * value of the read system call will reflect the return value of
 * this operation.
 *
 * Changed in version 2.2
 */
static int fs_read(const char *path, char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
	return 0;
}

/** Write data to an open file
 *
 * Write should return exactly the number of bytes requested
 * except on error.	 An exception to this is when the 'direct_io'
 * mount option is specified (see read operation).
 *
 * Changed in version 2.2
 */
static int fs_write(const char *path, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
	return 0;
}

/** Get file system statistics
 *
 * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
 *
 * Replaced 'struct statfs' parameter with 'struct statvfs' in
 * version 2.5
 */
static int fs_statfs(const char *path, struct statvfs *buf) {
	return 0;
}

/** Possibly flush cached data
 *
 * BIG NOTE: This is not equivalent to fsync().  It's not a
 * request to sync dirty data.
 *
 * Flush is called on each close() of a file descriptor.  So if a
 * filesystem wants to return write errors in close() and the file
 * has cached dirty data, this is a good place to write back data
 * and return any errors.  Since many applications ignore close()
 * errors this is not always useful.
 *
 * NOTE: The flush() method may be called more than once for each
 * open().	This happens if more than one file descriptor refers
 * to an opened file due to dup(), dup2() or fork() calls.	It is
 * not possible to determine if a flush is final, so each flush
 * should be treated equally.  Multiple write-flush sequences are
 * relatively rare, so this shouldn't be a problem.
 *
 * Filesystems shouldn't assume that flush will always be called
 * after some writes, or that if will be called at all.
 *
 * Changed in version 2.2
 */
static int fs_flush(const char *path, struct fuse_file_info *fi) {
	return 0;
}

/** 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
 * with the same flags and file descriptor.	 It is possible to
 * have a file opened more than once, in which case only the last
 * release will mean, that no more reads/writes will happen on the
 * file.  The return value of release is ignored.
 *
 * Changed in version 2.2
 */
static int fs_release(const char *path, struct fuse_file_info *fi) {
	return 0;
}

/** Synchronize file contents
 *
 * If the datasync parameter is non-zero, then only the user data
 * should be flushed, not the meta data.
 *
 * Changed in version 2.2
 */
static int fs_fsync(const char *path, int datasync, struct fuse_file_info *fi) {
	return 0;
}

/** Set extended attributes */
static int fs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) {
	return 0;
}

/** Get extended attributes */
static int fs_getxattr(const char *path, const char *name, char *value, size_t size) {
	return 0;
}

/** List extended attributes */
static int fs_listxattr(const char *path, char *list, size_t size) {
	return 0;
}

/** Remove extended attributes */
static int fs_removexattr(const char *path, const char *name) {
	return 0;
}

/** Open directory
 *
 * Unless the 'default_permissions' mount option is given,
 * this method should check if opendir is permitted for this
 * directory. Optionally opendir may also return an arbitrary
 * filehandle in the fuse_file_info structure, which will be
 * passed to readdir, closedir and fsyncdir.
 *
 * Introduced in version 2.3
 */
static int fs_opendir(const char *path, struct fuse_file_info *fi) {
	return 0;
}

/** Read directory
 *
 * This supersedes the old getdir() interface.  New applications
 * should use this.
 *
 * The filesystem may choose between two modes of operation:
 *
 * 1) The readdir implementation ignores the offset parameter, and
 * passes zero to the filler function's offset.  The filler
 * function will not return '1' (unless an error happens), so the
 * whole directory is read in a single readdir operation.  This
 * works just like the old getdir() method.
 *
 * 2) The readdir implementation keeps track of the offsets of the
 * directory entries.  It uses the offset parameter and always
 * passes non-zero offset to the filler function.  When the buffer
 * is full (or an error happens) the filler function will return
 * '1'.
 *
 * Introduced in version 2.3
 */
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off, struct fuse_file_info *fi) {
	return 0;
}

/** Release directory
 *
 * Introduced in version 2.3
 */
static int fs_releasedir(const char *path, struct fuse_file_info *fi) {
	return 0;
}

/** Synchronize directory contents
 *
 * If the datasync parameter is non-zero, then only the user data
 * should be flushed, not the meta data
 *
 * Introduced in version 2.3
 */
static int fs_fsyncdir(const char *path, int datasync, struct fuse_file_info *fi) {
	return 0;
}

/**
 * Initialize filesystem
 *
 * The return value will passed in the private_data field of
 * fuse_context to all file operations and as a parameter to the
 * destroy() method.
 *
 * Introduced in version 2.3
 * Changed in version 2.6
 */
static void *fs_init(struct fuse_conn_info *conn) {
	return 0;
}

/**
 * Clean up filesystem
 *
 * Called on filesystem exit.
 *
 * Introduced in version 2.3
 */
static void fs_destroy(void *data) {
	
}

/**
 * Check file access permissions
 *
 * This will be called for the access() system call.  If the
 * 'default_permissions' mount option is given, this method is not
 * called.
 *
 * This method is not called under Linux kernel versions 2.4.x
 *
 * Introduced in version 2.5
 */
static int fs_access(const char *path, int mask) {
	return 0;
}

/**
 * Create and open a file
 *
 * If the file does not exist, first create it with the specified
 * mode, and then open it.
 *
 * If this method is not implemented or under Linux kernel
 * versions earlier than 2.6.15, the mknod() and open() methods
 * will be called instead.
 *
 * Introduced in version 2.5
 */
static int fs_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
	return 0;
}

/**
 * Change the size of an open file
 *
 * This method is called instead of the truncate() method if the
 * truncation was invoked from an ftruncate() system call.
 *
 * If this method is not implemented or under Linux kernel
 * versions earlier than 2.6.15, the truncate() method will be
 * called instead.
 *
 * Introduced in version 2.5
 */
static int fs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) {
	return 0;
}

/**
 * Get attributes from an open file
 *
 * This method is called instead of the getattr() method if the
 * file information is available.
 *
 * Currently this is only called after the create() method if that
 * is implemented (see above).  Later it may be called for
 * invocations of fstat() too.
 *
 * Introduced in version 2.5
 */
static int fs_fgetattr(const char *path, struct stat *buf, struct fuse_file_info *fi) {
	return 0;
}

/**
 * Perform POSIX file locking operation
 *
 * The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
 *
 * For the meaning of fields in 'struct flock' see the man page
 * for fcntl(2).  The l_whence field will always be set to
 * SEEK_SET.
 *
 * For checking lock ownership, the 'fuse_file_info->owner'
 * argument must be used.
 *
 * For F_GETLK operation, the library will first check currently
 * held locks, and if a conflicting lock is found it will return
 * information without calling this method.	 This ensures, that
 * for local locks the l_pid field is correctly filled in.	The
 * results may not be accurate in case of race conditions and in
 * the presence of hard links, but it's unlikly that an
 * application would rely on accurate GETLK results in these
 * cases.  If a conflicting lock is not found, this method will be
 * called, and the filesystem may fill out l_pid by a meaningful
 * value, or it may leave this field zero.
 *
 * For F_SETLK and F_SETLKW the l_pid field will be set to the pid
 * of the process performing the locking operation.
 *
 * Note: if this method is not implemented, the kernel will still
 * allow file locking to work locally.  Hence it is only
 * interesting for network filesystems and similar.
 *
 * Introduced in version 2.6
 */
static int fs_lock(const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) {
	return 0;
}

/**
 * Change the access and modification times of a file with
 * nanosecond resolution
 *
 * Introduced in version 2.6
 */
static int fs_utimens(const char *path, const struct timespec tv[2]) {
	return 0;
}

/**
 * Map block index within file to block index within device
 *
 * Note: This makes sense only for block device backed filesystems
 * mounted with the 'blkdev' option
 *
 * Introduced in version 2.6
 */
static int fs_bmap(const char *path, size_t blocksize, uint64_t *idx) {
	return 0;
}

/**
 * Ioctl
 *
 * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
 * 64bit environment.  The size and direction of data is
 * determined by _IOC_*() decoding of cmd.  For _IOC_NONE,
 * data will be NULL, for _IOC_WRITE data is out area, for
 * _IOC_READ in area and if both are set in/out area.  In all
 * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
 *
 * Introduced in version 2.8
 */
static int fs_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data) {
	return 0;
}

/**
 * Poll for IO readiness events
 *
 * Note: If ph is non-NULL, the client should notify
 * when IO readiness events occur by calling
 * fuse_notify_poll() with the specified ph.
 *
 * Regardless of the number of times poll with a non-NULL ph
 * is received, single notification is enough to clear all.
 * Notifying more times incurs overhead but doesn't harm
 * correctness.
 *
 * The callee is responsible for destroying ph with
 * fuse_pollhandle_destroy() when no longer in use.
 *
 * Introduced in version 2.8
 */
static int fs_poll(const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) {
	return 0;
}

static struct fuse_operations fs_oper = {
	.getattr     = fs_getattr,
	.readlink    = fs_readlink,
	.mknod       = fs_mknod,
	.mkdir       = fs_mkdir,
	.unlink      = fs_unlink,
	.rmdir       = fs_rmdir,
	.symlink     = fs_symlink,
	.rename      = fs_rename,
	.link        = fs_link,
	.chmod       = fs_chmod,
	.chown       = fs_chown,
	.truncate    = fs_truncate,
	.open        = fs_open,
	.read        = fs_read,
	.write       = fs_write,
	.statfs      = fs_statfs,
	.flush       = fs_flush,
	.release     = fs_release,
	.fsync       = fs_fsync,
	.setxattr    = fs_setxattr,
	.getxattr    = fs_getxattr,
	.listxattr   = fs_listxattr,
	.removexattr = fs_removexattr,
	.opendir     = fs_opendir,
	.readdir     = fs_readdir,
	.releasedir  = fs_releasedir,
	.fsyncdir    = fs_fsyncdir,
	.init        = fs_init,
	.destroy     = fs_destroy,
	.access      = fs_access,
	.create      = fs_create,
	.ftruncate   = fs_ftruncate,
	.fgetattr    = fs_fgetattr,
	.lock        = fs_lock,
	.utimens     = fs_utimens,
	.bmap        = fs_bmap,
	.ioctl       = fs_ioctl,
	.poll        = fs_poll,
};

int main(int argc, char *argv[]) {
	return fuse_main(argc, argv, &fs_oper, NULL);
}