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 */
39 static 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 }
47 static 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
hello_init(struct fuse_conn_info * conn,struct fuse_config * cfg)55 static 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
hello_getattr(const char * path,struct stat * stbuf,struct fuse_file_info * fi)63 static 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
hello_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi,enum fuse_readdir_flags flags)83 static 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
hello_open(const char * path,struct fuse_file_info * fi)101 static 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
hello_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)112 static 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
131 static 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
show_help(const char * progname)139 static 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
main(int argc,char * argv[])150 int 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