blob: 92f21db9149906c4309f0b41722fda9490bfa749 [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 Szeredi288ed4e2006-09-07 06:02:44 +00001021static int do_utimes(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 Szeredifa440772006-09-02 09:51:08 +00001028 if (f->op.utimes) {
1029 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 Szeredifa440772006-09-02 09:51:08 +00001033 err = f->op.utimes(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 Szeredi288ed4e2006-09-07 06:02:44 +00001069 err = do_utimes(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 Szeredi0f62d722005-01-04 12:45:54 +00001624 int unlink_hidden;
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;
1640 unlink_hidden = (node->is_hidden && !node->open_count);
1641 pthread_mutex_unlock(&f->lock);
1642
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001643 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001644 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001645
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001646 if (path)
1647 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001648 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001649
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001650 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001651}
1652
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001653static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1654 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001655{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001656 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001657 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001658 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001659
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001660 err = -ENOENT;
1661 pthread_rwlock_rdlock(&f->tree_lock);
1662 path = get_path(f, ino);
1663 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001664 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001665 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001666 fflush(stdout);
1667 }
1668 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001669 if (f->op.fsync) {
1670 struct fuse_intr_data d;
1671 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001672 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001673 fuse_finish_interrupt(f, req, &d);
1674 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001675 free(path);
1676 }
1677 pthread_rwlock_unlock(&f->tree_lock);
1678 reply_err(req, err);
1679}
1680
1681static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1682 struct fuse_file_info *fi)
1683{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001684 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001685 memset(fi, 0, sizeof(struct fuse_file_info));
1686 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001687 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001688 return dh;
1689}
1690
1691static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1692 struct fuse_file_info *llfi)
1693{
1694 struct fuse *f = req_fuse_prepare(req);
1695 struct fuse_dirhandle *dh;
1696
1697 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1698 if (dh == NULL) {
1699 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001700 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001701 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001702 memset(dh, 0, sizeof(struct fuse_dirhandle));
1703 dh->fuse = f;
1704 dh->contents = NULL;
1705 dh->len = 0;
1706 dh->filled = 0;
1707 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001708 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001709
Miklos Szeredi3a770472005-11-11 21:32:42 +00001710 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001711
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001712 if (f->op.opendir) {
1713 struct fuse_file_info fi;
1714 char *path;
1715 int err;
1716
1717 memset(&fi, 0, sizeof(fi));
1718 fi.flags = llfi->flags;
1719
1720 err = -ENOENT;
1721 pthread_rwlock_rdlock(&f->tree_lock);
1722 path = get_path(f, ino);
1723 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001724 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001725 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001726 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001727 if (!err) {
1728 pthread_mutex_lock(&f->lock);
1729 if (fuse_reply_open(req, llfi) == -ENOENT) {
1730 /* The opendir syscall was interrupted, so it must be
1731 cancelled */
1732 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001733 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001734 pthread_mutex_destroy(&dh->lock);
1735 free(dh);
1736 }
1737 pthread_mutex_unlock(&f->lock);
1738 } else {
1739 reply_err(req, err);
1740 free(dh);
1741 }
Miklos Szerediab974562005-04-07 15:40:21 +00001742 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001743 pthread_rwlock_unlock(&f->tree_lock);
1744 } else
1745 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001746}
Miklos Szeredib483c932001-10-29 14:57:57 +00001747
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001748static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1749{
1750 if (minsize > dh->size) {
1751 char *newptr;
1752 unsigned newsize = dh->size;
1753 if (!newsize)
1754 newsize = 1024;
1755 while (newsize < minsize)
1756 newsize *= 2;
1757
1758 newptr = (char *) realloc(dh->contents, newsize);
1759 if (!newptr) {
1760 dh->error = -ENOMEM;
1761 return -1;
1762 }
1763 dh->contents = newptr;
1764 dh->size = newsize;
1765 }
1766 return 0;
1767}
1768
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001769static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001770 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001771{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001772 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001773 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001774
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001775 if (statp)
1776 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001777 else {
1778 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001779 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001780 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001781
Miklos Szeredi659743b2005-12-09 17:41:42 +00001782 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001783 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001784 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001785 struct node *node;
1786 pthread_mutex_lock(&dh->fuse->lock);
1787 node = lookup_node(dh->fuse, dh->nodeid, name);
1788 if (node)
1789 stbuf.st_ino = (ino_t) node->nodeid;
1790 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001791 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001792 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001793
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001794 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001795 if (extend_contents(dh, dh->needlen) == -1)
1796 return 1;
1797
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001798 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001799 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1800 dh->needlen - dh->len, name,
1801 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001802 if (newlen > dh->needlen)
1803 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001804 } else {
1805 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1806 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001807 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001808
1809 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1810 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001811 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001812 dh->len = newlen;
1813 return 0;
1814}
1815
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001816static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001817 off_t off)
1818{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001819 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001820}
1821
1822static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1823 ino_t ino)
1824{
1825 struct stat stbuf;
1826
1827 memset(&stbuf, 0, sizeof(stbuf));
1828 stbuf.st_mode = type << 12;
1829 stbuf.st_ino = ino;
1830
1831 fill_dir_common(dh, name, &stbuf, 0);
1832 return dh->error;
1833}
1834
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001835static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1836 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001837 struct fuse_file_info *fi)
1838{
1839 int err = -ENOENT;
1840 char *path;
1841 pthread_rwlock_rdlock(&f->tree_lock);
1842 path = get_path(f, ino);
1843 if (path != NULL) {
1844 dh->len = 0;
1845 dh->error = 0;
1846 dh->needlen = size;
1847 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001848 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001849 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001850 if (f->op.readdir) {
1851 struct fuse_intr_data d;
1852 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001853 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001854 fuse_finish_interrupt(f, req, &d);
1855 } else if (f->op.getdir) {
1856 struct fuse_intr_data d;
1857 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001858 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001859 fuse_finish_interrupt(f, req, &d);
1860 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001861 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001862 if (!err)
1863 err = dh->error;
1864 if (err)
1865 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001866 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001867 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001868 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001869 return err;
1870}
Miklos Szeredie5183742005-02-02 11:14:04 +00001871
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001872static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1873 off_t off, struct fuse_file_info *llfi)
1874{
1875 struct fuse *f = req_fuse_prepare(req);
1876 struct fuse_file_info fi;
1877 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1878
1879 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001880 /* According to SUS, directory contents need to be refreshed on
1881 rewinddir() */
1882 if (!off)
1883 dh->filled = 0;
1884
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001885 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001886 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001887 if (err) {
1888 reply_err(req, err);
1889 goto out;
1890 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001891 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001892 if (dh->filled) {
1893 if (off < dh->len) {
1894 if (off + size > dh->len)
1895 size = dh->len - off;
1896 } else
1897 size = 0;
1898 } else {
1899 size = dh->len;
1900 off = 0;
1901 }
1902 fuse_reply_buf(req, dh->contents + off, size);
1903 out:
1904 pthread_mutex_unlock(&dh->lock);
1905}
Miklos Szeredia181e612001-11-06 12:03:23 +00001906
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001907static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1908 struct fuse_file_info *llfi)
1909{
1910 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001911 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001912 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1913 if (f->op.releasedir) {
1914 char *path;
1915
1916 pthread_rwlock_rdlock(&f->tree_lock);
1917 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001918 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001919 free(path);
1920 pthread_rwlock_unlock(&f->tree_lock);
1921 }
1922 pthread_mutex_lock(&dh->lock);
1923 pthread_mutex_unlock(&dh->lock);
1924 pthread_mutex_destroy(&dh->lock);
1925 free(dh->contents);
1926 free(dh);
1927 reply_err(req, 0);
1928}
1929
1930static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1931 struct fuse_file_info *llfi)
1932{
1933 struct fuse *f = req_fuse_prepare(req);
1934 struct fuse_file_info fi;
1935 char *path;
1936 int err;
1937
1938 get_dirhandle(llfi, &fi);
1939
1940 err = -ENOENT;
1941 pthread_rwlock_rdlock(&f->tree_lock);
1942 path = get_path(f, ino);
1943 if (path != NULL) {
1944 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001945 if (f->op.fsyncdir) {
1946 struct fuse_intr_data d;
1947 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001948 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001949 fuse_finish_interrupt(f, req, &d);
1950 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001951 free(path);
1952 }
1953 pthread_rwlock_unlock(&f->tree_lock);
1954 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001955}
1956
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001957static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001958{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001959 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001960 buf->f_bsize = 512;
1961 return 0;
1962}
1963
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001964static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001965{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001966 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001967 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001968 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001969
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001970 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001971 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001972 if (ino && (!f->compat || f->compat >= 26)) {
1973 char *path;
1974 pthread_rwlock_rdlock(&f->tree_lock);
1975 err = -ENOENT;
1976 path = get_path(f, ino);
1977 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001978 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001979 free(path);
1980 }
1981 pthread_rwlock_unlock(&f->tree_lock);
1982 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001983 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001984 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001985 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001986
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001987 if (!err)
1988 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001989 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001990 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001991}
1992
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001993static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1994 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001995{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001996 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001997 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001998 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001999
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002000 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002001 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002002 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002003 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002004 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002005 if (f->op.setxattr) {
2006 struct fuse_intr_data d;
2007 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002008 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002009 fuse_finish_interrupt(f, req, &d);
2010 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 free(path);
2012 }
2013 pthread_rwlock_unlock(&f->tree_lock);
2014 reply_err(req, err);
2015}
2016
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002017static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2018 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002019{
2020 int err;
2021 char *path;
2022
2023 err = -ENOENT;
2024 pthread_rwlock_rdlock(&f->tree_lock);
2025 path = get_path(f, ino);
2026 if (path != NULL) {
2027 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002028 if (f->op.getxattr) {
2029 struct fuse_intr_data d;
2030 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002031 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002032 fuse_finish_interrupt(f, req, &d);
2033 }
Miklos Szerediab974562005-04-07 15:40:21 +00002034 free(path);
2035 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002036 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002037 return err;
2038}
2039
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002040static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2041 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002042{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002043 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002044 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002045
2046 if (size) {
2047 char *value = (char *) malloc(size);
2048 if (value == NULL) {
2049 reply_err(req, -ENOMEM);
2050 return;
2051 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002052 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002053 if (res > 0)
2054 fuse_reply_buf(req, value, res);
2055 else
2056 reply_err(req, res);
2057 free(value);
2058 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002059 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002060 if (res >= 0)
2061 fuse_reply_xattr(req, res);
2062 else
2063 reply_err(req, res);
2064 }
2065}
2066
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002067static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2068 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002069{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002070 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002071 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002072
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002073 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002074 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002075 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002076 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002077 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002078 if (f->op.listxattr) {
2079 struct fuse_intr_data d;
2080 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002081 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002082 fuse_finish_interrupt(f, req, &d);
2083 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002084 free(path);
2085 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002086 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002087 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002088}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002089
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002090static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002091{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002092 struct fuse *f = req_fuse_prepare(req);
2093 int res;
2094
2095 if (size) {
2096 char *list = (char *) malloc(size);
2097 if (list == NULL) {
2098 reply_err(req, -ENOMEM);
2099 return;
2100 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002101 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002102 if (res > 0)
2103 fuse_reply_buf(req, list, res);
2104 else
2105 reply_err(req, res);
2106 free(list);
2107 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002108 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002109 if (res >= 0)
2110 fuse_reply_xattr(req, res);
2111 else
2112 reply_err(req, res);
2113 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002114}
2115
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002116static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2117{
2118 struct fuse *f = req_fuse_prepare(req);
2119 char *path;
2120 int err;
2121
2122 err = -ENOENT;
2123 pthread_rwlock_rdlock(&f->tree_lock);
2124 path = get_path(f, ino);
2125 if (path != NULL) {
2126 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002127 if (f->op.removexattr) {
2128 struct fuse_intr_data d;
2129 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002130 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002131 fuse_finish_interrupt(f, req, &d);
2132 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002133 free(path);
2134 }
2135 pthread_rwlock_unlock(&f->tree_lock);
2136 reply_err(req, err);
2137}
2138
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002139static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2140{
2141 struct lock *l;
2142
2143 for (l = node->locks; l; l = l->next)
2144 if (l->owner != lock->owner &&
2145 lock->start <= l->end && l->start <= lock->end &&
2146 (l->type == F_WRLCK || lock->type == F_WRLCK))
2147 break;
2148
2149 return l;
2150}
2151
2152static void delete_lock(struct lock **lockp)
2153{
2154 struct lock *l = *lockp;
2155 *lockp = l->next;
2156 free(l);
2157}
2158
2159static void insert_lock(struct lock **pos, struct lock *lock)
2160{
2161 lock->next = *pos;
2162 *pos = lock;
2163}
2164
2165static int locks_insert(struct node *node, struct lock *lock)
2166{
2167 struct lock **lp;
2168 struct lock *newl1 = NULL;
2169 struct lock *newl2 = NULL;
2170
2171 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2172 newl1 = malloc(sizeof(struct lock));
2173 newl2 = malloc(sizeof(struct lock));
2174
2175 if (!newl1 || !newl2) {
2176 free(newl1);
2177 free(newl2);
2178 return -ENOLCK;
2179 }
2180 }
2181
2182 for (lp = &node->locks; *lp;) {
2183 struct lock *l = *lp;
2184 if (l->owner != lock->owner)
2185 goto skip;
2186
2187 if (lock->type == l->type) {
2188 if (l->end < lock->start - 1)
2189 goto skip;
2190 if (lock->end < l->start - 1)
2191 break;
2192 if (l->start <= lock->start && lock->end <= l->end)
2193 goto out;
2194 if (l->start < lock->start)
2195 lock->start = l->start;
2196 if (lock->end < l->end)
2197 lock->end = l->end;
2198 goto delete;
2199 } else {
2200 if (l->end < lock->start)
2201 goto skip;
2202 if (lock->end < l->start)
2203 break;
2204 if (lock->start <= l->start && l->end <= lock->end)
2205 goto delete;
2206 if (l->end <= lock->end) {
2207 l->end = lock->start - 1;
2208 goto skip;
2209 }
2210 if (lock->start <= l->start) {
2211 l->start = lock->end + 1;
2212 break;
2213 }
2214 *newl2 = *l;
2215 newl2->start = lock->end + 1;
2216 l->end = lock->start - 1;
2217 insert_lock(&l->next, newl2);
2218 newl2 = NULL;
2219 }
2220 skip:
2221 lp = &l->next;
2222 continue;
2223
2224 delete:
2225 delete_lock(lp);
2226 }
2227 if (lock->type != F_UNLCK) {
2228 *newl1 = *lock;
2229 insert_lock(lp, newl1);
2230 newl1 = NULL;
2231 }
2232out:
2233 free(newl1);
2234 free(newl2);
2235 return 0;
2236}
2237
2238static void flock_to_lock(struct flock *flock, struct lock *lock)
2239{
2240 memset(lock, 0, sizeof(struct lock));
2241 lock->type = flock->l_type;
2242 lock->start = flock->l_start;
2243 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2244 lock->pid = flock->l_pid;
2245}
2246
2247static void lock_to_flock(struct lock *lock, struct flock *flock)
2248{
2249 flock->l_type = lock->type;
2250 flock->l_start = lock->start;
2251 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2252 flock->l_pid = lock->pid;
2253}
2254
2255static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
2256 struct fuse_file_info *fi, uint64_t owner)
2257{
2258 struct fuse *f = req_fuse_prepare(req);
2259 char *path;
2260 int err;
2261
2262 err = -ENOENT;
2263 pthread_rwlock_rdlock(&f->tree_lock);
2264 path = get_path(f, ino);
2265 if (path != NULL) {
2266 if (f->conf.debug) {
2267 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2268 fflush(stdout);
2269 }
2270 err = -ENOSYS;
2271 if (f->op.flush) {
2272 struct fuse_intr_data d;
2273 fuse_prepare_interrupt(f, req, &d);
2274 err = f->op.flush(path, fi);
2275 fuse_finish_interrupt(f, req, &d);
2276 }
2277 free(path);
2278 }
2279 if (f->op.lock) {
2280 struct flock lock;
2281 struct lock l;
2282 memset(&lock, 0, sizeof(lock));
2283 lock.l_type = F_UNLCK;
2284 lock.l_whence = SEEK_SET;
2285 fuse_do_lock(f, req, path, fi, F_SETLK, &lock, owner);
2286 flock_to_lock(&lock, &l);
2287 l.owner = owner;
2288 pthread_mutex_lock(&f->lock);
2289 locks_insert(get_node(f, ino), &l);
2290 pthread_mutex_unlock(&f->lock);
2291
2292 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2293 if (err == -ENOSYS)
2294 err = 0;
2295 }
2296 pthread_rwlock_unlock(&f->tree_lock);
2297 reply_err(req, err);
2298}
2299
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002300static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2301 struct fuse_file_info *fi, struct flock *lock,
2302 uint64_t owner, int cmd)
2303{
2304 struct fuse *f = req_fuse_prepare(req);
2305 char *path;
2306 int err;
2307
2308 err = -ENOENT;
2309 pthread_rwlock_rdlock(&f->tree_lock);
2310 path = get_path(f, ino);
2311 if (path != NULL) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002312 err = fuse_do_lock(f, req, path, fi, cmd, lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002313 free(path);
2314 }
2315 pthread_rwlock_unlock(&f->tree_lock);
2316 return err;
2317}
2318
2319static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
2320 struct fuse_file_info *fi, struct flock *lock,
2321 uint64_t owner)
2322{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002323 int err;
2324 struct lock l;
2325 struct lock *conflict;
2326 struct fuse *f = req_fuse(req);
2327
2328 flock_to_lock(lock, &l);
2329 l.owner = owner;
2330 pthread_mutex_lock(&f->lock);
2331 conflict = locks_conflict(get_node(f, ino), &l);
2332 if (conflict)
2333 lock_to_flock(conflict, lock);
2334 pthread_mutex_unlock(&f->lock);
2335 if (!conflict)
2336 err = fuse_lock_common(req, ino, fi, lock, owner, F_GETLK);
2337 else
2338 err = 0;
2339
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002340 if (!err)
2341 fuse_reply_lock(req, lock);
2342 else
2343 reply_err(req, err);
2344}
2345
2346static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2347 struct fuse_file_info *fi, struct flock *lock,
2348 uint64_t owner, int sleep)
2349{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002350 int err = fuse_lock_common(req, ino, fi, lock, owner,
2351 sleep ? F_SETLKW : F_SETLK);
2352 if (!err) {
2353 struct fuse *f = req_fuse(req);
2354 struct lock l;
2355 flock_to_lock(lock, &l);
2356 l.owner = owner;
2357 pthread_mutex_lock(&f->lock);
2358 locks_insert(get_node(f, ino), &l);
2359 pthread_mutex_unlock(&f->lock);
2360 }
2361 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002362}
2363
Miklos Szeredia1482422005-08-14 23:00:27 +00002364static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002365 .init = fuse_data_init,
2366 .destroy = fuse_data_destroy,
2367 .lookup = fuse_lookup,
2368 .forget = fuse_forget,
2369 .getattr = fuse_getattr,
2370 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002371 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002372 .readlink = fuse_readlink,
2373 .mknod = fuse_mknod,
2374 .mkdir = fuse_mkdir,
2375 .unlink = fuse_unlink,
2376 .rmdir = fuse_rmdir,
2377 .symlink = fuse_symlink,
2378 .rename = fuse_rename,
2379 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002380 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002381 .open = fuse_open,
2382 .read = fuse_read,
2383 .write = fuse_write,
2384 .flush = fuse_flush,
2385 .release = fuse_release,
2386 .fsync = fuse_fsync,
2387 .opendir = fuse_opendir,
2388 .readdir = fuse_readdir,
2389 .releasedir = fuse_releasedir,
2390 .fsyncdir = fuse_fsyncdir,
2391 .statfs = fuse_statfs,
2392 .setxattr = fuse_setxattr,
2393 .getxattr = fuse_getxattr,
2394 .listxattr = fuse_listxattr,
2395 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002396 .getlk = fuse_getlk,
2397 .setlk = fuse_setlk,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002398};
2399
Miklos Szeredia1482422005-08-14 23:00:27 +00002400static void free_cmd(struct fuse_cmd *cmd)
2401{
2402 free(cmd->buf);
2403 free(cmd);
2404}
2405
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002406void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002407{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002408 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002409 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002410}
2411
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002412int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002413{
Miklos Szeredia1482422005-08-14 23:00:27 +00002414 return fuse_session_exited(f->se);
2415}
2416
2417struct fuse_session *fuse_get_session(struct fuse *f)
2418{
2419 return f->se;
2420}
2421
2422static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2423{
2424 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2425 if (cmd == NULL) {
2426 fprintf(stderr, "fuse: failed to allocate cmd\n");
2427 return NULL;
2428 }
2429 cmd->buf = (char *) malloc(bufsize);
2430 if (cmd->buf == NULL) {
2431 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2432 free(cmd);
2433 return NULL;
2434 }
2435 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002436}
2437
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002438struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002439{
Miklos Szeredia1482422005-08-14 23:00:27 +00002440 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2441 size_t bufsize = fuse_chan_bufsize(ch);
2442 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2443 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002444 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002445 if (res <= 0) {
2446 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002447 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002448 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002449 return NULL;
2450 }
2451 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002452 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002453 }
2454 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002455}
2456
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002457int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002458{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002459 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002460 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002461 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002462 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002463}
2464
Miklos Szeredi891b8742004-07-29 09:27:49 +00002465int fuse_invalidate(struct fuse *f, const char *path)
2466{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002467 (void) f;
2468 (void) path;
2469 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002470}
2471
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002472void fuse_exit(struct fuse *f)
2473{
Miklos Szeredia1482422005-08-14 23:00:27 +00002474 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002475}
2476
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002477struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002478{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002479 return &fuse_get_context_internal()->ctx;
2480}
2481
2482int fuse_interrupted(void)
2483{
2484 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002485}
2486
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002487void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002488{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002489 (void) func;
2490 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002491}
2492
Miklos Szerediad005972006-01-07 10:14:34 +00002493enum {
2494 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002495};
2496
Miklos Szeredi659743b2005-12-09 17:41:42 +00002497#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2498
2499static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002500 FUSE_OPT_KEY("-h", KEY_HELP),
2501 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002502 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2503 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002504 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002505 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002506 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2507 FUSE_LIB_OPT("use_ino", use_ino, 1),
2508 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2509 FUSE_LIB_OPT("direct_io", direct_io, 1),
2510 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002511 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2512 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002513 FUSE_LIB_OPT("umask=", set_mode, 1),
2514 FUSE_LIB_OPT("umask=%o", umask, 0),
2515 FUSE_LIB_OPT("uid=", set_uid, 1),
2516 FUSE_LIB_OPT("uid=%d", uid, 0),
2517 FUSE_LIB_OPT("gid=", set_gid, 1),
2518 FUSE_LIB_OPT("gid=%d", gid, 0),
2519 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2520 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002521 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2522 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002523 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002524 FUSE_LIB_OPT("intr", intr, 1),
2525 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002526 FUSE_OPT_END
2527};
2528
Miklos Szerediad005972006-01-07 10:14:34 +00002529static void fuse_lib_help(void)
2530{
2531 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002532" -o hard_remove immediate removal (don't hide files)\n"
2533" -o use_ino let filesystem set inode numbers\n"
2534" -o readdir_ino try to fill in d_ino in readdir\n"
2535" -o direct_io use direct I/O\n"
2536" -o kernel_cache cache files in kernel\n"
2537" -o [no]auto_cache enable caching based on modification times\n"
2538" -o umask=M set file permissions (octal)\n"
2539" -o uid=N set file owner\n"
2540" -o gid=N set file group\n"
2541" -o entry_timeout=T cache timeout for names (1.0s)\n"
2542" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002543" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2544" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002545" -o intr allow requests to be interrupted\n"
2546" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2547"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002548}
2549
2550static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2551 struct fuse_args *outargs)
2552{
2553 (void) data; (void) arg; (void) outargs;
2554
2555 if (key == KEY_HELP)
2556 fuse_lib_help();
2557
2558 return 1;
2559}
2560
2561
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002562int fuse_is_lib_option(const char *opt)
2563{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002564 return fuse_lowlevel_is_lib_option(opt) ||
2565 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002566}
2567
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002568static int fuse_init_intr_signal(int signum, int *installed)
2569{
2570 struct sigaction old_sa;
2571
2572 if (sigaction(signum, NULL, &old_sa) == -1) {
2573 perror("fuse: cannot get old signal handler");
2574 return -1;
2575 }
2576
2577 if (old_sa.sa_handler == SIG_DFL) {
2578 struct sigaction sa;
2579
2580 memset(&sa, 0, sizeof(struct sigaction));
2581 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002582 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002583
2584 if (sigaction(signum, &sa, NULL) == -1) {
2585 perror("fuse: cannot set interrupt signal handler");
2586 return -1;
2587 }
2588 *installed = 1;
2589 }
2590 return 0;
2591}
2592
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002593static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002594{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002595 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002596
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002597 memset(&sa, 0, sizeof(struct sigaction));
2598 sa.sa_handler = SIG_DFL;
2599 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002600}
2601
Miklos Szeredi6f385412006-03-17 15:05:40 +00002602struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002603 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002604 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002605{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002606 struct fuse *f;
2607 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002608 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002609
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002610 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002611 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002612 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002613 }
2614
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002615 if (fuse_create_context_key() == -1)
2616 goto out;
2617
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002618 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002619 if (f == NULL) {
2620 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002621 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002622 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002623
Miklos Szeredi6f385412006-03-17 15:05:40 +00002624 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002625 f->conf.entry_timeout = 1.0;
2626 f->conf.attr_timeout = 1.0;
2627 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002628 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002629
Miklos Szerediad005972006-01-07 10:14:34 +00002630 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002631 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002632
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002633 if (!f->conf.ac_attr_timeout_set)
2634 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2635
Miklos Szeredi659743b2005-12-09 17:41:42 +00002636#ifdef __FreeBSD__
2637 /*
2638 * In FreeBSD, we always use these settings as inode numbers are needed to
2639 * make getcwd(3) work.
2640 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002641 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002642#endif
2643
Miklos Szeredi065f2222006-01-20 15:15:21 +00002644 if (compat && compat <= 25) {
2645 if (fuse_sync_compat_args(args) == -1)
2646 goto out_free;
2647 }
2648
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002649 memcpy(&f->op, op, op_size);
2650 if (!f->op.lock) {
2651 llop.getlk = NULL;
2652 llop.setlk = NULL;
2653 }
2654
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002655 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002656 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002657 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002658
Miklos Szeredia1482422005-08-14 23:00:27 +00002659 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002660
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002661 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002662 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002663 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002664 f->name_table_size = 14057;
2665 f->name_table = (struct node **)
2666 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002667 if (f->name_table == NULL) {
2668 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002669 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002670 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002671
Miklos Szeredia13d9002004-11-02 17:32:03 +00002672 f->id_table_size = 14057;
2673 f->id_table = (struct node **)
2674 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002675 if (f->id_table == NULL) {
2676 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002677 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002678 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002679
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002680 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002681 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002682 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002683
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002684 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002685 if (root == NULL) {
2686 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002687 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002688 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002689
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002690 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002691 if (root->name == NULL) {
2692 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002693 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002694 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002695
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002696 if (f->conf.intr &&
2697 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2698 goto out_free_root_name;
2699
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002700 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002701 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002702 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002703 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002704 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002705 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002706
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002707 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002708
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002709 out_free_root_name:
2710 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002711 out_free_root:
2712 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002713 out_free_id_table:
2714 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002715 out_free_name_table:
2716 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002717 out_free_session:
2718 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002719 out_free:
2720 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002721 out_delete_context_key:
2722 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002723 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002724 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002725}
2726
Miklos Szeredi6f385412006-03-17 15:05:40 +00002727struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2728 const struct fuse_operations *op, size_t op_size,
2729 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002730{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002731 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002732}
2733
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002734void fuse_destroy(struct fuse *f)
2735{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002736 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002737 struct fuse_context_i *c = fuse_get_context_internal();
2738
2739 if (f->conf.intr && f->intr_installed)
2740 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002741
2742 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002743 c->ctx.fuse = f;
2744 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002745
Miklos Szeredia13d9002004-11-02 17:32:03 +00002746 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002747 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002748
Miklos Szeredia13d9002004-11-02 17:32:03 +00002749 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002750 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002751 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002752 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002753 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002754 free(path);
2755 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002756 }
2757 }
2758 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002759 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002760 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002761 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002762
Miklos Szeredia13d9002004-11-02 17:32:03 +00002763 for (node = f->id_table[i]; node != NULL; node = next) {
2764 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002765 free_node(node);
2766 }
2767 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002768 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002769 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002770 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002771 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002772 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002773 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002774 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002775}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002776
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002777#include "fuse_compat.h"
2778
Miklos Szeredi6f385412006-03-17 15:05:40 +00002779static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2780 const struct fuse_operations *op,
2781 size_t op_size, int compat)
2782{
2783 struct fuse *f = NULL;
2784 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2785
2786 if (ch)
2787 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2788
2789 return f;
2790}
2791
Miklos Szeredi065f2222006-01-20 15:15:21 +00002792#ifndef __FreeBSD__
2793
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002794static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2795 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002796{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002797 int err;
2798 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002799 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002800 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002801 else if (f->compat == 22) {
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002802 struct fuse_file_info_compat22 tmp;
2803 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002804 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002805 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002806 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002807 memcpy(fi, &tmp, sizeof(tmp));
2808 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002809 } else {
2810 fuse_prepare_interrupt(f, req, &d);
2811 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002812 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002813 fuse_finish_interrupt(f, req, &d);
2814 }
2815 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002816}
2817
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002818static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2819 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002820{
2821 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002822 fuse_do_release(f, req, path ? path : "-", fi);
2823 else if (path) {
2824 struct fuse_intr_data d;
2825 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002826 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002827 fuse_finish_interrupt(f, req, &d);
2828 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002829}
2830
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002831static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2832 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002833{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002834 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002835 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002836 } else {
2837 int err;
2838 struct fuse_file_info_compat22 tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002839 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002840 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002841 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002842 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002843 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002844 memcpy(fi, &tmp, sizeof(tmp));
2845 fi->fh = tmp.fh;
2846 return err;
2847 }
2848}
2849
2850static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2851 struct statvfs *stbuf)
2852{
2853 stbuf->f_bsize = compatbuf->block_size;
2854 stbuf->f_blocks = compatbuf->blocks;
2855 stbuf->f_bfree = compatbuf->blocks_free;
2856 stbuf->f_bavail = compatbuf->blocks_free;
2857 stbuf->f_files = compatbuf->files;
2858 stbuf->f_ffree = compatbuf->files_free;
2859 stbuf->f_namemax = compatbuf->namelen;
2860}
2861
2862static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2863{
2864 stbuf->f_bsize = oldbuf->f_bsize;
2865 stbuf->f_blocks = oldbuf->f_blocks;
2866 stbuf->f_bfree = oldbuf->f_bfree;
2867 stbuf->f_bavail = oldbuf->f_bavail;
2868 stbuf->f_files = oldbuf->f_files;
2869 stbuf->f_ffree = oldbuf->f_ffree;
2870 stbuf->f_namemax = oldbuf->f_namelen;
2871}
2872
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002873static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2874 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002875{
2876 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002877 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002878
Miklos Szeredi065f2222006-01-20 15:15:21 +00002879 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002880 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002881 } else if (f->compat > 11) {
2882 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002883 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002884 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002885 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002886 if (!err)
2887 convert_statfs_old(&oldbuf, buf);
2888 } else {
2889 struct fuse_statfs_compat1 compatbuf;
2890 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002891 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002892 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002893 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002894 if (!err)
2895 convert_statfs_compat(&compatbuf, buf);
2896 }
2897 return err;
2898}
2899
Miklos Szeredi95da8602006-01-06 18:29:40 +00002900static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2901 const struct fuse_operations *op,
2902 size_t op_size, int compat)
2903{
2904 struct fuse *f;
2905 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2906
2907 if (opts &&
2908 (fuse_opt_add_arg(&args, "") == -1 ||
2909 fuse_opt_add_arg(&args, "-o") == -1 ||
2910 fuse_opt_add_arg(&args, opts) == -1)) {
2911 fuse_opt_free_args(&args);
2912 return NULL;
2913 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002914 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002915 fuse_opt_free_args(&args);
2916
2917 return f;
2918}
2919
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002920struct fuse *fuse_new_compat22(int fd, const char *opts,
2921 const struct fuse_operations_compat22 *op,
2922 size_t op_size)
2923{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002924 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2925 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002926}
2927
2928struct fuse *fuse_new_compat2(int fd, const char *opts,
2929 const struct fuse_operations_compat2 *op)
2930{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002931 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2932 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002933}
2934
2935struct fuse *fuse_new_compat1(int fd, int flags,
2936 const struct fuse_operations_compat1 *op)
2937{
2938 const char *opts = NULL;
2939 if (flags & FUSE_DEBUG_COMPAT1)
2940 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002941 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2942 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002943}
2944
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002945__asm__(".symver fuse_exited,__fuse_exited@");
2946__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2947__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2948__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2949__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002950__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002951
2952#else /* __FreeBSD__ */
2953
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002954static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2955 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002956{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002957 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002958}
2959
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002960static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2961 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002962{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002963 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002964}
2965
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002966static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2967 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002968{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002969 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002970}
2971
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002972static int fuse_do_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002973{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002974 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002975}
2976
2977#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00002978
2979struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
2980 const struct fuse_operations_compat25 *op,
2981 size_t op_size)
2982{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002983 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
2984 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00002985}
2986
2987__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");