1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
/*
FUSE: Filesystem in Userspace
Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
This program can be distributed under the terms of the GNU GPLv2.
See the file GPL2.txt.
*/
#define FUSE_USE_VERSION 30
/* Not really needed - just to test build with FUSE_USE_VERSION == 30 */
#include <fuse.h>
#include <fuse_config.h>
#include <fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <assert.h>
#include <stddef.h>
#include <unistd.h>
#include <pthread.h>
#ifndef __linux__
#include <limits.h>
#else
#include <linux/limits.h>
#endif
#define FILE_INO 2
#define FILE_NAME "truncate_me"
static int got_fh;
static mode_t file_mode = S_IFREG | 0644;
static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
stbuf->st_ino = ino;
if (ino == FUSE_ROOT_ID) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 1;
}
else if (ino == FILE_INO) {
stbuf->st_mode = file_mode;
stbuf->st_nlink = 1;
stbuf->st_size = 0;
}
else
return -1;
return 0;
}
static void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
const char *name) {
struct fuse_entry_param e;
memset(&e, 0, sizeof(e));
if (parent != FUSE_ROOT_ID)
goto err_out;
else if (strcmp(name, FILE_NAME) == 0)
e.ino = FILE_INO;
else
goto err_out;
if (tfs_stat(e.ino, &e.attr) != 0)
goto err_out;
fuse_reply_entry(req, &e);
return;
err_out:
fuse_reply_err(req, ENOENT);
}
static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
struct stat stbuf;
(void) fi;
memset(&stbuf, 0, sizeof(stbuf));
if (tfs_stat(ino, &stbuf) != 0)
fuse_reply_err(req, ENOENT);
else
fuse_reply_attr(req, &stbuf, 5);
}
static void tfs_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
if (ino == FUSE_ROOT_ID)
fuse_reply_err(req, EISDIR);
else {
assert(ino == FILE_INO);
fi->fh = FILE_INO;
fuse_reply_open(req, fi);
}
}
static void tfs_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi) {
if(ino != FILE_INO ||
!(to_set & FUSE_SET_ATTR_MODE)) {
fuse_reply_err(req, EINVAL);
return;
}
if(fi == NULL)
fprintf(stderr, "setattr with fi == NULL\n");
else if (fi->fh != FILE_INO)
fprintf(stderr, "setattr with wrong fi->fh\n");
else {
fprintf(stderr, "setattr ok\n");
got_fh = 1;
file_mode = attr->st_mode;
}
tfs_getattr(req, ino, fi);
}
static struct fuse_lowlevel_ops tfs_oper = {
.lookup = tfs_lookup,
.getattr = tfs_getattr,
.open = tfs_open,
.setattr = tfs_setattr,
};
static void* run_fs(void *data) {
struct fuse_session *se = (struct fuse_session*) data;
assert(fuse_session_loop(se) == 0);
return NULL;
}
static void test_fs(char *mountpoint) {
char fname[PATH_MAX];
int fd;
assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME,
mountpoint) > 0);
fd = open(fname, O_WRONLY);
if (fd == -1) {
perror(fname);
assert(0);
}
assert(fchmod(fd, 0600) == 0);
close(fd);
}
int main(int argc, char *argv[]) {
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_session *se;
struct fuse_cmdline_opts fuse_opts;
pthread_t fs_thread;
assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
#ifndef __FreeBSD__
assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0);
#endif
se = fuse_session_new(&args, &tfs_oper,
sizeof(tfs_oper), NULL);
assert (se != NULL);
assert(fuse_set_signal_handlers(se) == 0);
assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0);
/* Start file-system thread */
assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0);
/* Do test */
test_fs(fuse_opts.mountpoint);
/* Stop file system */
assert(pthread_cancel(fs_thread) == 0);
fuse_session_unmount(se);
assert(got_fh == 1);
fuse_remove_signal_handlers(se);
fuse_session_destroy(se);
printf("Test completed successfully.\n");
return 0;
}
/**
* Local Variables:
* mode: c
* indent-tabs-mode: nil
* c-basic-offset: 4
* End:
*/
|