1/* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU GPLv2. 6 See the file COPYING. 7*/ 8 9/** @file 10 * 11 * minimal example filesystem using high-level API 12 * 13 * Compile with: 14 * 15 * gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello 16 * 17 * ## Source code ## 18 * \include hello.c 19 */ 20 21 22#define FUSE_USE_VERSION 31 23 24#include <fuse.h> 25#include <stdio.h> 26#include <string.h> 27#include <errno.h> 28#include <fcntl.h> 29#include <stddef.h> 30#include <assert.h> 31 32/* 33 * Command line options 34 * 35 * We can't set default values for the char* fields here because 36 * fuse_opt_parse would attempt to free() them when the user specifies 37 * different values on the command line. 38 */ 39static struct options { 40 const char *filename; 41 const char *contents; 42 int show_help; 43} options; 44 45#define OPTION(t, p) \ 46 { t, offsetof(struct options, p), 1 } 47static const struct fuse_opt option_spec[] = { 48 OPTION("--name=%s", filename), 49 OPTION("--contents=%s", contents), 50 OPTION("-h", show_help), 51 OPTION("--help", show_help), 52 FUSE_OPT_END 53}; 54 55static void *hello_init(struct fuse_conn_info *conn, 56 struct fuse_config *cfg) 57{ 58 (void) conn; 59 cfg->kernel_cache = 1; 60 return NULL; 61} 62 63static int hello_getattr(const char *path, struct stat *stbuf, 64 struct fuse_file_info *fi) 65{ 66 (void) fi; 67 int res = 0; 68 69 memset(stbuf, 0, sizeof(struct stat)); 70 if (strcmp(path, "/") == 0) { 71 stbuf->st_mode = S_IFDIR | 0755; 72 stbuf->st_nlink = 2; 73 } else if (strcmp(path+1, options.filename) == 0) { 74 stbuf->st_mode = S_IFREG | 0444; 75 stbuf->st_nlink = 1; 76 stbuf->st_size = strlen(options.contents); 77 } else 78 res = -ENOENT; 79 80 return res; 81} 82 83static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 84 off_t offset, struct fuse_file_info *fi, 85 enum fuse_readdir_flags flags) 86{ 87 (void) offset; 88 (void) fi; 89 (void) flags; 90 91 if (strcmp(path, "/") != 0) 92 return -ENOENT; 93 94 filler(buf, ".", NULL, 0, 0); 95 filler(buf, "..", NULL, 0, 0); 96 filler(buf, options.filename, NULL, 0, 0); 97 98 return 0; 99} 100 101static int hello_open(const char *path, struct fuse_file_info *fi) 102{ 103 if (strcmp(path+1, options.filename) != 0) 104 return -ENOENT; 105 106 if ((fi->flags & O_ACCMODE) != O_RDONLY) 107 return -EACCES; 108 109 return 0; 110} 111 112static int hello_read(const char *path, char *buf, size_t size, off_t offset, 113 struct fuse_file_info *fi) 114{ 115 size_t len; 116 (void) fi; 117 if(strcmp(path+1, options.filename) != 0) 118 return -ENOENT; 119 120 len = strlen(options.contents); 121 if (offset < len) { 122 if (offset + size > len) 123 size = len - offset; 124 memcpy(buf, options.contents + offset, size); 125 } else 126 size = 0; 127 128 return size; 129} 130 131static const struct fuse_operations hello_oper = { 132 .init = hello_init, 133 .getattr = hello_getattr, 134 .readdir = hello_readdir, 135 .open = hello_open, 136 .read = hello_read, 137}; 138 139static void show_help(const char *progname) 140{ 141 printf("usage: %s [options] <mountpoint>\n\n", progname); 142 printf("File-system specific options:\n" 143 " --name=<s> Name of the \"hello\" file\n" 144 " (default: \"hello\")\n" 145 " --contents=<s> Contents \"hello\" file\n" 146 " (default \"Hello, World!\\n\")\n" 147 "\n"); 148} 149 150int main(int argc, char *argv[]) 151{ 152 int ret; 153 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 154 155 /* Set defaults -- we have to use strdup so that 156 fuse_opt_parse can free the defaults if other 157 values are specified */ 158 options.filename = strdup("hello"); 159 options.contents = strdup("Hello World!\n"); 160 161 /* Parse options */ 162 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) 163 return 1; 164 165 /* When --help is specified, first print our own file-system 166 specific help text, then signal fuse_main to show 167 additional help (by adding `--help` to the options again) 168 without usage: line (by setting argv[0] to the empty 169 string) */ 170 if (options.show_help) { 171 show_help(argv[0]); 172 assert(fuse_opt_add_arg(&args, "--help") == 0); 173 args.argv[0][0] = '\0'; 174 } 175 176 ret = fuse_main(args.argc, args.argv, &hello_oper, NULL); 177 fuse_opt_free_args(&args); 178 return ret; 179} 180