• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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