"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/doc/html/fuse-3_810_82_2example_2notify__inval__inode_8c_source.html" (9 Jun 2021, 64711 Bytes) of package /linux/misc/fuse-3.10.4.tar.xz:


Caution: In this restricted "Fossies" environment the current HTML page may not be correctly presentated and may have some non-functional links. You can here alternatively try to browse the pure source code or just view or download the uninterpreted raw source code. If the rendering is insufficient you may try to find and view the page on the project site itself.

libfuse
notify_inval_inode.c
Go to the documentation of this file.
1 /*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
4 
5  This program can be distributed under the terms of the GNU GPLv2.
6  See the file COPYING.
7 */
8 
62 #define FUSE_USE_VERSION 34
63 
64 #include <fuse_lowlevel.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include <assert.h>
71 #include <stddef.h>
72 #include <unistd.h>
73 #include <pthread.h>
74 
75 /* We can't actually tell the kernel that there is no
76  timeout, so we just send a big value */
77 #define NO_TIMEOUT 500000
78 
79 #define MAX_STR_LEN 128
80 #define FILE_INO 2
81 #define FILE_NAME "current_time"
82 static char file_contents[MAX_STR_LEN];
83 static int lookup_cnt = 0;
84 static size_t file_size;
85 
86 /* Command line parsing */
87 struct options {
88  int no_notify;
89  int update_interval;
90 };
91 static struct options options = {
92  .no_notify = 0,
93  .update_interval = 1,
94 };
95 
96 #define OPTION(t, p) \
97  { t, offsetof(struct options, p), 1 }
98 static const struct fuse_opt option_spec[] = {
99  OPTION("--no-notify", no_notify),
100  OPTION("--update-interval=%d", update_interval),
102 };
103 
104 static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
105  stbuf->st_ino = ino;
106  if (ino == FUSE_ROOT_ID) {
107  stbuf->st_mode = S_IFDIR | 0755;
108  stbuf->st_nlink = 1;
109  }
110 
111  else if (ino == FILE_INO) {
112  stbuf->st_mode = S_IFREG | 0444;
113  stbuf->st_nlink = 1;
114  stbuf->st_size = file_size;
115  }
116 
117  else
118  return -1;
119 
120  return 0;
121 }
122 
123 static void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
124  const char *name) {
125  struct fuse_entry_param e;
126  memset(&e, 0, sizeof(e));
127 
128  if (parent != FUSE_ROOT_ID)
129  goto err_out;
130  else if (strcmp(name, FILE_NAME) == 0) {
131  e.ino = FILE_INO;
132  lookup_cnt++;
133  } else
134  goto err_out;
135 
136  e.attr_timeout = NO_TIMEOUT;
137  e.entry_timeout = NO_TIMEOUT;
138  if (tfs_stat(e.ino, &e.attr) != 0)
139  goto err_out;
140  fuse_reply_entry(req, &e);
141  return;
142 
143 err_out:
144  fuse_reply_err(req, ENOENT);
145 }
146 
147 static void tfs_forget (fuse_req_t req, fuse_ino_t ino,
148  uint64_t nlookup) {
149  (void) req;
150  if(ino == FILE_INO)
151  lookup_cnt -= nlookup;
152  else
153  assert(ino == FUSE_ROOT_ID);
154  fuse_reply_none(req);
155 }
156 
157 static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
158  struct fuse_file_info *fi) {
159  struct stat stbuf;
160 
161  (void) fi;
162 
163  memset(&stbuf, 0, sizeof(stbuf));
164  if (tfs_stat(ino, &stbuf) != 0)
165  fuse_reply_err(req, ENOENT);
166  else
167  fuse_reply_attr(req, &stbuf, NO_TIMEOUT);
168 }
169 
170 struct dirbuf {
171  char *p;
172  size_t size;
173 };
174 
175 static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
176  fuse_ino_t ino) {
177  struct stat stbuf;
178  size_t oldsize = b->size;
179  b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
180  b->p = (char *) realloc(b->p, b->size);
181  memset(&stbuf, 0, sizeof(stbuf));
182  stbuf.st_ino = ino;
183  fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
184  b->size);
185 }
186 
187 #define min(x, y) ((x) < (y) ? (x) : (y))
188 
189 static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
190  off_t off, size_t maxsize) {
191  if (off < bufsize)
192  return fuse_reply_buf(req, buf + off,
193  min(bufsize - off, maxsize));
194  else
195  return fuse_reply_buf(req, NULL, 0);
196 }
197 
198 static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
199  off_t off, struct fuse_file_info *fi) {
200  (void) fi;
201 
202  if (ino != FUSE_ROOT_ID)
203  fuse_reply_err(req, ENOTDIR);
204  else {
205  struct dirbuf b;
206 
207  memset(&b, 0, sizeof(b));
208  dirbuf_add(req, &b, FILE_NAME, FILE_INO);
209  reply_buf_limited(req, b.p, b.size, off, size);
210  free(b.p);
211  }
212 }
213 
214 static void tfs_open(fuse_req_t req, fuse_ino_t ino,
215  struct fuse_file_info *fi) {
216 
217  /* Make cache persistent even if file is closed,
218  this makes it easier to see the effects */
219  fi->keep_cache = 1;
220 
221  if (ino == FUSE_ROOT_ID)
222  fuse_reply_err(req, EISDIR);
223  else if ((fi->flags & O_ACCMODE) != O_RDONLY)
224  fuse_reply_err(req, EACCES);
225  else if (ino == FILE_INO)
226  fuse_reply_open(req, fi);
227  else {
228  // This should not happen
229  fprintf(stderr, "Got open for non-existing inode!\n");
230  fuse_reply_err(req, ENOENT);
231  }
232 }
233 
234 static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
235  off_t off, struct fuse_file_info *fi) {
236  (void) fi;
237 
238  assert(ino == FILE_INO);
239  reply_buf_limited(req, file_contents, file_size, off, size);
240 }
241 
242 static const struct fuse_lowlevel_ops tfs_oper = {
243  .lookup = tfs_lookup,
244  .getattr = tfs_getattr,
245  .readdir = tfs_readdir,
246  .open = tfs_open,
247  .read = tfs_read,
248  .forget = tfs_forget,
249 };
250 
251 static void update_fs(void) {
252  struct tm *now;
253  time_t t;
254  t = time(NULL);
255  now = localtime(&t);
256  assert(now != NULL);
257 
258  file_size = strftime(file_contents, MAX_STR_LEN,
259  "The current time is %H:%M:%S\n", now);
260  assert(file_size != 0);
261 }
262 
263 static void* update_fs_loop(void *data) {
264  struct fuse_session *se = (struct fuse_session*) data;
265 
266  while(1) {
267  update_fs();
268  if (!options.no_notify && lookup_cnt) {
269  /* Only send notification if the kernel
270  is aware of the inode */
272  (se, FILE_INO, 0, 0) == 0);
273  }
274  sleep(options.update_interval);
275  }
276  return NULL;
277 }
278 
279 static void show_help(const char *progname)
280 {
281  printf("usage: %s [options] <mountpoint>\n\n", progname);
282  printf("File-system specific options:\n"
283  " --update-interval=<secs> Update-rate of file system contents\n"
284  " --no-notify Disable kernel notifications\n"
285  "\n");
286 }
287 
288 int main(int argc, char *argv[]) {
289  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
290  struct fuse_session *se;
291  struct fuse_cmdline_opts opts;
292  struct fuse_loop_config config;
293  pthread_t updater;
294  int ret = -1;
295 
296  if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
297  return 1;
298 
299  if (fuse_parse_cmdline(&args, &opts) != 0) {
300  ret = 1;
301  goto err_out1;
302  }
303 
304  if (opts.show_help) {
305  show_help(argv[0]);
308  ret = 0;
309  goto err_out1;
310  } else if (opts.show_version) {
311  printf("FUSE library version %s\n", fuse_pkgversion());
313  ret = 0;
314  goto err_out1;
315  }
316 
317  /* Initial contents */
318  update_fs();
319 
320  se = fuse_session_new(&args, &tfs_oper,
321  sizeof(tfs_oper), NULL);
322  if (se == NULL)
323  goto err_out1;
324 
325  if (fuse_set_signal_handlers(se) != 0)
326  goto err_out2;
327 
328  if (fuse_session_mount(se, opts.mountpoint) != 0)
329  goto err_out3;
330 
331  fuse_daemonize(opts.foreground);
332 
333  /* Start thread to update file contents */
334  ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
335  if (ret != 0) {
336  fprintf(stderr, "pthread_create failed with %s\n",
337  strerror(ret));
338  goto err_out3;
339  }
340 
341  /* Block until ctrl+c or fusermount -u */
342  if (opts.singlethread)
343  ret = fuse_session_loop(se);
344  else {
345  config.clone_fd = opts.clone_fd;
346  config.max_idle_threads = opts.max_idle_threads;
347  ret = fuse_session_loop_mt(se, &config);
348  }
349 
351 err_out3:
353 err_out2:
355 err_out1:
356  fuse_opt_free_args(&args);
357  free(opts.mountpoint);
358 
359  return ret ? 1 : 0;
360 }
361 
362 
void(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
void fuse_lowlevel_help(void)
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
void fuse_lowlevel_version(void)
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
void fuse_session_destroy(struct fuse_session *se)
int fuse_session_loop(struct fuse_session *se)
Definition: fuse_loop.c:19
int fuse_daemonize(int foreground)
Definition: helper.c:225
unsigned int keep_cache
Definition: fuse_common.h:64
Definition: fuse_lowlevel.h:59
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
int fuse_set_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:62
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
void fuse_cmdline_help(void)
Definition: helper.c:129
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:34
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
#define FUSE_OPT_END
Definition: fuse_opt.h:104
int fuse_reply_err(fuse_req_t req, int err)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
Definition: helper.c:202
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
void fuse_reply_none(fuse_req_t req)
#define FUSE_ROOT_ID
Definition: fuse_lowlevel.h:43
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
const char * fuse_pkgversion(void)
Definition: fuse.c:5117
void fuse_session_unmount(struct fuse_session *se)
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123
void fuse_remove_signal_handlers(struct fuse_session *se)
Definition: fuse_signals.c:79
int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config)