16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE: Filesystem in Userspace
36881f68fSopenharmony_ci  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
46881f68fSopenharmony_ci
56881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU GPLv2.
66881f68fSopenharmony_ci  See the file COPYING.
76881f68fSopenharmony_ci*/
86881f68fSopenharmony_ci
96881f68fSopenharmony_ci/** @file
106881f68fSopenharmony_ci *
116881f68fSopenharmony_ci * minimal example filesystem using high-level API
126881f68fSopenharmony_ci *
136881f68fSopenharmony_ci * Compile with:
146881f68fSopenharmony_ci *
156881f68fSopenharmony_ci *     gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello
166881f68fSopenharmony_ci *
176881f68fSopenharmony_ci * ## Source code ##
186881f68fSopenharmony_ci * \include hello.c
196881f68fSopenharmony_ci */
206881f68fSopenharmony_ci
216881f68fSopenharmony_ci
226881f68fSopenharmony_ci#define FUSE_USE_VERSION 31
236881f68fSopenharmony_ci
246881f68fSopenharmony_ci#include <fuse.h>
256881f68fSopenharmony_ci#include <stdio.h>
266881f68fSopenharmony_ci#include <string.h>
276881f68fSopenharmony_ci#include <errno.h>
286881f68fSopenharmony_ci#include <fcntl.h>
296881f68fSopenharmony_ci#include <stddef.h>
306881f68fSopenharmony_ci#include <assert.h>
316881f68fSopenharmony_ci
326881f68fSopenharmony_ci/*
336881f68fSopenharmony_ci * Command line options
346881f68fSopenharmony_ci *
356881f68fSopenharmony_ci * We can't set default values for the char* fields here because
366881f68fSopenharmony_ci * fuse_opt_parse would attempt to free() them when the user specifies
376881f68fSopenharmony_ci * different values on the command line.
386881f68fSopenharmony_ci */
396881f68fSopenharmony_cistatic struct options {
406881f68fSopenharmony_ci	const char *filename;
416881f68fSopenharmony_ci	const char *contents;
426881f68fSopenharmony_ci	int show_help;
436881f68fSopenharmony_ci} options;
446881f68fSopenharmony_ci
456881f68fSopenharmony_ci#define OPTION(t, p)                           \
466881f68fSopenharmony_ci    { t, offsetof(struct options, p), 1 }
476881f68fSopenharmony_cistatic const struct fuse_opt option_spec[] = {
486881f68fSopenharmony_ci	OPTION("--name=%s", filename),
496881f68fSopenharmony_ci	OPTION("--contents=%s", contents),
506881f68fSopenharmony_ci	OPTION("-h", show_help),
516881f68fSopenharmony_ci	OPTION("--help", show_help),
526881f68fSopenharmony_ci	FUSE_OPT_END
536881f68fSopenharmony_ci};
546881f68fSopenharmony_ci
556881f68fSopenharmony_cistatic void *hello_init(struct fuse_conn_info *conn,
566881f68fSopenharmony_ci			struct fuse_config *cfg)
576881f68fSopenharmony_ci{
586881f68fSopenharmony_ci	(void) conn;
596881f68fSopenharmony_ci	cfg->kernel_cache = 1;
606881f68fSopenharmony_ci	return NULL;
616881f68fSopenharmony_ci}
626881f68fSopenharmony_ci
636881f68fSopenharmony_cistatic int hello_getattr(const char *path, struct stat *stbuf,
646881f68fSopenharmony_ci			 struct fuse_file_info *fi)
656881f68fSopenharmony_ci{
666881f68fSopenharmony_ci	(void) fi;
676881f68fSopenharmony_ci	int res = 0;
686881f68fSopenharmony_ci
696881f68fSopenharmony_ci	memset(stbuf, 0, sizeof(struct stat));
706881f68fSopenharmony_ci	if (strcmp(path, "/") == 0) {
716881f68fSopenharmony_ci		stbuf->st_mode = S_IFDIR | 0755;
726881f68fSopenharmony_ci		stbuf->st_nlink = 2;
736881f68fSopenharmony_ci	} else if (strcmp(path+1, options.filename) == 0) {
746881f68fSopenharmony_ci		stbuf->st_mode = S_IFREG | 0444;
756881f68fSopenharmony_ci		stbuf->st_nlink = 1;
766881f68fSopenharmony_ci		stbuf->st_size = strlen(options.contents);
776881f68fSopenharmony_ci	} else
786881f68fSopenharmony_ci		res = -ENOENT;
796881f68fSopenharmony_ci
806881f68fSopenharmony_ci	return res;
816881f68fSopenharmony_ci}
826881f68fSopenharmony_ci
836881f68fSopenharmony_cistatic int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
846881f68fSopenharmony_ci			 off_t offset, struct fuse_file_info *fi,
856881f68fSopenharmony_ci			 enum fuse_readdir_flags flags)
866881f68fSopenharmony_ci{
876881f68fSopenharmony_ci	(void) offset;
886881f68fSopenharmony_ci	(void) fi;
896881f68fSopenharmony_ci	(void) flags;
906881f68fSopenharmony_ci
916881f68fSopenharmony_ci	if (strcmp(path, "/") != 0)
926881f68fSopenharmony_ci		return -ENOENT;
936881f68fSopenharmony_ci
946881f68fSopenharmony_ci	filler(buf, ".", NULL, 0, 0);
956881f68fSopenharmony_ci	filler(buf, "..", NULL, 0, 0);
966881f68fSopenharmony_ci	filler(buf, options.filename, NULL, 0, 0);
976881f68fSopenharmony_ci
986881f68fSopenharmony_ci	return 0;
996881f68fSopenharmony_ci}
1006881f68fSopenharmony_ci
1016881f68fSopenharmony_cistatic int hello_open(const char *path, struct fuse_file_info *fi)
1026881f68fSopenharmony_ci{
1036881f68fSopenharmony_ci	if (strcmp(path+1, options.filename) != 0)
1046881f68fSopenharmony_ci		return -ENOENT;
1056881f68fSopenharmony_ci
1066881f68fSopenharmony_ci	if ((fi->flags & O_ACCMODE) != O_RDONLY)
1076881f68fSopenharmony_ci		return -EACCES;
1086881f68fSopenharmony_ci
1096881f68fSopenharmony_ci	return 0;
1106881f68fSopenharmony_ci}
1116881f68fSopenharmony_ci
1126881f68fSopenharmony_cistatic int hello_read(const char *path, char *buf, size_t size, off_t offset,
1136881f68fSopenharmony_ci		      struct fuse_file_info *fi)
1146881f68fSopenharmony_ci{
1156881f68fSopenharmony_ci	size_t len;
1166881f68fSopenharmony_ci	(void) fi;
1176881f68fSopenharmony_ci	if(strcmp(path+1, options.filename) != 0)
1186881f68fSopenharmony_ci		return -ENOENT;
1196881f68fSopenharmony_ci
1206881f68fSopenharmony_ci	len = strlen(options.contents);
1216881f68fSopenharmony_ci	if (offset < len) {
1226881f68fSopenharmony_ci		if (offset + size > len)
1236881f68fSopenharmony_ci			size = len - offset;
1246881f68fSopenharmony_ci		memcpy(buf, options.contents + offset, size);
1256881f68fSopenharmony_ci	} else
1266881f68fSopenharmony_ci		size = 0;
1276881f68fSopenharmony_ci
1286881f68fSopenharmony_ci	return size;
1296881f68fSopenharmony_ci}
1306881f68fSopenharmony_ci
1316881f68fSopenharmony_cistatic const struct fuse_operations hello_oper = {
1326881f68fSopenharmony_ci	.init           = hello_init,
1336881f68fSopenharmony_ci	.getattr	= hello_getattr,
1346881f68fSopenharmony_ci	.readdir	= hello_readdir,
1356881f68fSopenharmony_ci	.open		= hello_open,
1366881f68fSopenharmony_ci	.read		= hello_read,
1376881f68fSopenharmony_ci};
1386881f68fSopenharmony_ci
1396881f68fSopenharmony_cistatic void show_help(const char *progname)
1406881f68fSopenharmony_ci{
1416881f68fSopenharmony_ci	printf("usage: %s [options] <mountpoint>\n\n", progname);
1426881f68fSopenharmony_ci	printf("File-system specific options:\n"
1436881f68fSopenharmony_ci	       "    --name=<s>          Name of the \"hello\" file\n"
1446881f68fSopenharmony_ci	       "                        (default: \"hello\")\n"
1456881f68fSopenharmony_ci	       "    --contents=<s>      Contents \"hello\" file\n"
1466881f68fSopenharmony_ci	       "                        (default \"Hello, World!\\n\")\n"
1476881f68fSopenharmony_ci	       "\n");
1486881f68fSopenharmony_ci}
1496881f68fSopenharmony_ci
1506881f68fSopenharmony_ciint main(int argc, char *argv[])
1516881f68fSopenharmony_ci{
1526881f68fSopenharmony_ci	int ret;
1536881f68fSopenharmony_ci	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1546881f68fSopenharmony_ci
1556881f68fSopenharmony_ci	/* Set defaults -- we have to use strdup so that
1566881f68fSopenharmony_ci	   fuse_opt_parse can free the defaults if other
1576881f68fSopenharmony_ci	   values are specified */
1586881f68fSopenharmony_ci	options.filename = strdup("hello");
1596881f68fSopenharmony_ci	options.contents = strdup("Hello World!\n");
1606881f68fSopenharmony_ci
1616881f68fSopenharmony_ci	/* Parse options */
1626881f68fSopenharmony_ci	if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
1636881f68fSopenharmony_ci		return 1;
1646881f68fSopenharmony_ci
1656881f68fSopenharmony_ci	/* When --help is specified, first print our own file-system
1666881f68fSopenharmony_ci	   specific help text, then signal fuse_main to show
1676881f68fSopenharmony_ci	   additional help (by adding `--help` to the options again)
1686881f68fSopenharmony_ci	   without usage: line (by setting argv[0] to the empty
1696881f68fSopenharmony_ci	   string) */
1706881f68fSopenharmony_ci	if (options.show_help) {
1716881f68fSopenharmony_ci		show_help(argv[0]);
1726881f68fSopenharmony_ci		assert(fuse_opt_add_arg(&args, "--help") == 0);
1736881f68fSopenharmony_ci		args.argv[0][0] = '\0';
1746881f68fSopenharmony_ci	}
1756881f68fSopenharmony_ci
1766881f68fSopenharmony_ci	ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
1776881f68fSopenharmony_ci	fuse_opt_free_args(&args);
1786881f68fSopenharmony_ci	return ret;
1796881f68fSopenharmony_ci}
180