xref: /third_party/libfuse/example/hello.c (revision 6881f68f)
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