blob: 16eb7ada39c85671716f1e5407d2027c14c48a6d [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017
Miklos Szeredi0f62d722005-01-04 12:45:54 +000018#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000020#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000021#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000023#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000024#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000025#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000027#include <signal.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000028#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000029#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000030#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000031#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000032
Miklos Szeredi97c61e92001-11-07 12:09:43 +000033#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000035
Miklos Szeredie248e4b2005-12-14 16:18:32 +000036#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000037#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000038
Miklos Szeredi659743b2005-12-09 17:41:42 +000039struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000040 unsigned int uid;
41 unsigned int gid;
42 unsigned int umask;
43 double entry_timeout;
44 double negative_timeout;
45 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000046 double ac_attr_timeout;
47 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000048 int debug;
49 int hard_remove;
50 int use_ino;
51 int readdir_ino;
52 int set_mode;
53 int set_uid;
54 int set_gid;
55 int direct_io;
56 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000057 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000058 int intr;
59 int intr_signal;
Miklos Szeredi659743b2005-12-09 17:41:42 +000060};
61
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000062struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000063 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000064 struct fuse_operations op;
65 int compat;
66 struct node **name_table;
67 size_t name_table_size;
68 struct node **id_table;
69 size_t id_table_size;
70 fuse_ino_t ctr;
71 unsigned int generation;
72 unsigned int hidectr;
73 pthread_mutex_t lock;
74 pthread_rwlock_t tree_lock;
75 void *user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +000076 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000077 int intr_installed;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000078};
79
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000080struct lock {
81 int type;
82 off_t start;
83 off_t end;
84 pid_t pid;
85 uint64_t owner;
86 struct lock *next;
87};
88
Miklos Szeredi0f62d722005-01-04 12:45:54 +000089struct node {
90 struct node *name_next;
91 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000092 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000093 unsigned int generation;
94 int refctr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000095 fuse_ino_t parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000096 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +000097 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000098 int open_count;
99 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000100 struct timespec stat_updated;
101 struct timespec mtime;
102 off_t size;
103 int cache_valid;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +0000104 struct lock *locks;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105};
106
107struct fuse_dirhandle {
Miklos Szerediab974562005-04-07 15:40:21 +0000108 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000109 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000110 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000111 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000112 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000113 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000114 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000115 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000116 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000117 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000118 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000119 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120};
121
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000122struct fuse_context_i {
123 struct fuse_context ctx;
124 fuse_req_t req;
125};
Miklos Szeredid169f312004-09-22 08:48:26 +0000126
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000127static pthread_key_t fuse_context_key;
128static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
129static int fuse_context_ref;
130
131static int fuse_compat_open(struct fuse *, fuse_req_t, char *,
132 struct fuse_file_info *);
133static void fuse_compat_release(struct fuse *, fuse_req_t, char *,
134 struct fuse_file_info *);
135static int fuse_compat_opendir(struct fuse *, fuse_req_t, char *,
136 struct fuse_file_info *);
137static int fuse_compat_statfs(struct fuse *, fuse_req_t, struct statvfs *);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000138
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000139static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000140{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000141 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000142 struct node *node;
143
Miklos Szeredia13d9002004-11-02 17:32:03 +0000144 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
145 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000149}
150
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000151static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000152{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000153 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000154 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000155 fprintf(stderr, "fuse internal error: node %llu not found\n",
156 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000157 abort();
158 }
159 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000160}
161
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000162static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000163{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000164 free(node->name);
165 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000166}
167
Miklos Szeredia13d9002004-11-02 17:32:03 +0000168static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000169{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000170 size_t hash = node->nodeid % f->id_table_size;
171 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172
Miklos Szeredie5183742005-02-02 11:14:04 +0000173 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000174 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000175 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176 return;
177 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000178}
179
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000180static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000182 size_t hash = node->nodeid % f->id_table_size;
183 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000184 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185}
186
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000187static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000188{
189 unsigned int hash = *name;
190
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000191 if (hash)
192 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 hash = (hash << 5) - hash + *name;
194
195 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196}
197
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000198static void unref_node(struct fuse *f, struct node *node);
199
200static void unhash_name(struct fuse *f, struct node *node)
201{
202 if (node->name) {
203 size_t hash = name_hash(f, node->parent, node->name);
204 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000205
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000206 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
207 if (*nodep == node) {
208 *nodep = node->name_next;
209 node->name_next = NULL;
210 unref_node(f, get_node(f, node->parent));
211 free(node->name);
212 node->name = NULL;
213 node->parent = 0;
214 return;
215 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000216 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
217 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000218 abort();
219 }
220}
221
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000222static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000223 const char *name)
224{
225 size_t hash = name_hash(f, parent, name);
226 node->name = strdup(name);
227 if (node->name == NULL)
228 return -1;
229
230 get_node(f, parent)->refctr ++;
231 node->parent = parent;
232 node->name_next = f->name_table[hash];
233 f->name_table[hash] = node;
234 return 0;
235}
236
237static void delete_node(struct fuse *f, struct node *node)
238{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000239 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000240 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000241 fflush(stdout);
242 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000243 assert(!node->name);
244 unhash_id(f, node);
245 free_node(node);
246}
247
248static void unref_node(struct fuse *f, struct node *node)
249{
250 assert(node->refctr > 0);
251 node->refctr --;
252 if (!node->refctr)
253 delete_node(f, node);
254}
255
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000256static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000257{
258 do {
259 f->ctr++;
260 if (!f->ctr)
261 f->generation ++;
262 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
263 return f->ctr;
264}
265
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000266static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000267 const char *name)
268{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000269 size_t hash = name_hash(f, parent, name);
270 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
273 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000275
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000277}
278
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000279static struct node *find_node(struct fuse *f, fuse_ino_t parent,
280 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000281{
282 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000283
Miklos Szeredia181e612001-11-06 12:03:23 +0000284 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000285 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000286 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000287 node = (struct node *) calloc(1, sizeof(struct node));
288 if (node == NULL)
289 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000290
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000291 node->refctr = 1;
292 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000293 node->open_count = 0;
294 node->is_hidden = 0;
295 node->generation = f->generation;
296 if (hash_name(f, node, parent, name) == -1) {
297 free(node);
298 node = NULL;
299 goto out_err;
300 }
301 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000302 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000303 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000304 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000305 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000306 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000307}
308
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000309static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 size_t len = strlen(name);
312 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
315 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 strncpy(s, name, len);
318 s--;
319 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000321 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000322}
323
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000324static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000325{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000326 char buf[FUSE_MAX_PATH];
327 char *s = buf + FUSE_MAX_PATH - 1;
328 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000329
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000330 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000331
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000333 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000335 return NULL;
336 }
337
338 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000339 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
340 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000341 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342 s = NULL;
343 break;
344 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000345
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000346 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000347 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000348 break;
349 }
350 pthread_mutex_unlock(&f->lock);
351
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000352 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000354 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000355 return strdup("/");
356 else
357 return strdup(s);
358}
Miklos Szeredia181e612001-11-06 12:03:23 +0000359
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000360static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000361{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000362 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000363}
364
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000365static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000366{
367 struct node *node;
368 if (nodeid == FUSE_ROOT_ID)
369 return;
370 pthread_mutex_lock(&f->lock);
371 node = get_node(f, nodeid);
372 assert(node->nlookup >= nlookup);
373 node->nlookup -= nlookup;
374 if (!node->nlookup) {
375 unhash_name(f, node);
376 unref_node(f, node);
377 }
378 pthread_mutex_unlock(&f->lock);
379}
380
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000381static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000382{
Miklos Szeredia181e612001-11-06 12:03:23 +0000383 struct node *node;
384
385 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000386 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000387 if (node != NULL)
388 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000389 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000390}
391
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000392static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
393 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394{
Miklos Szeredia181e612001-11-06 12:03:23 +0000395 struct node *node;
396 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000397 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000398
Miklos Szeredia181e612001-11-06 12:03:23 +0000399 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000400 node = lookup_node(f, olddir, oldname);
401 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000402 if (node == NULL)
403 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000404
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000405 if (newnode != NULL) {
406 if (hide) {
407 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000408 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000409 goto out;
410 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000411 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000412 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000413
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000414 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000415 if (hash_name(f, node, newdir, newname) == -1) {
416 err = -ENOMEM;
417 goto out;
418 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000419
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000420 if (hide)
421 node->is_hidden = 1;
422
423 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000424 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000425 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000426}
427
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000428static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000430 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000431 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000432 if (f->conf.set_mode)
433 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
434 if (f->conf.set_uid)
435 stbuf->st_uid = f->conf.uid;
436 if (f->conf.set_gid)
437 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438}
439
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000440static struct fuse *req_fuse(fuse_req_t req)
441{
442 return (struct fuse *) fuse_req_userdata(req);
443}
444
445static void fuse_intr_sighandler(int sig)
446{
447 (void) sig;
448 /* Nothing to do */
449}
450
451struct fuse_intr_data {
452 pthread_t id;
453 pthread_cond_t cond;
454 int finished;
455};
456
457static void fuse_interrupt(fuse_req_t req, void *d_)
458{
459 struct fuse_intr_data *d = d_;
460 struct fuse *f = req_fuse(req);
461
462 if (d->id == pthread_self())
463 return;
464
465 pthread_mutex_lock(&f->lock);
466 while (!d->finished) {
467 struct timeval now;
468 struct timespec timeout;
469
470 pthread_kill(d->id, f->conf.intr_signal);
471 gettimeofday(&now, NULL);
472 timeout.tv_sec = now.tv_sec + 1;
473 timeout.tv_nsec = now.tv_usec * 1000;
474 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
475 }
476 pthread_mutex_unlock(&f->lock);
477}
478
479static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
480 struct fuse_intr_data *d)
481{
482 pthread_mutex_lock(&f->lock);
483 d->finished = 1;
484 pthread_cond_broadcast(&d->cond);
485 pthread_mutex_unlock(&f->lock);
486 fuse_req_interrupt_func(req, NULL, NULL);
487 pthread_cond_destroy(&d->cond);
488}
489
490static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
491{
492 d->id = pthread_self();
493 pthread_cond_init(&d->cond, NULL);
494 d->finished = 0;
495 fuse_req_interrupt_func(req, fuse_interrupt, d);
496}
497
498static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
499 struct fuse_intr_data *d)
500{
501 if (f->conf.intr)
502 fuse_do_finish_interrupt(f, req, d);
503}
504
505static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
506 struct fuse_intr_data *d)
507{
508 if (f->conf.intr)
509 fuse_do_prepare_interrupt(req, d);
510}
511
512static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path,
513 struct stat *buf)
514{
515 int res;
516 struct fuse_intr_data d;
517 fuse_prepare_interrupt(f, req, &d);
518 res = f->op.getattr(path, buf);
519 fuse_finish_interrupt(f, req, &d);
520 return res;
521}
522
523static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path,
524 struct stat *buf, struct fuse_file_info *fi)
525{
526 int res;
527 struct fuse_intr_data d;
528 fuse_prepare_interrupt(f, req, &d);
529 res = f->op.fgetattr(path, buf, fi);
530 fuse_finish_interrupt(f, req, &d);
531 return res;
532}
533
534static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath,
535 const char *newpath)
536{
537 int res;
538 struct fuse_intr_data d;
539 fuse_prepare_interrupt(f, req, &d);
540 res = f->op.rename(oldpath, newpath);
541 fuse_finish_interrupt(f, req, &d);
542 return res;
543}
544
545static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path)
546{
547 int res;
548 struct fuse_intr_data d;
549 fuse_prepare_interrupt(f, req, &d);
550 res = f->op.unlink(path);
551 fuse_finish_interrupt(f, req, &d);
552 return res;
553}
554
555static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path,
556 struct fuse_file_info *fi)
557{
558 struct fuse_intr_data d;
559 fuse_prepare_interrupt(f, req, &d);
560 f->op.release(path, fi);
561 fuse_finish_interrupt(f, req, &d);
562}
563
564static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path,
565 struct fuse_file_info *fi)
566{
567 int res;
568 struct fuse_intr_data d;
569 fuse_prepare_interrupt(f, req, &d);
570 res = f->op.opendir(path, fi);
571 fuse_finish_interrupt(f, req, &d);
572 return res;
573}
574
575static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path,
576 struct fuse_file_info *fi)
577{
578 int res;
579 struct fuse_intr_data d;
580 fuse_prepare_interrupt(f, req, &d);
581 res = f->op.open(path, fi);
582 fuse_finish_interrupt(f, req, &d);
583 return res;
584}
585
586static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
587 struct statvfs *buf)
588{
589 int res;
590 struct fuse_intr_data d;
591 fuse_prepare_interrupt(f, req, &d);
592 res = f->op.statfs(path, buf);
593 fuse_finish_interrupt(f, req, &d);
594 return res;
595}
596
597static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
598 const char *path, struct fuse_file_info *fi)
599{
600 struct fuse_intr_data d;
601 fuse_prepare_interrupt(f, req, &d);
602 f->op.releasedir(path, fi);
603 fuse_finish_interrupt(f, req, &d);
604}
605
606static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
607 mode_t mode, struct fuse_file_info *fi)
608{
609 int res;
610 struct fuse_intr_data d;
611 fuse_prepare_interrupt(f, req, &d);
612 res = f->op.create(path, mode, fi);
613 fuse_finish_interrupt(f, req, &d);
614 return res;
615}
616
617static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
618 struct fuse_file_info *fi, int cmd, struct flock *lock,
619 uint64_t owner)
620{
621 int res;
622 struct fuse_intr_data d;
623 fuse_prepare_interrupt(f, req, &d);
624 res = f->op.lock(path, fi, cmd, lock, owner);
625 fuse_finish_interrupt(f, req, &d);
626 return res;
627}
628
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000629static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000630{
631 struct node *node;
632 int isopen = 0;
633 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000634 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000635 if (node && node->open_count > 0)
636 isopen = 1;
637 pthread_mutex_unlock(&f->lock);
638 return isopen;
639}
640
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000641static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
642 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000643{
644 struct stat buf;
645 struct node *node;
646 struct node *newnode;
647 char *newpath;
648 int res;
649 int failctr = 10;
650
651 if (!f->op.getattr)
652 return NULL;
653
654 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000655 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000656 node = lookup_node(f, dir, oldname);
657 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000658 pthread_mutex_unlock(&f->lock);
659 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000660 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000661 do {
662 f->hidectr ++;
663 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000664 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000665 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000666 } while(newnode);
667 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000668
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000669 newpath = get_path_name(f, dir, newname);
670 if (!newpath)
671 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000672
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000673 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000674 if (res != 0)
675 break;
676 free(newpath);
677 newpath = NULL;
678 } while(--failctr);
679
680 return newpath;
681}
682
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000683static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
684 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000685{
686 char newname[64];
687 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000688 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000689
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000690 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000691 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000692 if (newpath) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000693 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000694 if (res == 0)
695 err = rename_node(f, dir, oldname, dir, newname, 1);
696 free(newpath);
697 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000698 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000699 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000700}
701
Miklos Szeredi320abe42006-01-30 18:14:51 +0000702static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
703{
704 return stbuf->st_mtime == ts->tv_sec
705#ifdef HAVE_STRUCT_STAT_ST_ATIM
706 && stbuf->st_mtim.tv_nsec == ts->tv_nsec
707#endif
708 ;
709}
710
711static void mtime_set(const struct stat *stbuf, struct timespec *ts)
712{
713#ifdef HAVE_STRUCT_STAT_ST_ATIM
714 *ts = stbuf->st_mtim;
715#else
716 ts->tv_sec = stbuf->st_mtime;
717#endif
718}
719
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000720#ifndef CLOCK_MONOTONIC
721#define CLOCK_MONOTONIC CLOCK_REALTIME
722#endif
723
Miklos Szeredi320abe42006-01-30 18:14:51 +0000724static void curr_time(struct timespec *now)
725{
726 static clockid_t clockid = CLOCK_MONOTONIC;
727 int res = clock_gettime(clockid, now);
728 if (res == -1 && errno == EINVAL) {
729 clockid = CLOCK_REALTIME;
730 res = clock_gettime(clockid, now);
731 }
732 if (res == -1) {
733 perror("fuse: clock_gettime");
734 abort();
735 }
736}
737
738static void update_stat(struct node *node, const struct stat *stbuf)
739{
740 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
741 stbuf->st_size != node->size))
742 node->cache_valid = 0;
743 mtime_set(stbuf, &node->mtime);
744 node->size = stbuf->st_size;
745 curr_time(&node->stat_updated);
746}
747
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000748static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
749 const char *name, const char *path,
750 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000751{
752 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000753
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000754 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000755 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000756 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000757 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000758 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000760 struct node *node;
761
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000762 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000763 if (node == NULL)
764 res = -ENOMEM;
765 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000766 e->ino = node->nodeid;
767 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000768 e->entry_timeout = f->conf.entry_timeout;
769 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000770 if (f->conf.auto_cache) {
771 pthread_mutex_lock(&f->lock);
772 update_stat(node, &e->attr);
773 pthread_mutex_unlock(&f->lock);
774 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000775 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000776 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000777 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000778 fflush(stdout);
779 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000780 }
781 }
782 return res;
783}
784
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000785static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000787 struct fuse_context_i *c;
788
789 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
790 if (c == NULL) {
791 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
792 if (c == NULL) {
793 /* This is hard to deal with properly, so just abort. If
794 memory is so low that the context cannot be allocated,
795 there's not much hope for the filesystem anyway */
796 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
797 abort();
798 }
799 pthread_setspecific(fuse_context_key, c);
800 }
801 return c;
802}
803
804static void fuse_freecontext(void *data)
805{
806 free(data);
807}
808
809static int fuse_create_context_key(void)
810{
811 int err = 0;
812 pthread_mutex_lock(&fuse_context_lock);
813 if (!fuse_context_ref) {
814 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
815 if (err) {
816 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
817 strerror(err));
818 pthread_mutex_unlock(&fuse_context_lock);
819 return -1;
820 }
821 }
822 fuse_context_ref++;
823 pthread_mutex_unlock(&fuse_context_lock);
824 return 0;
825}
826
827static void fuse_delete_context_key(void)
828{
829 pthread_mutex_lock(&fuse_context_lock);
830 fuse_context_ref--;
831 if (!fuse_context_ref) {
832 free(pthread_getspecific(fuse_context_key));
833 pthread_key_delete(fuse_context_key);
834 }
835 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000836}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000837
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000838static struct fuse *req_fuse_prepare(fuse_req_t req)
839{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000840 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000841 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000842 c->req = req;
843 c->ctx.fuse = req_fuse(req);
844 c->ctx.uid = ctx->uid;
845 c->ctx.gid = ctx->gid;
846 c->ctx.pid = ctx->pid;
847 c->ctx.private_data = c->ctx.fuse->user_data;
848 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000849}
850
851static inline void reply_err(fuse_req_t req, int err)
852{
853 /* fuse_reply_err() uses non-negated errno values */
854 fuse_reply_err(req, -err);
855}
856
857static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
858 int err)
859{
860 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000861 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000862 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000863 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000864 } else
865 reply_err(req, err);
866}
867
Miklos Szeredi065f2222006-01-20 15:15:21 +0000868static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000869{
870 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000871 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000872
873 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000874 c->ctx.fuse = f;
875 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000876
877 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000878 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000879}
880
881static void fuse_data_destroy(void *data)
882{
883 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000884 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000885
886 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000887 c->ctx.fuse = f;
888 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000889
890 if (f->op.destroy)
891 f->op.destroy(f->user_data);
892}
893
894static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
895{
896 struct fuse *f = req_fuse_prepare(req);
897 struct fuse_entry_param e;
898 char *path;
899 int err;
900
901 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000902 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000903 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000905 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000906 printf("LOOKUP %s\n", path);
907 fflush(stdout);
908 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000909 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000910 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000911 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000912 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000913 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000914 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000915 err = 0;
916 }
917 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000918 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000919 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000920 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000921 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000922}
923
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000924static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000925{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000926 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000927 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000928 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000929 fflush(stdout);
930 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000931 forget_node(f, ino, nlookup);
932 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933}
934
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000935static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
936 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000937{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000938 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000939 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000940 char *path;
941 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000942
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000943 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000944 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000945
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000946 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000947 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000948 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000950 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000952 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000953 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000954 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000955 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000956 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000957 if (f->conf.auto_cache) {
958 pthread_mutex_lock(&f->lock);
959 update_stat(get_node(f, ino), &buf);
960 pthread_mutex_unlock(&f->lock);
961 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000962 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000963 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000964 } else
965 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000966}
967
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000968static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
969 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000970{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000971 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000972
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000973 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000974 if (f->op.chmod) {
975 struct fuse_intr_data d;
976 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000977 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000978 fuse_finish_interrupt(f, req, &d);
979 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000980
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000981 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000982}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000983
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
985 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000986{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000987 int err;
988 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
989 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000990
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000991 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000992 if (f->op.chown) {
993 struct fuse_intr_data d;
994 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000995 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000996 fuse_finish_interrupt(f, req, &d);
997 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000998
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000999 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001000}
1001
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001002static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1003 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001004{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001005 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001006 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001007
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001008 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001009 if (fi && f->op.ftruncate) {
1010 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001011 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001012 fuse_finish_interrupt(f, req, &d);
1013 } else if (f->op.truncate) {
1014 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001015 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001016 fuse_finish_interrupt(f, req, &d);
1017 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001018 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001019}
1020
Miklos Szeredic3b76812006-09-16 08:52:09 +00001021static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1022 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001023{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001024 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001025 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001026
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001027 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001028 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001029 struct timespec tv[2];
1030 tv[0] = attr->st_atim;
1031 tv[1] = attr->st_mtim;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001032 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001033 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001034 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001035 } else if (f->op.utime) {
1036 struct utimbuf buf;
1037 buf.actime = attr->st_atime;
1038 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001039 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001040 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001041 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001042 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001043
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001044 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001045}
1046
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001047static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001048 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001049{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001050 struct fuse *f = req_fuse_prepare(req);
1051 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001052 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001053 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001054
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001055 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001056 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001057 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001058 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001059 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001061 err = 0;
1062 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001063 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001064 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001065 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001066 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001067 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001068 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
Miklos Szeredic3b76812006-09-16 08:52:09 +00001069 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001070 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001071 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001072 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001073 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001074 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001075 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001076 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001077 if (f->conf.auto_cache) {
1078 pthread_mutex_lock(&f->lock);
1079 update_stat(get_node(f, ino), &buf);
1080 pthread_mutex_unlock(&f->lock);
1081 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001082 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001083 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001084 } else
1085 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001086}
1087
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001088static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1089{
1090 struct fuse *f = req_fuse_prepare(req);
1091 char *path;
1092 int err;
1093
1094 err = -ENOENT;
1095 pthread_rwlock_rdlock(&f->tree_lock);
1096 path = get_path(f, ino);
1097 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001098 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001099 printf("ACCESS %s 0%o\n", path, mask);
1100 fflush(stdout);
1101 }
1102 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001103 if (f->op.access) {
1104 struct fuse_intr_data d;
1105 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001106 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001107 fuse_finish_interrupt(f, req, &d);
1108 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001109 free(path);
1110 }
1111 pthread_rwlock_unlock(&f->tree_lock);
1112 reply_err(req, err);
1113}
1114
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001115static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001116{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001117 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001118 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001119 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001120 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001121
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001122 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001123 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001124 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001125 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001126 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001127 if (f->op.readlink) {
1128 struct fuse_intr_data d;
1129 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001130 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001131 fuse_finish_interrupt(f, req, &d);
1132 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001133 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001134 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001135 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001136 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001137 linkname[PATH_MAX] = '\0';
1138 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001139 } else
1140 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001141}
1142
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001143static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1144 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001145{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001146 struct fuse *f = req_fuse_prepare(req);
1147 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001148 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001149 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001150
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001151 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001152 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001153 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001154 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001155 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001156 printf("MKNOD %s\n", path);
1157 fflush(stdout);
1158 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001159 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001160 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1161 struct fuse_file_info fi;
1162
1163 memset(&fi, 0, sizeof(fi));
1164 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001165 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001166 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001167 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001168 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001169 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001170 }
1171 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001172 struct fuse_intr_data d;
1173 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001174 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001175 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001176 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001177 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001178 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001179 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001180 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001181 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001182 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001183}
1184
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001185static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1186 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001187{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001188 struct fuse *f = req_fuse_prepare(req);
1189 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001190 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001191 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001192
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001193 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001194 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001195 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001196 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001197 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001198 printf("MKDIR %s\n", path);
1199 fflush(stdout);
1200 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001201 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001202 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001203 struct fuse_intr_data d;
1204 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001205 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001206 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001207 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001208 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001209 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001210 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001211 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001212 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001213 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001214}
1215
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001216static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001217{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001218 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001219 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001220 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001221
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001222 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001223 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001224 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001225 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001226 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001227 printf("UNLINK %s\n", path);
1228 fflush(stdout);
1229 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001230 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001231 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001232 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001233 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001234 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001235 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001236 if (!err)
1237 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001238 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001239 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001240 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001241 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001242 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001243 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001244}
1245
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001246static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001247{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001248 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001249 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001250 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001251
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001252 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001253 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001254 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001255 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001256 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001257 printf("RMDIR %s\n", path);
1258 fflush(stdout);
1259 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001260 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001261 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001262 struct fuse_intr_data d;
1263 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001264 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001265 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001266 if (!err)
1267 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001268 }
1269 free(path);
1270 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001271 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001272 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001273}
1274
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001275static void fuse_symlink(fuse_req_t req, const char *linkname,
1276 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001277{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001278 struct fuse *f = req_fuse_prepare(req);
1279 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001280 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001281 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001282
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001283 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001284 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001285 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001286 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001287 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001288 printf("SYMLINK %s\n", path);
1289 fflush(stdout);
1290 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001291 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001292 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001293 struct fuse_intr_data d;
1294 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001295 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001296 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001297 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001298 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001299 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001300 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001301 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001302 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001303 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001304}
1305
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001306static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1307 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001308{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001309 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001310 char *oldpath;
1311 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001312 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001313
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001314 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001315 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001316 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001317 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001318 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001319 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001320 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001321 printf("RENAME %s -> %s\n", oldpath, newpath);
1322 fflush(stdout);
1323 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001324 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001325 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001326 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001327 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001328 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001329 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001331 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001332 if (!err)
1333 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001334 }
1335 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001336 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001337 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001338 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001339 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001340 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001341 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001342}
1343
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001344static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1345 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001346{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001347 struct fuse *f = req_fuse_prepare(req);
1348 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001349 char *oldpath;
1350 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001351 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001352
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001353 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001354 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001355 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001356 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001357 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001358 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001359 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001360 printf("LINK %s\n", newpath);
1361 fflush(stdout);
1362 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001363 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001364 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001365 struct fuse_intr_data d;
1366 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001367 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001368 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001369 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001370 err = lookup_path(f, req, newparent, newname, newpath, &e,
1371 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001372 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001373 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001374 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001375 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001376 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001377 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001378 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001379}
1380
Miklos Szeredid9079a72005-10-26 15:29:06 +00001381static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1382 mode_t mode, struct fuse_file_info *fi)
1383{
1384 struct fuse *f = req_fuse_prepare(req);
1385 struct fuse_entry_param e;
1386 char *path;
1387 int err;
1388
1389 err = -ENOENT;
1390 pthread_rwlock_rdlock(&f->tree_lock);
1391 path = get_path_name(f, parent, name);
1392 if (path != NULL) {
1393 err = -ENOSYS;
1394 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001395 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001396 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001397 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001398 printf("CREATE[%llu] flags: 0x%x %s\n",
1399 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001400 fflush(stdout);
1401 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001402 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001403 if (err) {
1404 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001405 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001406 } else if (!S_ISREG(e.attr.st_mode)) {
1407 err = -EIO;
1408 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001409 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001410 forget_node(f, e.ino, 1);
1411 }
1412 }
1413 }
1414 }
1415
1416 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001417 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001418 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001419 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001420 fi->keep_cache = 1;
1421
1422 pthread_mutex_lock(&f->lock);
1423 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1424 /* The open syscall was interrupted, so it must be cancelled */
1425 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001426 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001427 forget_node(f, e.ino, 1);
1428 } else {
1429 struct node *node = get_node(f, e.ino);
1430 node->open_count ++;
1431 }
1432 pthread_mutex_unlock(&f->lock);
1433 } else
1434 reply_err(req, err);
1435
1436 if (path)
1437 free(path);
1438 pthread_rwlock_unlock(&f->tree_lock);
1439}
1440
Miklos Szeredi320abe42006-01-30 18:14:51 +00001441static double diff_timespec(const struct timespec *t1,
1442 const struct timespec *t2)
1443{
1444 return (t1->tv_sec - t2->tv_sec) +
1445 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1446}
1447
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001448static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1449 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001450{
1451 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001452 if (node->cache_valid) {
1453 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001454
Miklos Szeredi08dab162006-02-01 13:39:15 +00001455 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001456 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001457 struct stat stbuf;
1458 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001459
Miklos Szeredi08dab162006-02-01 13:39:15 +00001460 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001461 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001462 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001463 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001464
1465 if (!err)
1466 update_stat(node, &stbuf);
1467 else
1468 node->cache_valid = 0;
1469 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001470 }
1471 if (node->cache_valid)
1472 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001473
1474 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001475}
1476
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001477static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1478 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001479{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001480 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001481 char *path = NULL;
1482 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001483
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001484 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001485 if (f->op.open) {
1486 err = -ENOENT;
1487 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001488 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001489 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001490 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001491 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001492 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001493 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1494 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001495 fflush(stdout);
1496 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001497
Miklos Szeredi659743b2005-12-09 17:41:42 +00001498 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001499 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001500 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001501 fi->keep_cache = 1;
1502
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001503 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001504 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001505 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001506
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001507 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001508 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001509 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001510 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001511 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001512 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001513 node->open_count ++;
1514 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001515 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001516 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001517 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001518
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001519 if (path)
1520 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001521 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001522}
1523
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001524static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1525 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001526{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001527 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001528 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001529 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001530 int res;
1531
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001532 buf = (char *) malloc(size);
1533 if (buf == NULL) {
1534 reply_err(req, -ENOMEM);
1535 return;
1536 }
1537
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001538 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001539 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001540 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001541 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001542 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001543 printf("READ[%llu] %lu bytes from %llu\n",
1544 (unsigned long long) fi->fh, (unsigned long) size,
1545 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001546 fflush(stdout);
1547 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001548
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001549 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001550 if (f->op.read) {
1551 struct fuse_intr_data d;
1552 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001553 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001554 fuse_finish_interrupt(f, req, &d);
1555 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001556 free(path);
1557 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001558 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001559
1560 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001561 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001562 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1563 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001564 fflush(stdout);
1565 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001566 if ((size_t) res > size)
1567 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001568 fuse_reply_buf(req, buf, res);
1569 } else
1570 reply_err(req, res);
1571
1572 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001573}
1574
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001575static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1576 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001577{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001578 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001579 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001580 int res;
1581
1582 res = -ENOENT;
1583 pthread_rwlock_rdlock(&f->tree_lock);
1584 path = get_path(f, ino);
1585 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001586 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001587 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001588 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001589 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001590 fflush(stdout);
1591 }
1592
1593 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001594 if (f->op.write) {
1595 struct fuse_intr_data d;
1596 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001598 fuse_finish_interrupt(f, req, &d);
1599 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001600 free(path);
1601 }
1602 pthread_rwlock_unlock(&f->tree_lock);
1603
Miklos Szeredif412d072005-10-14 21:24:32 +00001604 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001605 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001606 printf(" WRITE%s[%llu] %u bytes\n",
1607 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1608 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001609 fflush(stdout);
1610 }
1611 if ((size_t) res > size)
1612 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001613 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001614 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001615 reply_err(req, res);
1616}
1617
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001618static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1619 struct fuse_file_info *fi)
1620{
1621 struct fuse *f = req_fuse_prepare(req);
1622 char *path;
1623 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001624 int unlink_hidden = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001625
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001626 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001627 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001628 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001629 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1630 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001631 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001632 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001633 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001634 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001635
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001636 pthread_mutex_lock(&f->lock);
1637 node = get_node(f, ino);
1638 assert(node->open_count > 0);
1639 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001640 if (node->is_hidden && !node->open_count) {
1641 unlink_hidden = 1;
1642 node->is_hidden = 0;
1643 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001644 pthread_mutex_unlock(&f->lock);
1645
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001646 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001647 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001648
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001649 if (path)
1650 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001651 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001652
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001653 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001654}
1655
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001656static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1657 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001658{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001659 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001660 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001661 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001662
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001663 err = -ENOENT;
1664 pthread_rwlock_rdlock(&f->tree_lock);
1665 path = get_path(f, ino);
1666 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001667 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001668 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001669 fflush(stdout);
1670 }
1671 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001672 if (f->op.fsync) {
1673 struct fuse_intr_data d;
1674 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001675 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001676 fuse_finish_interrupt(f, req, &d);
1677 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001678 free(path);
1679 }
1680 pthread_rwlock_unlock(&f->tree_lock);
1681 reply_err(req, err);
1682}
1683
1684static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1685 struct fuse_file_info *fi)
1686{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001687 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001688 memset(fi, 0, sizeof(struct fuse_file_info));
1689 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001690 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001691 return dh;
1692}
1693
1694static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1695 struct fuse_file_info *llfi)
1696{
1697 struct fuse *f = req_fuse_prepare(req);
1698 struct fuse_dirhandle *dh;
1699
1700 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1701 if (dh == NULL) {
1702 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001703 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001704 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001705 memset(dh, 0, sizeof(struct fuse_dirhandle));
1706 dh->fuse = f;
1707 dh->contents = NULL;
1708 dh->len = 0;
1709 dh->filled = 0;
1710 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001711 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001712
Miklos Szeredi3a770472005-11-11 21:32:42 +00001713 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001714
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001715 if (f->op.opendir) {
1716 struct fuse_file_info fi;
1717 char *path;
1718 int err;
1719
1720 memset(&fi, 0, sizeof(fi));
1721 fi.flags = llfi->flags;
1722
1723 err = -ENOENT;
1724 pthread_rwlock_rdlock(&f->tree_lock);
1725 path = get_path(f, ino);
1726 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001727 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001728 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001729 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001730 if (!err) {
1731 pthread_mutex_lock(&f->lock);
1732 if (fuse_reply_open(req, llfi) == -ENOENT) {
1733 /* The opendir syscall was interrupted, so it must be
1734 cancelled */
1735 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001736 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001737 pthread_mutex_destroy(&dh->lock);
1738 free(dh);
1739 }
1740 pthread_mutex_unlock(&f->lock);
1741 } else {
1742 reply_err(req, err);
1743 free(dh);
1744 }
Miklos Szerediab974562005-04-07 15:40:21 +00001745 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001746 pthread_rwlock_unlock(&f->tree_lock);
1747 } else
1748 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001749}
Miklos Szeredib483c932001-10-29 14:57:57 +00001750
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001751static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1752{
1753 if (minsize > dh->size) {
1754 char *newptr;
1755 unsigned newsize = dh->size;
1756 if (!newsize)
1757 newsize = 1024;
1758 while (newsize < minsize)
1759 newsize *= 2;
1760
1761 newptr = (char *) realloc(dh->contents, newsize);
1762 if (!newptr) {
1763 dh->error = -ENOMEM;
1764 return -1;
1765 }
1766 dh->contents = newptr;
1767 dh->size = newsize;
1768 }
1769 return 0;
1770}
1771
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001772static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001773 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001774{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001775 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001776 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001777
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001778 if (statp)
1779 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001780 else {
1781 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001782 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001783 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001784
Miklos Szeredi659743b2005-12-09 17:41:42 +00001785 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001786 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001787 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001788 struct node *node;
1789 pthread_mutex_lock(&dh->fuse->lock);
1790 node = lookup_node(dh->fuse, dh->nodeid, name);
1791 if (node)
1792 stbuf.st_ino = (ino_t) node->nodeid;
1793 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001794 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001795 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001796
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001797 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001798 if (extend_contents(dh, dh->needlen) == -1)
1799 return 1;
1800
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001801 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001802 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1803 dh->needlen - dh->len, name,
1804 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001805 if (newlen > dh->needlen)
1806 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001807 } else {
1808 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1809 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001810 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001811
1812 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1813 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001814 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001815 dh->len = newlen;
1816 return 0;
1817}
1818
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001819static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001820 off_t off)
1821{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001822 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001823}
1824
1825static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1826 ino_t ino)
1827{
1828 struct stat stbuf;
1829
1830 memset(&stbuf, 0, sizeof(stbuf));
1831 stbuf.st_mode = type << 12;
1832 stbuf.st_ino = ino;
1833
1834 fill_dir_common(dh, name, &stbuf, 0);
1835 return dh->error;
1836}
1837
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001838static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1839 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001840 struct fuse_file_info *fi)
1841{
1842 int err = -ENOENT;
1843 char *path;
1844 pthread_rwlock_rdlock(&f->tree_lock);
1845 path = get_path(f, ino);
1846 if (path != NULL) {
1847 dh->len = 0;
1848 dh->error = 0;
1849 dh->needlen = size;
1850 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001851 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001852 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001853 if (f->op.readdir) {
1854 struct fuse_intr_data d;
1855 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001856 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001857 fuse_finish_interrupt(f, req, &d);
1858 } else if (f->op.getdir) {
1859 struct fuse_intr_data d;
1860 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001861 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001862 fuse_finish_interrupt(f, req, &d);
1863 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001864 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001865 if (!err)
1866 err = dh->error;
1867 if (err)
1868 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001869 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001870 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001871 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001872 return err;
1873}
Miklos Szeredie5183742005-02-02 11:14:04 +00001874
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001875static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1876 off_t off, struct fuse_file_info *llfi)
1877{
1878 struct fuse *f = req_fuse_prepare(req);
1879 struct fuse_file_info fi;
1880 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1881
1882 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001883 /* According to SUS, directory contents need to be refreshed on
1884 rewinddir() */
1885 if (!off)
1886 dh->filled = 0;
1887
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001888 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001889 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001890 if (err) {
1891 reply_err(req, err);
1892 goto out;
1893 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001894 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 if (dh->filled) {
1896 if (off < dh->len) {
1897 if (off + size > dh->len)
1898 size = dh->len - off;
1899 } else
1900 size = 0;
1901 } else {
1902 size = dh->len;
1903 off = 0;
1904 }
1905 fuse_reply_buf(req, dh->contents + off, size);
1906 out:
1907 pthread_mutex_unlock(&dh->lock);
1908}
Miklos Szeredia181e612001-11-06 12:03:23 +00001909
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001910static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1911 struct fuse_file_info *llfi)
1912{
1913 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001914 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001915 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1916 if (f->op.releasedir) {
1917 char *path;
1918
1919 pthread_rwlock_rdlock(&f->tree_lock);
1920 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001921 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001922 free(path);
1923 pthread_rwlock_unlock(&f->tree_lock);
1924 }
1925 pthread_mutex_lock(&dh->lock);
1926 pthread_mutex_unlock(&dh->lock);
1927 pthread_mutex_destroy(&dh->lock);
1928 free(dh->contents);
1929 free(dh);
1930 reply_err(req, 0);
1931}
1932
1933static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1934 struct fuse_file_info *llfi)
1935{
1936 struct fuse *f = req_fuse_prepare(req);
1937 struct fuse_file_info fi;
1938 char *path;
1939 int err;
1940
1941 get_dirhandle(llfi, &fi);
1942
1943 err = -ENOENT;
1944 pthread_rwlock_rdlock(&f->tree_lock);
1945 path = get_path(f, ino);
1946 if (path != NULL) {
1947 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001948 if (f->op.fsyncdir) {
1949 struct fuse_intr_data d;
1950 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001951 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001952 fuse_finish_interrupt(f, req, &d);
1953 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001954 free(path);
1955 }
1956 pthread_rwlock_unlock(&f->tree_lock);
1957 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001958}
1959
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001960static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001961{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001962 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001963 buf->f_bsize = 512;
1964 return 0;
1965}
1966
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001967static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001968{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001969 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001970 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001971 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001972
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001973 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001974 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001975 if (ino && (!f->compat || f->compat >= 26)) {
1976 char *path;
1977 pthread_rwlock_rdlock(&f->tree_lock);
1978 err = -ENOENT;
1979 path = get_path(f, ino);
1980 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001981 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001982 free(path);
1983 }
1984 pthread_rwlock_unlock(&f->tree_lock);
1985 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001986 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001987 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001988 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001989
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001990 if (!err)
1991 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001992 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001994}
1995
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001996static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1997 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001998{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001999 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002000 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002001 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002002
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002003 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002004 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002005 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002006 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002007 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002008 if (f->op.setxattr) {
2009 struct fuse_intr_data d;
2010 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002012 fuse_finish_interrupt(f, req, &d);
2013 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002014 free(path);
2015 }
2016 pthread_rwlock_unlock(&f->tree_lock);
2017 reply_err(req, err);
2018}
2019
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002020static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2021 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002022{
2023 int err;
2024 char *path;
2025
2026 err = -ENOENT;
2027 pthread_rwlock_rdlock(&f->tree_lock);
2028 path = get_path(f, ino);
2029 if (path != NULL) {
2030 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002031 if (f->op.getxattr) {
2032 struct fuse_intr_data d;
2033 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002035 fuse_finish_interrupt(f, req, &d);
2036 }
Miklos Szerediab974562005-04-07 15:40:21 +00002037 free(path);
2038 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002039 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002040 return err;
2041}
2042
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002043static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2044 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002045{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002046 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002047 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002048
2049 if (size) {
2050 char *value = (char *) malloc(size);
2051 if (value == NULL) {
2052 reply_err(req, -ENOMEM);
2053 return;
2054 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002055 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002056 if (res > 0)
2057 fuse_reply_buf(req, value, res);
2058 else
2059 reply_err(req, res);
2060 free(value);
2061 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002062 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002063 if (res >= 0)
2064 fuse_reply_xattr(req, res);
2065 else
2066 reply_err(req, res);
2067 }
2068}
2069
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002070static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2071 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002072{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002073 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002074 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002075
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002076 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002077 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002078 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002079 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002080 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002081 if (f->op.listxattr) {
2082 struct fuse_intr_data d;
2083 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002084 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002085 fuse_finish_interrupt(f, req, &d);
2086 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002087 free(path);
2088 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002089 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002090 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002091}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002092
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002093static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002094{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002095 struct fuse *f = req_fuse_prepare(req);
2096 int res;
2097
2098 if (size) {
2099 char *list = (char *) malloc(size);
2100 if (list == NULL) {
2101 reply_err(req, -ENOMEM);
2102 return;
2103 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002104 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002105 if (res > 0)
2106 fuse_reply_buf(req, list, res);
2107 else
2108 reply_err(req, res);
2109 free(list);
2110 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002111 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002112 if (res >= 0)
2113 fuse_reply_xattr(req, res);
2114 else
2115 reply_err(req, res);
2116 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002117}
2118
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002119static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2120{
2121 struct fuse *f = req_fuse_prepare(req);
2122 char *path;
2123 int err;
2124
2125 err = -ENOENT;
2126 pthread_rwlock_rdlock(&f->tree_lock);
2127 path = get_path(f, ino);
2128 if (path != NULL) {
2129 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002130 if (f->op.removexattr) {
2131 struct fuse_intr_data d;
2132 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002133 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002134 fuse_finish_interrupt(f, req, &d);
2135 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002136 free(path);
2137 }
2138 pthread_rwlock_unlock(&f->tree_lock);
2139 reply_err(req, err);
2140}
2141
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002142static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2143{
2144 struct lock *l;
2145
2146 for (l = node->locks; l; l = l->next)
2147 if (l->owner != lock->owner &&
2148 lock->start <= l->end && l->start <= lock->end &&
2149 (l->type == F_WRLCK || lock->type == F_WRLCK))
2150 break;
2151
2152 return l;
2153}
2154
2155static void delete_lock(struct lock **lockp)
2156{
2157 struct lock *l = *lockp;
2158 *lockp = l->next;
2159 free(l);
2160}
2161
2162static void insert_lock(struct lock **pos, struct lock *lock)
2163{
2164 lock->next = *pos;
2165 *pos = lock;
2166}
2167
2168static int locks_insert(struct node *node, struct lock *lock)
2169{
2170 struct lock **lp;
2171 struct lock *newl1 = NULL;
2172 struct lock *newl2 = NULL;
2173
2174 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2175 newl1 = malloc(sizeof(struct lock));
2176 newl2 = malloc(sizeof(struct lock));
2177
2178 if (!newl1 || !newl2) {
2179 free(newl1);
2180 free(newl2);
2181 return -ENOLCK;
2182 }
2183 }
2184
2185 for (lp = &node->locks; *lp;) {
2186 struct lock *l = *lp;
2187 if (l->owner != lock->owner)
2188 goto skip;
2189
2190 if (lock->type == l->type) {
2191 if (l->end < lock->start - 1)
2192 goto skip;
2193 if (lock->end < l->start - 1)
2194 break;
2195 if (l->start <= lock->start && lock->end <= l->end)
2196 goto out;
2197 if (l->start < lock->start)
2198 lock->start = l->start;
2199 if (lock->end < l->end)
2200 lock->end = l->end;
2201 goto delete;
2202 } else {
2203 if (l->end < lock->start)
2204 goto skip;
2205 if (lock->end < l->start)
2206 break;
2207 if (lock->start <= l->start && l->end <= lock->end)
2208 goto delete;
2209 if (l->end <= lock->end) {
2210 l->end = lock->start - 1;
2211 goto skip;
2212 }
2213 if (lock->start <= l->start) {
2214 l->start = lock->end + 1;
2215 break;
2216 }
2217 *newl2 = *l;
2218 newl2->start = lock->end + 1;
2219 l->end = lock->start - 1;
2220 insert_lock(&l->next, newl2);
2221 newl2 = NULL;
2222 }
2223 skip:
2224 lp = &l->next;
2225 continue;
2226
2227 delete:
2228 delete_lock(lp);
2229 }
2230 if (lock->type != F_UNLCK) {
2231 *newl1 = *lock;
2232 insert_lock(lp, newl1);
2233 newl1 = NULL;
2234 }
2235out:
2236 free(newl1);
2237 free(newl2);
2238 return 0;
2239}
2240
2241static void flock_to_lock(struct flock *flock, struct lock *lock)
2242{
2243 memset(lock, 0, sizeof(struct lock));
2244 lock->type = flock->l_type;
2245 lock->start = flock->l_start;
2246 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2247 lock->pid = flock->l_pid;
2248}
2249
2250static void lock_to_flock(struct lock *lock, struct flock *flock)
2251{
2252 flock->l_type = lock->type;
2253 flock->l_start = lock->start;
2254 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2255 flock->l_pid = lock->pid;
2256}
2257
2258static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
2259 struct fuse_file_info *fi, uint64_t owner)
2260{
2261 struct fuse *f = req_fuse_prepare(req);
2262 char *path;
2263 int err;
2264
2265 err = -ENOENT;
2266 pthread_rwlock_rdlock(&f->tree_lock);
2267 path = get_path(f, ino);
2268 if (path != NULL) {
2269 if (f->conf.debug) {
2270 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2271 fflush(stdout);
2272 }
2273 err = -ENOSYS;
2274 if (f->op.flush) {
2275 struct fuse_intr_data d;
2276 fuse_prepare_interrupt(f, req, &d);
2277 err = f->op.flush(path, fi);
2278 fuse_finish_interrupt(f, req, &d);
2279 }
2280 free(path);
2281 }
2282 if (f->op.lock) {
2283 struct flock lock;
2284 struct lock l;
2285 memset(&lock, 0, sizeof(lock));
2286 lock.l_type = F_UNLCK;
2287 lock.l_whence = SEEK_SET;
2288 fuse_do_lock(f, req, path, fi, F_SETLK, &lock, owner);
2289 flock_to_lock(&lock, &l);
2290 l.owner = owner;
2291 pthread_mutex_lock(&f->lock);
2292 locks_insert(get_node(f, ino), &l);
2293 pthread_mutex_unlock(&f->lock);
2294
2295 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2296 if (err == -ENOSYS)
2297 err = 0;
2298 }
2299 pthread_rwlock_unlock(&f->tree_lock);
2300 reply_err(req, err);
2301}
2302
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002303static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2304 struct fuse_file_info *fi, struct flock *lock,
2305 uint64_t owner, int cmd)
2306{
2307 struct fuse *f = req_fuse_prepare(req);
2308 char *path;
2309 int err;
2310
2311 err = -ENOENT;
2312 pthread_rwlock_rdlock(&f->tree_lock);
2313 path = get_path(f, ino);
2314 if (path != NULL) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002315 err = fuse_do_lock(f, req, path, fi, cmd, lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002316 free(path);
2317 }
2318 pthread_rwlock_unlock(&f->tree_lock);
2319 return err;
2320}
2321
2322static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
2323 struct fuse_file_info *fi, struct flock *lock,
2324 uint64_t owner)
2325{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002326 int err;
2327 struct lock l;
2328 struct lock *conflict;
2329 struct fuse *f = req_fuse(req);
2330
2331 flock_to_lock(lock, &l);
2332 l.owner = owner;
2333 pthread_mutex_lock(&f->lock);
2334 conflict = locks_conflict(get_node(f, ino), &l);
2335 if (conflict)
2336 lock_to_flock(conflict, lock);
2337 pthread_mutex_unlock(&f->lock);
2338 if (!conflict)
2339 err = fuse_lock_common(req, ino, fi, lock, owner, F_GETLK);
2340 else
2341 err = 0;
2342
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002343 if (!err)
2344 fuse_reply_lock(req, lock);
2345 else
2346 reply_err(req, err);
2347}
2348
2349static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2350 struct fuse_file_info *fi, struct flock *lock,
2351 uint64_t owner, int sleep)
2352{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002353 int err = fuse_lock_common(req, ino, fi, lock, owner,
2354 sleep ? F_SETLKW : F_SETLK);
2355 if (!err) {
2356 struct fuse *f = req_fuse(req);
2357 struct lock l;
2358 flock_to_lock(lock, &l);
2359 l.owner = owner;
2360 pthread_mutex_lock(&f->lock);
2361 locks_insert(get_node(f, ino), &l);
2362 pthread_mutex_unlock(&f->lock);
2363 }
2364 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002365}
2366
Miklos Szeredia1482422005-08-14 23:00:27 +00002367static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002368 .init = fuse_data_init,
2369 .destroy = fuse_data_destroy,
2370 .lookup = fuse_lookup,
2371 .forget = fuse_forget,
2372 .getattr = fuse_getattr,
2373 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002374 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002375 .readlink = fuse_readlink,
2376 .mknod = fuse_mknod,
2377 .mkdir = fuse_mkdir,
2378 .unlink = fuse_unlink,
2379 .rmdir = fuse_rmdir,
2380 .symlink = fuse_symlink,
2381 .rename = fuse_rename,
2382 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002383 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002384 .open = fuse_open,
2385 .read = fuse_read,
2386 .write = fuse_write,
2387 .flush = fuse_flush,
2388 .release = fuse_release,
2389 .fsync = fuse_fsync,
2390 .opendir = fuse_opendir,
2391 .readdir = fuse_readdir,
2392 .releasedir = fuse_releasedir,
2393 .fsyncdir = fuse_fsyncdir,
2394 .statfs = fuse_statfs,
2395 .setxattr = fuse_setxattr,
2396 .getxattr = fuse_getxattr,
2397 .listxattr = fuse_listxattr,
2398 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002399 .getlk = fuse_getlk,
2400 .setlk = fuse_setlk,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002401};
2402
Miklos Szeredia1482422005-08-14 23:00:27 +00002403static void free_cmd(struct fuse_cmd *cmd)
2404{
2405 free(cmd->buf);
2406 free(cmd);
2407}
2408
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002409void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002410{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002411 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002412 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002413}
2414
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002415int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002416{
Miklos Szeredia1482422005-08-14 23:00:27 +00002417 return fuse_session_exited(f->se);
2418}
2419
2420struct fuse_session *fuse_get_session(struct fuse *f)
2421{
2422 return f->se;
2423}
2424
2425static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2426{
2427 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2428 if (cmd == NULL) {
2429 fprintf(stderr, "fuse: failed to allocate cmd\n");
2430 return NULL;
2431 }
2432 cmd->buf = (char *) malloc(bufsize);
2433 if (cmd->buf == NULL) {
2434 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2435 free(cmd);
2436 return NULL;
2437 }
2438 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002439}
2440
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002441struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002442{
Miklos Szeredia1482422005-08-14 23:00:27 +00002443 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2444 size_t bufsize = fuse_chan_bufsize(ch);
2445 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2446 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002447 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002448 if (res <= 0) {
2449 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002450 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002451 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002452 return NULL;
2453 }
2454 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002455 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002456 }
2457 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002458}
2459
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002460int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002461{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002462 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002463 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002464 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002465 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002466}
2467
Miklos Szeredi891b8742004-07-29 09:27:49 +00002468int fuse_invalidate(struct fuse *f, const char *path)
2469{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002470 (void) f;
2471 (void) path;
2472 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002473}
2474
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002475void fuse_exit(struct fuse *f)
2476{
Miklos Szeredia1482422005-08-14 23:00:27 +00002477 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002478}
2479
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002480struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002481{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002482 return &fuse_get_context_internal()->ctx;
2483}
2484
2485int fuse_interrupted(void)
2486{
2487 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002488}
2489
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002490void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002491{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002492 (void) func;
2493 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002494}
2495
Miklos Szerediad005972006-01-07 10:14:34 +00002496enum {
2497 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002498};
2499
Miklos Szeredi659743b2005-12-09 17:41:42 +00002500#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2501
2502static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002503 FUSE_OPT_KEY("-h", KEY_HELP),
2504 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002505 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2506 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002507 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002508 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002509 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2510 FUSE_LIB_OPT("use_ino", use_ino, 1),
2511 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2512 FUSE_LIB_OPT("direct_io", direct_io, 1),
2513 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002514 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2515 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002516 FUSE_LIB_OPT("umask=", set_mode, 1),
2517 FUSE_LIB_OPT("umask=%o", umask, 0),
2518 FUSE_LIB_OPT("uid=", set_uid, 1),
2519 FUSE_LIB_OPT("uid=%d", uid, 0),
2520 FUSE_LIB_OPT("gid=", set_gid, 1),
2521 FUSE_LIB_OPT("gid=%d", gid, 0),
2522 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2523 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002524 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2525 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002526 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002527 FUSE_LIB_OPT("intr", intr, 1),
2528 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002529 FUSE_OPT_END
2530};
2531
Miklos Szerediad005972006-01-07 10:14:34 +00002532static void fuse_lib_help(void)
2533{
2534 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002535" -o hard_remove immediate removal (don't hide files)\n"
2536" -o use_ino let filesystem set inode numbers\n"
2537" -o readdir_ino try to fill in d_ino in readdir\n"
2538" -o direct_io use direct I/O\n"
2539" -o kernel_cache cache files in kernel\n"
2540" -o [no]auto_cache enable caching based on modification times\n"
2541" -o umask=M set file permissions (octal)\n"
2542" -o uid=N set file owner\n"
2543" -o gid=N set file group\n"
2544" -o entry_timeout=T cache timeout for names (1.0s)\n"
2545" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002546" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2547" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002548" -o intr allow requests to be interrupted\n"
2549" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2550"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002551}
2552
2553static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2554 struct fuse_args *outargs)
2555{
2556 (void) data; (void) arg; (void) outargs;
2557
2558 if (key == KEY_HELP)
2559 fuse_lib_help();
2560
2561 return 1;
2562}
2563
2564
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002565int fuse_is_lib_option(const char *opt)
2566{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002567 return fuse_lowlevel_is_lib_option(opt) ||
2568 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002569}
2570
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002571static int fuse_init_intr_signal(int signum, int *installed)
2572{
2573 struct sigaction old_sa;
2574
2575 if (sigaction(signum, NULL, &old_sa) == -1) {
2576 perror("fuse: cannot get old signal handler");
2577 return -1;
2578 }
2579
2580 if (old_sa.sa_handler == SIG_DFL) {
2581 struct sigaction sa;
2582
2583 memset(&sa, 0, sizeof(struct sigaction));
2584 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002585 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002586
2587 if (sigaction(signum, &sa, NULL) == -1) {
2588 perror("fuse: cannot set interrupt signal handler");
2589 return -1;
2590 }
2591 *installed = 1;
2592 }
2593 return 0;
2594}
2595
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002596static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002597{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002598 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002599
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002600 memset(&sa, 0, sizeof(struct sigaction));
2601 sa.sa_handler = SIG_DFL;
2602 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002603}
2604
Miklos Szeredi6f385412006-03-17 15:05:40 +00002605struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002606 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002607 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002608{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002609 struct fuse *f;
2610 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002611 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002612
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002613 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002614 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002615 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002616 }
2617
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002618 if (fuse_create_context_key() == -1)
2619 goto out;
2620
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002621 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002622 if (f == NULL) {
2623 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002624 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002625 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002626
Miklos Szeredi6f385412006-03-17 15:05:40 +00002627 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002628 f->conf.entry_timeout = 1.0;
2629 f->conf.attr_timeout = 1.0;
2630 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002631 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002632
Miklos Szerediad005972006-01-07 10:14:34 +00002633 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002634 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002635
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002636 if (!f->conf.ac_attr_timeout_set)
2637 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2638
Miklos Szeredi659743b2005-12-09 17:41:42 +00002639#ifdef __FreeBSD__
2640 /*
2641 * In FreeBSD, we always use these settings as inode numbers are needed to
2642 * make getcwd(3) work.
2643 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002644 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002645#endif
2646
Miklos Szeredi065f2222006-01-20 15:15:21 +00002647 if (compat && compat <= 25) {
2648 if (fuse_sync_compat_args(args) == -1)
2649 goto out_free;
2650 }
2651
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002652 memcpy(&f->op, op, op_size);
2653 if (!f->op.lock) {
2654 llop.getlk = NULL;
2655 llop.setlk = NULL;
2656 }
2657
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002658 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002659 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002660 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002661
Miklos Szeredia1482422005-08-14 23:00:27 +00002662 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002663
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002664 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002665 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002666 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002667 f->name_table_size = 14057;
2668 f->name_table = (struct node **)
2669 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002670 if (f->name_table == NULL) {
2671 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002672 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002673 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002674
Miklos Szeredia13d9002004-11-02 17:32:03 +00002675 f->id_table_size = 14057;
2676 f->id_table = (struct node **)
2677 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002678 if (f->id_table == NULL) {
2679 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002680 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002681 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002682
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002683 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002684 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002685 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002686
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002687 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002688 if (root == NULL) {
2689 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002690 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002691 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002692
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002693 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002694 if (root->name == NULL) {
2695 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002696 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002697 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002698
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002699 if (f->conf.intr &&
2700 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2701 goto out_free_root_name;
2702
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002703 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002704 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002705 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002706 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002707 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002708 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002709
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002710 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002711
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002712 out_free_root_name:
2713 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002714 out_free_root:
2715 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002716 out_free_id_table:
2717 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002718 out_free_name_table:
2719 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002720 out_free_session:
2721 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002722 out_free:
2723 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002724 out_delete_context_key:
2725 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002726 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002727 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002728}
2729
Miklos Szeredi6f385412006-03-17 15:05:40 +00002730struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2731 const struct fuse_operations *op, size_t op_size,
2732 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002733{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002734 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002735}
2736
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002737void fuse_destroy(struct fuse *f)
2738{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002739 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002740 struct fuse_context_i *c = fuse_get_context_internal();
2741
2742 if (f->conf.intr && f->intr_installed)
2743 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002744
2745 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002746 c->ctx.fuse = f;
2747 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002748
Miklos Szeredia13d9002004-11-02 17:32:03 +00002749 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002750 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002751
Miklos Szeredia13d9002004-11-02 17:32:03 +00002752 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002753 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002754 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002755 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002756 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002757 free(path);
2758 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002759 }
2760 }
2761 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002762 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002763 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002764 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002765
Miklos Szeredia13d9002004-11-02 17:32:03 +00002766 for (node = f->id_table[i]; node != NULL; node = next) {
2767 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002768 free_node(node);
2769 }
2770 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002771 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002772 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002773 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002774 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002775 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002776 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002777 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002778}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002779
Miklos Szeredieafdf422006-09-22 19:30:17 +00002780#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002781#include "fuse_compat.h"
2782
Miklos Szeredi6f385412006-03-17 15:05:40 +00002783static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2784 const struct fuse_operations *op,
2785 size_t op_size, int compat)
2786{
2787 struct fuse *f = NULL;
2788 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2789
2790 if (ch)
2791 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2792
2793 return f;
2794}
2795
Miklos Szeredi065f2222006-01-20 15:15:21 +00002796#ifndef __FreeBSD__
2797
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002798static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2799 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002800{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002801 int err;
2802 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002803 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002804 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002805 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002806 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002807 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002808 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002809 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002810 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002811 memcpy(fi, &tmp, sizeof(tmp));
2812 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002813 } else {
2814 fuse_prepare_interrupt(f, req, &d);
2815 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002816 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002817 fuse_finish_interrupt(f, req, &d);
2818 }
2819 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002820}
2821
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002822static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2823 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002824{
2825 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002826 fuse_do_release(f, req, path ? path : "-", fi);
2827 else if (path) {
2828 struct fuse_intr_data d;
2829 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002830 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002831 fuse_finish_interrupt(f, req, &d);
2832 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002833}
2834
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002835static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2836 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002837{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002838 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002839 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002840 } else {
2841 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002842 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002843 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002844 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002845 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002846 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002847 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002848 memcpy(fi, &tmp, sizeof(tmp));
2849 fi->fh = tmp.fh;
2850 return err;
2851 }
2852}
2853
2854static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2855 struct statvfs *stbuf)
2856{
2857 stbuf->f_bsize = compatbuf->block_size;
2858 stbuf->f_blocks = compatbuf->blocks;
2859 stbuf->f_bfree = compatbuf->blocks_free;
2860 stbuf->f_bavail = compatbuf->blocks_free;
2861 stbuf->f_files = compatbuf->files;
2862 stbuf->f_ffree = compatbuf->files_free;
2863 stbuf->f_namemax = compatbuf->namelen;
2864}
2865
2866static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2867{
2868 stbuf->f_bsize = oldbuf->f_bsize;
2869 stbuf->f_blocks = oldbuf->f_blocks;
2870 stbuf->f_bfree = oldbuf->f_bfree;
2871 stbuf->f_bavail = oldbuf->f_bavail;
2872 stbuf->f_files = oldbuf->f_files;
2873 stbuf->f_ffree = oldbuf->f_ffree;
2874 stbuf->f_namemax = oldbuf->f_namelen;
2875}
2876
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002877static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2878 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002879{
2880 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002881 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002882
Miklos Szeredi065f2222006-01-20 15:15:21 +00002883 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002884 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002885 } else if (f->compat > 11) {
2886 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002887 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002888 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002889 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002890 if (!err)
2891 convert_statfs_old(&oldbuf, buf);
2892 } else {
2893 struct fuse_statfs_compat1 compatbuf;
2894 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002895 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002896 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002897 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002898 if (!err)
2899 convert_statfs_compat(&compatbuf, buf);
2900 }
2901 return err;
2902}
2903
Miklos Szeredi95da8602006-01-06 18:29:40 +00002904static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2905 const struct fuse_operations *op,
2906 size_t op_size, int compat)
2907{
2908 struct fuse *f;
2909 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2910
2911 if (opts &&
2912 (fuse_opt_add_arg(&args, "") == -1 ||
2913 fuse_opt_add_arg(&args, "-o") == -1 ||
2914 fuse_opt_add_arg(&args, opts) == -1)) {
2915 fuse_opt_free_args(&args);
2916 return NULL;
2917 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002918 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002919 fuse_opt_free_args(&args);
2920
2921 return f;
2922}
2923
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002924struct fuse *fuse_new_compat22(int fd, const char *opts,
2925 const struct fuse_operations_compat22 *op,
2926 size_t op_size)
2927{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002928 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2929 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002930}
2931
2932struct fuse *fuse_new_compat2(int fd, const char *opts,
2933 const struct fuse_operations_compat2 *op)
2934{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002935 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2936 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002937}
2938
2939struct fuse *fuse_new_compat1(int fd, int flags,
2940 const struct fuse_operations_compat1 *op)
2941{
2942 const char *opts = NULL;
2943 if (flags & FUSE_DEBUG_COMPAT1)
2944 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002945 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2946 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002947}
2948
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002949__asm__(".symver fuse_exited,__fuse_exited@");
2950__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2951__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2952__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2953__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002954__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002955
2956#else /* __FreeBSD__ */
2957
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002958static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2959 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002960{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002961 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002962}
2963
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002964static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2965 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002966{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002967 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002968}
2969
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002970static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2971 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002972{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002973 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002974}
2975
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002976static int fuse_do_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002977{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002978 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002979}
2980
2981#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00002982
2983struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
2984 const struct fuse_operations_compat25 *op,
2985 size_t op_size)
2986{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002987 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
2988 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00002989}
2990
2991__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");