blob: 14789b7589f51fa55f7e48c317b99ea8fca68e05 [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
Csaba Henk3e3a1252006-09-24 14:53:29 +0000705#ifdef FUSE_STAT_HAS_NANOSEC
706 && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec
Miklos Szeredi320abe42006-01-30 18:14:51 +0000707#endif
708 ;
709}
710
711static void mtime_set(const struct stat *stbuf, struct timespec *ts)
712{
Csaba Henk3e3a1252006-09-24 14:53:29 +0000713#ifdef FUSE_STAT_HAS_NANOSEC
714 *ts = ST_MTIM(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +0000715#else
716 ts->tv_sec = stbuf->st_mtime;
717#endif
718}
719
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000720#ifndef CLOCK_MONOTONIC
721#define CLOCK_MONOTONIC CLOCK_REALTIME
722#endif
723
Miklos Szeredi320abe42006-01-30 18:14:51 +0000724static void curr_time(struct timespec *now)
725{
726 static clockid_t clockid = CLOCK_MONOTONIC;
727 int res = clock_gettime(clockid, now);
728 if (res == -1 && errno == EINVAL) {
729 clockid = CLOCK_REALTIME;
730 res = clock_gettime(clockid, now);
731 }
732 if (res == -1) {
733 perror("fuse: clock_gettime");
734 abort();
735 }
736}
737
738static void update_stat(struct node *node, const struct stat *stbuf)
739{
740 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
741 stbuf->st_size != node->size))
742 node->cache_valid = 0;
743 mtime_set(stbuf, &node->mtime);
744 node->size = stbuf->st_size;
745 curr_time(&node->stat_updated);
746}
747
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000748static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
749 const char *name, const char *path,
750 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000751{
752 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000753
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000754 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000755 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000756 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000757 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000758 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000760 struct node *node;
761
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000762 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000763 if (node == NULL)
764 res = -ENOMEM;
765 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000766 e->ino = node->nodeid;
767 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000768 e->entry_timeout = f->conf.entry_timeout;
769 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000770 if (f->conf.auto_cache) {
771 pthread_mutex_lock(&f->lock);
772 update_stat(node, &e->attr);
773 pthread_mutex_unlock(&f->lock);
774 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000775 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000776 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000777 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000778 fflush(stdout);
779 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000780 }
781 }
782 return res;
783}
784
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000785static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000787 struct fuse_context_i *c;
788
789 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
790 if (c == NULL) {
791 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
792 if (c == NULL) {
793 /* This is hard to deal with properly, so just abort. If
794 memory is so low that the context cannot be allocated,
795 there's not much hope for the filesystem anyway */
796 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
797 abort();
798 }
799 pthread_setspecific(fuse_context_key, c);
800 }
801 return c;
802}
803
804static void fuse_freecontext(void *data)
805{
806 free(data);
807}
808
809static int fuse_create_context_key(void)
810{
811 int err = 0;
812 pthread_mutex_lock(&fuse_context_lock);
813 if (!fuse_context_ref) {
814 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
815 if (err) {
816 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
817 strerror(err));
818 pthread_mutex_unlock(&fuse_context_lock);
819 return -1;
820 }
821 }
822 fuse_context_ref++;
823 pthread_mutex_unlock(&fuse_context_lock);
824 return 0;
825}
826
827static void fuse_delete_context_key(void)
828{
829 pthread_mutex_lock(&fuse_context_lock);
830 fuse_context_ref--;
831 if (!fuse_context_ref) {
832 free(pthread_getspecific(fuse_context_key));
833 pthread_key_delete(fuse_context_key);
834 }
835 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000836}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000837
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000838static struct fuse *req_fuse_prepare(fuse_req_t req)
839{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000840 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000841 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000842 c->req = req;
843 c->ctx.fuse = req_fuse(req);
844 c->ctx.uid = ctx->uid;
845 c->ctx.gid = ctx->gid;
846 c->ctx.pid = ctx->pid;
847 c->ctx.private_data = c->ctx.fuse->user_data;
848 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000849}
850
851static inline void reply_err(fuse_req_t req, int err)
852{
853 /* fuse_reply_err() uses non-negated errno values */
854 fuse_reply_err(req, -err);
855}
856
857static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
858 int err)
859{
860 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000861 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000862 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000863 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000864 } else
865 reply_err(req, err);
866}
867
Miklos Szeredi065f2222006-01-20 15:15:21 +0000868static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000869{
870 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000871 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000872
873 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000874 c->ctx.fuse = f;
875 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000876
877 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000878 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000879}
880
881static void fuse_data_destroy(void *data)
882{
883 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000884 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000885
886 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000887 c->ctx.fuse = f;
888 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000889
890 if (f->op.destroy)
891 f->op.destroy(f->user_data);
892}
893
894static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
895{
896 struct fuse *f = req_fuse_prepare(req);
897 struct fuse_entry_param e;
898 char *path;
899 int err;
900
901 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000902 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000903 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000905 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000906 printf("LOOKUP %s\n", path);
907 fflush(stdout);
908 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000909 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000910 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000911 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000912 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000913 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000914 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000915 err = 0;
916 }
917 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000918 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000919 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000920 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000921 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000922}
923
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000924static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000925{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000926 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000927 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000928 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000929 fflush(stdout);
930 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000931 forget_node(f, ino, nlookup);
932 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933}
934
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000935static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
936 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000937{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000938 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000939 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000940 char *path;
941 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000942
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000943 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000944 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000945
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000946 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000947 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000948 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000950 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000952 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000953 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000954 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000955 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000956 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000957 if (f->conf.auto_cache) {
958 pthread_mutex_lock(&f->lock);
959 update_stat(get_node(f, ino), &buf);
960 pthread_mutex_unlock(&f->lock);
961 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000962 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000963 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000964 } else
965 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000966}
967
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000968static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
969 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000970{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000971 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000972
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000973 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000974 if (f->op.chmod) {
975 struct fuse_intr_data d;
976 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000977 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000978 fuse_finish_interrupt(f, req, &d);
979 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000980
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000981 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000982}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000983
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
985 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000986{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000987 int err;
988 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
989 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000990
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000991 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000992 if (f->op.chown) {
993 struct fuse_intr_data d;
994 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000995 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000996 fuse_finish_interrupt(f, req, &d);
997 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000998
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000999 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001000}
1001
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001002static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1003 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001004{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001005 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001006 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001007
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001008 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001009 if (fi && f->op.ftruncate) {
1010 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001011 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001012 fuse_finish_interrupt(f, req, &d);
1013 } else if (f->op.truncate) {
1014 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001015 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001016 fuse_finish_interrupt(f, req, &d);
1017 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001018 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001019}
1020
Miklos Szeredic3b76812006-09-16 08:52:09 +00001021static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1022 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001023{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001024 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001025 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001026
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001027 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001028 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001029 struct timespec tv[2];
Csaba Henk3e3a1252006-09-24 14:53:29 +00001030#ifdef FUSE_STAT_HAS_NANOSEC
1031 tv[0] = ST_ATIM(attr);
1032 tv[1] = ST_MTIM(attr);
1033#else
1034 tv[0].tv_sec = attr->st_atime;
1035 tv[0].tv_nsec = 0;
1036 tv[1].tv_sec = attr->st_mtime;
1037 tv[1].tv_nsec = 0;
1038#endif
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001039 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001040 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001041 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001042 } else if (f->op.utime) {
1043 struct utimbuf buf;
1044 buf.actime = attr->st_atime;
1045 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001046 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001047 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001048 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001049 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001050
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001051 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001052}
1053
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001054static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001055 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001056{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001057 struct fuse *f = req_fuse_prepare(req);
1058 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001059 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001060 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001061
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001062 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001063 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001064 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001065 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001066 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001067 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001068 err = 0;
1069 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001070 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001071 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001072 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001073 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001074 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001075 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
Miklos Szeredic3b76812006-09-16 08:52:09 +00001076 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001077 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001078 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001079 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001080 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001081 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001082 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001083 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001084 if (f->conf.auto_cache) {
1085 pthread_mutex_lock(&f->lock);
1086 update_stat(get_node(f, ino), &buf);
1087 pthread_mutex_unlock(&f->lock);
1088 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001089 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001090 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001091 } else
1092 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001093}
1094
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001095static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1096{
1097 struct fuse *f = req_fuse_prepare(req);
1098 char *path;
1099 int err;
1100
1101 err = -ENOENT;
1102 pthread_rwlock_rdlock(&f->tree_lock);
1103 path = get_path(f, ino);
1104 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001105 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001106 printf("ACCESS %s 0%o\n", path, mask);
1107 fflush(stdout);
1108 }
1109 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001110 if (f->op.access) {
1111 struct fuse_intr_data d;
1112 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001113 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001114 fuse_finish_interrupt(f, req, &d);
1115 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001116 free(path);
1117 }
1118 pthread_rwlock_unlock(&f->tree_lock);
1119 reply_err(req, err);
1120}
1121
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001122static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001123{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001124 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001125 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001126 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001127 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001128
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001129 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001130 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001131 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001132 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001133 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001134 if (f->op.readlink) {
1135 struct fuse_intr_data d;
1136 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001137 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001138 fuse_finish_interrupt(f, req, &d);
1139 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001140 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001141 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001142 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001143 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001144 linkname[PATH_MAX] = '\0';
1145 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001146 } else
1147 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001148}
1149
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001150static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1151 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001152{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001153 struct fuse *f = req_fuse_prepare(req);
1154 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001155 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001156 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001157
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001158 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001159 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001160 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001161 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001162 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001163 printf("MKNOD %s\n", path);
1164 fflush(stdout);
1165 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001166 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001167 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1168 struct fuse_file_info fi;
1169
1170 memset(&fi, 0, sizeof(fi));
1171 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001172 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001173 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001174 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001175 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001176 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001177 }
1178 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001179 struct fuse_intr_data d;
1180 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001181 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001182 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001183 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001184 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001185 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001186 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001187 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001188 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001189 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001190}
1191
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001192static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1193 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001194{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001195 struct fuse *f = req_fuse_prepare(req);
1196 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001197 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001198 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001199
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001200 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001201 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001202 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001203 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001204 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001205 printf("MKDIR %s\n", path);
1206 fflush(stdout);
1207 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001208 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001209 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001210 struct fuse_intr_data d;
1211 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001212 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001213 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001214 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001215 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001216 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001217 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001218 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001219 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001220 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001221}
1222
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001223static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001224{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001225 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001226 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001227 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001228
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001229 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001230 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001231 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001232 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001233 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001234 printf("UNLINK %s\n", path);
1235 fflush(stdout);
1236 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001237 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001238 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001239 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001240 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001241 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001242 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001243 if (!err)
1244 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001245 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001246 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001247 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001248 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001249 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001250 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001251}
1252
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001253static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001254{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001255 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001256 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001257 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001258
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001259 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001260 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001261 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001262 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001263 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001264 printf("RMDIR %s\n", path);
1265 fflush(stdout);
1266 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001267 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001268 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001269 struct fuse_intr_data d;
1270 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001271 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001272 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001273 if (!err)
1274 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001275 }
1276 free(path);
1277 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001278 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001279 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001280}
1281
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001282static void fuse_symlink(fuse_req_t req, const char *linkname,
1283 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001284{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001285 struct fuse *f = req_fuse_prepare(req);
1286 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001287 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001288 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001289
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001290 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001291 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001292 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001293 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001294 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001295 printf("SYMLINK %s\n", path);
1296 fflush(stdout);
1297 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001298 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001299 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001300 struct fuse_intr_data d;
1301 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001302 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001303 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001304 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001305 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001306 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001307 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001308 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001309 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001310 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001311}
1312
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001313static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1314 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001315{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001316 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001317 char *oldpath;
1318 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001319 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001320
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001321 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001322 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001323 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001324 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001325 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001326 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001327 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001328 printf("RENAME %s -> %s\n", oldpath, newpath);
1329 fflush(stdout);
1330 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001331 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001332 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001333 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001334 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001335 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001336 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001337 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001338 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001339 if (!err)
1340 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001341 }
1342 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001343 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001344 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001345 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001346 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001347 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001348 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001349}
1350
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001351static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1352 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001353{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001354 struct fuse *f = req_fuse_prepare(req);
1355 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001356 char *oldpath;
1357 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001358 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001359
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001360 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001361 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001362 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001363 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001364 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001365 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001366 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001367 printf("LINK %s\n", newpath);
1368 fflush(stdout);
1369 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001370 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001371 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001372 struct fuse_intr_data d;
1373 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001374 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001375 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001376 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001377 err = lookup_path(f, req, newparent, newname, newpath, &e,
1378 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001379 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001380 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001381 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001382 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001383 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001384 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001385 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001386}
1387
Miklos Szeredid9079a72005-10-26 15:29:06 +00001388static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1389 mode_t mode, struct fuse_file_info *fi)
1390{
1391 struct fuse *f = req_fuse_prepare(req);
1392 struct fuse_entry_param e;
1393 char *path;
1394 int err;
1395
1396 err = -ENOENT;
1397 pthread_rwlock_rdlock(&f->tree_lock);
1398 path = get_path_name(f, parent, name);
1399 if (path != NULL) {
1400 err = -ENOSYS;
1401 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001402 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001403 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001404 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001405 printf("CREATE[%llu] flags: 0x%x %s\n",
1406 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001407 fflush(stdout);
1408 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001409 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001410 if (err) {
1411 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001412 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001413 } else if (!S_ISREG(e.attr.st_mode)) {
1414 err = -EIO;
1415 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001416 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001417 forget_node(f, e.ino, 1);
1418 }
1419 }
1420 }
1421 }
1422
1423 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001424 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001425 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001426 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001427 fi->keep_cache = 1;
1428
1429 pthread_mutex_lock(&f->lock);
1430 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1431 /* The open syscall was interrupted, so it must be cancelled */
1432 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001433 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001434 forget_node(f, e.ino, 1);
1435 } else {
1436 struct node *node = get_node(f, e.ino);
1437 node->open_count ++;
1438 }
1439 pthread_mutex_unlock(&f->lock);
1440 } else
1441 reply_err(req, err);
1442
1443 if (path)
1444 free(path);
1445 pthread_rwlock_unlock(&f->tree_lock);
1446}
1447
Miklos Szeredi320abe42006-01-30 18:14:51 +00001448static double diff_timespec(const struct timespec *t1,
1449 const struct timespec *t2)
1450{
1451 return (t1->tv_sec - t2->tv_sec) +
1452 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1453}
1454
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001455static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1456 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001457{
1458 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001459 if (node->cache_valid) {
1460 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001461
Miklos Szeredi08dab162006-02-01 13:39:15 +00001462 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001463 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001464 struct stat stbuf;
1465 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001466
Miklos Szeredi08dab162006-02-01 13:39:15 +00001467 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001468 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001469 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001470 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001471
1472 if (!err)
1473 update_stat(node, &stbuf);
1474 else
1475 node->cache_valid = 0;
1476 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001477 }
1478 if (node->cache_valid)
1479 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001480
1481 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001482}
1483
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001484static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1485 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001486{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001487 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001488 char *path = NULL;
1489 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001490
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001491 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001492 if (f->op.open) {
1493 err = -ENOENT;
1494 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001495 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001496 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001497 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001498 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001499 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001500 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1501 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001502 fflush(stdout);
1503 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001504
Miklos Szeredi659743b2005-12-09 17:41:42 +00001505 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001506 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001507 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001508 fi->keep_cache = 1;
1509
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001510 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001511 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001512 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001513
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001514 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001515 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001516 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001517 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001518 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001519 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001520 node->open_count ++;
1521 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001522 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001523 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001524 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001525
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001526 if (path)
1527 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001528 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001529}
1530
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001531static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1532 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001533{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001534 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001535 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001536 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001537 int res;
1538
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001539 buf = (char *) malloc(size);
1540 if (buf == NULL) {
1541 reply_err(req, -ENOMEM);
1542 return;
1543 }
1544
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001545 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001546 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001547 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001548 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001549 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001550 printf("READ[%llu] %lu bytes from %llu\n",
1551 (unsigned long long) fi->fh, (unsigned long) size,
1552 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001553 fflush(stdout);
1554 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001555
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001556 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001557 if (f->op.read) {
1558 struct fuse_intr_data d;
1559 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001560 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001561 fuse_finish_interrupt(f, req, &d);
1562 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001563 free(path);
1564 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001565 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001566
1567 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001568 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001569 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1570 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001571 fflush(stdout);
1572 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001573 if ((size_t) res > size)
1574 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001575 fuse_reply_buf(req, buf, res);
1576 } else
1577 reply_err(req, res);
1578
1579 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001580}
1581
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001582static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1583 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001584{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001585 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001586 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001587 int res;
1588
1589 res = -ENOENT;
1590 pthread_rwlock_rdlock(&f->tree_lock);
1591 path = get_path(f, ino);
1592 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001593 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001594 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001595 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001596 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 fflush(stdout);
1598 }
1599
1600 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001601 if (f->op.write) {
1602 struct fuse_intr_data d;
1603 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001604 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001605 fuse_finish_interrupt(f, req, &d);
1606 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001607 free(path);
1608 }
1609 pthread_rwlock_unlock(&f->tree_lock);
1610
Miklos Szeredif412d072005-10-14 21:24:32 +00001611 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001612 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001613 printf(" WRITE%s[%llu] %u bytes\n",
1614 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1615 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001616 fflush(stdout);
1617 }
1618 if ((size_t) res > size)
1619 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001620 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001621 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001622 reply_err(req, res);
1623}
1624
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001625static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1626 struct fuse_file_info *fi)
1627{
1628 struct fuse *f = req_fuse_prepare(req);
1629 char *path;
1630 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001631 int unlink_hidden = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001632
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001633 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001634 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001635 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001636 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1637 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001638 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001639 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001640 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001641 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001642
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001643 pthread_mutex_lock(&f->lock);
1644 node = get_node(f, ino);
1645 assert(node->open_count > 0);
1646 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001647 if (node->is_hidden && !node->open_count) {
1648 unlink_hidden = 1;
1649 node->is_hidden = 0;
1650 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001651 pthread_mutex_unlock(&f->lock);
1652
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001653 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001654 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001655
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001656 if (path)
1657 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001658 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001659
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001660 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001661}
1662
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001663static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1664 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001665{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001666 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001667 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001668 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001669
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001670 err = -ENOENT;
1671 pthread_rwlock_rdlock(&f->tree_lock);
1672 path = get_path(f, ino);
1673 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001674 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001675 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001676 fflush(stdout);
1677 }
1678 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001679 if (f->op.fsync) {
1680 struct fuse_intr_data d;
1681 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001682 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001683 fuse_finish_interrupt(f, req, &d);
1684 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001685 free(path);
1686 }
1687 pthread_rwlock_unlock(&f->tree_lock);
1688 reply_err(req, err);
1689}
1690
1691static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1692 struct fuse_file_info *fi)
1693{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001694 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001695 memset(fi, 0, sizeof(struct fuse_file_info));
1696 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001697 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001698 return dh;
1699}
1700
1701static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1702 struct fuse_file_info *llfi)
1703{
1704 struct fuse *f = req_fuse_prepare(req);
1705 struct fuse_dirhandle *dh;
1706
1707 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1708 if (dh == NULL) {
1709 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001710 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001711 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001712 memset(dh, 0, sizeof(struct fuse_dirhandle));
1713 dh->fuse = f;
1714 dh->contents = NULL;
1715 dh->len = 0;
1716 dh->filled = 0;
1717 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001718 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001719
Miklos Szeredi3a770472005-11-11 21:32:42 +00001720 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001721
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001722 if (f->op.opendir) {
1723 struct fuse_file_info fi;
1724 char *path;
1725 int err;
1726
1727 memset(&fi, 0, sizeof(fi));
1728 fi.flags = llfi->flags;
1729
1730 err = -ENOENT;
1731 pthread_rwlock_rdlock(&f->tree_lock);
1732 path = get_path(f, ino);
1733 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001734 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001735 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001736 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001737 if (!err) {
1738 pthread_mutex_lock(&f->lock);
1739 if (fuse_reply_open(req, llfi) == -ENOENT) {
1740 /* The opendir syscall was interrupted, so it must be
1741 cancelled */
1742 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001743 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001744 pthread_mutex_destroy(&dh->lock);
1745 free(dh);
1746 }
1747 pthread_mutex_unlock(&f->lock);
1748 } else {
1749 reply_err(req, err);
1750 free(dh);
1751 }
Miklos Szerediab974562005-04-07 15:40:21 +00001752 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001753 pthread_rwlock_unlock(&f->tree_lock);
1754 } else
1755 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001756}
Miklos Szeredib483c932001-10-29 14:57:57 +00001757
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001758static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1759{
1760 if (minsize > dh->size) {
1761 char *newptr;
1762 unsigned newsize = dh->size;
1763 if (!newsize)
1764 newsize = 1024;
1765 while (newsize < minsize)
1766 newsize *= 2;
1767
1768 newptr = (char *) realloc(dh->contents, newsize);
1769 if (!newptr) {
1770 dh->error = -ENOMEM;
1771 return -1;
1772 }
1773 dh->contents = newptr;
1774 dh->size = newsize;
1775 }
1776 return 0;
1777}
1778
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001779static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001780 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001781{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001782 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001783 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001784
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001785 if (statp)
1786 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001787 else {
1788 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001789 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001790 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001791
Miklos Szeredi659743b2005-12-09 17:41:42 +00001792 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001793 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001794 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001795 struct node *node;
1796 pthread_mutex_lock(&dh->fuse->lock);
1797 node = lookup_node(dh->fuse, dh->nodeid, name);
1798 if (node)
1799 stbuf.st_ino = (ino_t) node->nodeid;
1800 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001801 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001802 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001803
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001804 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001805 if (extend_contents(dh, dh->needlen) == -1)
1806 return 1;
1807
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001808 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001809 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1810 dh->needlen - dh->len, name,
1811 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001812 if (newlen > dh->needlen)
1813 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001814 } else {
1815 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1816 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001817 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001818
1819 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1820 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001821 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001822 dh->len = newlen;
1823 return 0;
1824}
1825
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001826static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001827 off_t off)
1828{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001829 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001830}
1831
1832static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1833 ino_t ino)
1834{
1835 struct stat stbuf;
1836
1837 memset(&stbuf, 0, sizeof(stbuf));
1838 stbuf.st_mode = type << 12;
1839 stbuf.st_ino = ino;
1840
1841 fill_dir_common(dh, name, &stbuf, 0);
1842 return dh->error;
1843}
1844
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001845static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1846 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001847 struct fuse_file_info *fi)
1848{
1849 int err = -ENOENT;
1850 char *path;
1851 pthread_rwlock_rdlock(&f->tree_lock);
1852 path = get_path(f, ino);
1853 if (path != NULL) {
1854 dh->len = 0;
1855 dh->error = 0;
1856 dh->needlen = size;
1857 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001858 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001859 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001860 if (f->op.readdir) {
1861 struct fuse_intr_data d;
1862 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001863 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001864 fuse_finish_interrupt(f, req, &d);
1865 } else if (f->op.getdir) {
1866 struct fuse_intr_data d;
1867 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001868 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001869 fuse_finish_interrupt(f, req, &d);
1870 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001871 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001872 if (!err)
1873 err = dh->error;
1874 if (err)
1875 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001876 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001877 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001878 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001879 return err;
1880}
Miklos Szeredie5183742005-02-02 11:14:04 +00001881
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001882static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1883 off_t off, struct fuse_file_info *llfi)
1884{
1885 struct fuse *f = req_fuse_prepare(req);
1886 struct fuse_file_info fi;
1887 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1888
1889 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001890 /* According to SUS, directory contents need to be refreshed on
1891 rewinddir() */
1892 if (!off)
1893 dh->filled = 0;
1894
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001896 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001897 if (err) {
1898 reply_err(req, err);
1899 goto out;
1900 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001901 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001902 if (dh->filled) {
1903 if (off < dh->len) {
1904 if (off + size > dh->len)
1905 size = dh->len - off;
1906 } else
1907 size = 0;
1908 } else {
1909 size = dh->len;
1910 off = 0;
1911 }
1912 fuse_reply_buf(req, dh->contents + off, size);
1913 out:
1914 pthread_mutex_unlock(&dh->lock);
1915}
Miklos Szeredia181e612001-11-06 12:03:23 +00001916
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001917static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1918 struct fuse_file_info *llfi)
1919{
1920 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001921 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001922 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1923 if (f->op.releasedir) {
1924 char *path;
1925
1926 pthread_rwlock_rdlock(&f->tree_lock);
1927 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001928 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001929 free(path);
1930 pthread_rwlock_unlock(&f->tree_lock);
1931 }
1932 pthread_mutex_lock(&dh->lock);
1933 pthread_mutex_unlock(&dh->lock);
1934 pthread_mutex_destroy(&dh->lock);
1935 free(dh->contents);
1936 free(dh);
1937 reply_err(req, 0);
1938}
1939
1940static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1941 struct fuse_file_info *llfi)
1942{
1943 struct fuse *f = req_fuse_prepare(req);
1944 struct fuse_file_info fi;
1945 char *path;
1946 int err;
1947
1948 get_dirhandle(llfi, &fi);
1949
1950 err = -ENOENT;
1951 pthread_rwlock_rdlock(&f->tree_lock);
1952 path = get_path(f, ino);
1953 if (path != NULL) {
1954 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001955 if (f->op.fsyncdir) {
1956 struct fuse_intr_data d;
1957 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001958 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001959 fuse_finish_interrupt(f, req, &d);
1960 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001961 free(path);
1962 }
1963 pthread_rwlock_unlock(&f->tree_lock);
1964 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001965}
1966
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001967static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001968{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001969 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001970 buf->f_bsize = 512;
1971 return 0;
1972}
1973
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001974static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001975{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001976 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001977 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001978 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001979
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001980 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001981 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001982 if (ino && (!f->compat || f->compat >= 26)) {
1983 char *path;
1984 pthread_rwlock_rdlock(&f->tree_lock);
1985 err = -ENOENT;
1986 path = get_path(f, ino);
1987 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001988 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001989 free(path);
1990 }
1991 pthread_rwlock_unlock(&f->tree_lock);
1992 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001993 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001994 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001995 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001996
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001997 if (!err)
1998 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001999 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002000 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002001}
2002
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002003static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2004 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002005{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002006 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002007 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002008 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002009
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002010 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002011 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002012 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002013 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002014 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002015 if (f->op.setxattr) {
2016 struct fuse_intr_data d;
2017 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002018 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002019 fuse_finish_interrupt(f, req, &d);
2020 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002021 free(path);
2022 }
2023 pthread_rwlock_unlock(&f->tree_lock);
2024 reply_err(req, err);
2025}
2026
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002027static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2028 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002029{
2030 int err;
2031 char *path;
2032
2033 err = -ENOENT;
2034 pthread_rwlock_rdlock(&f->tree_lock);
2035 path = get_path(f, ino);
2036 if (path != NULL) {
2037 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002038 if (f->op.getxattr) {
2039 struct fuse_intr_data d;
2040 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002041 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002042 fuse_finish_interrupt(f, req, &d);
2043 }
Miklos Szerediab974562005-04-07 15:40:21 +00002044 free(path);
2045 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002046 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002047 return err;
2048}
2049
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002050static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2051 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002052{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002053 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002054 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002055
2056 if (size) {
2057 char *value = (char *) malloc(size);
2058 if (value == NULL) {
2059 reply_err(req, -ENOMEM);
2060 return;
2061 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002062 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002063 if (res > 0)
2064 fuse_reply_buf(req, value, res);
2065 else
2066 reply_err(req, res);
2067 free(value);
2068 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002069 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002070 if (res >= 0)
2071 fuse_reply_xattr(req, res);
2072 else
2073 reply_err(req, res);
2074 }
2075}
2076
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002077static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2078 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002079{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002080 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002081 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002082
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002083 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002084 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002085 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002086 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002087 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002088 if (f->op.listxattr) {
2089 struct fuse_intr_data d;
2090 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002091 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002092 fuse_finish_interrupt(f, req, &d);
2093 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002094 free(path);
2095 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002096 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002097 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002098}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002099
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002100static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002101{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002102 struct fuse *f = req_fuse_prepare(req);
2103 int res;
2104
2105 if (size) {
2106 char *list = (char *) malloc(size);
2107 if (list == NULL) {
2108 reply_err(req, -ENOMEM);
2109 return;
2110 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002111 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002112 if (res > 0)
2113 fuse_reply_buf(req, list, res);
2114 else
2115 reply_err(req, res);
2116 free(list);
2117 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002118 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002119 if (res >= 0)
2120 fuse_reply_xattr(req, res);
2121 else
2122 reply_err(req, res);
2123 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002124}
2125
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002126static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2127{
2128 struct fuse *f = req_fuse_prepare(req);
2129 char *path;
2130 int err;
2131
2132 err = -ENOENT;
2133 pthread_rwlock_rdlock(&f->tree_lock);
2134 path = get_path(f, ino);
2135 if (path != NULL) {
2136 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002137 if (f->op.removexattr) {
2138 struct fuse_intr_data d;
2139 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002140 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002141 fuse_finish_interrupt(f, req, &d);
2142 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002143 free(path);
2144 }
2145 pthread_rwlock_unlock(&f->tree_lock);
2146 reply_err(req, err);
2147}
2148
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002149static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2150{
2151 struct lock *l;
2152
2153 for (l = node->locks; l; l = l->next)
2154 if (l->owner != lock->owner &&
2155 lock->start <= l->end && l->start <= lock->end &&
2156 (l->type == F_WRLCK || lock->type == F_WRLCK))
2157 break;
2158
2159 return l;
2160}
2161
2162static void delete_lock(struct lock **lockp)
2163{
2164 struct lock *l = *lockp;
2165 *lockp = l->next;
2166 free(l);
2167}
2168
2169static void insert_lock(struct lock **pos, struct lock *lock)
2170{
2171 lock->next = *pos;
2172 *pos = lock;
2173}
2174
2175static int locks_insert(struct node *node, struct lock *lock)
2176{
2177 struct lock **lp;
2178 struct lock *newl1 = NULL;
2179 struct lock *newl2 = NULL;
2180
2181 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2182 newl1 = malloc(sizeof(struct lock));
2183 newl2 = malloc(sizeof(struct lock));
2184
2185 if (!newl1 || !newl2) {
2186 free(newl1);
2187 free(newl2);
2188 return -ENOLCK;
2189 }
2190 }
2191
2192 for (lp = &node->locks; *lp;) {
2193 struct lock *l = *lp;
2194 if (l->owner != lock->owner)
2195 goto skip;
2196
2197 if (lock->type == l->type) {
2198 if (l->end < lock->start - 1)
2199 goto skip;
2200 if (lock->end < l->start - 1)
2201 break;
2202 if (l->start <= lock->start && lock->end <= l->end)
2203 goto out;
2204 if (l->start < lock->start)
2205 lock->start = l->start;
2206 if (lock->end < l->end)
2207 lock->end = l->end;
2208 goto delete;
2209 } else {
2210 if (l->end < lock->start)
2211 goto skip;
2212 if (lock->end < l->start)
2213 break;
2214 if (lock->start <= l->start && l->end <= lock->end)
2215 goto delete;
2216 if (l->end <= lock->end) {
2217 l->end = lock->start - 1;
2218 goto skip;
2219 }
2220 if (lock->start <= l->start) {
2221 l->start = lock->end + 1;
2222 break;
2223 }
2224 *newl2 = *l;
2225 newl2->start = lock->end + 1;
2226 l->end = lock->start - 1;
2227 insert_lock(&l->next, newl2);
2228 newl2 = NULL;
2229 }
2230 skip:
2231 lp = &l->next;
2232 continue;
2233
2234 delete:
2235 delete_lock(lp);
2236 }
2237 if (lock->type != F_UNLCK) {
2238 *newl1 = *lock;
2239 insert_lock(lp, newl1);
2240 newl1 = NULL;
2241 }
2242out:
2243 free(newl1);
2244 free(newl2);
2245 return 0;
2246}
2247
2248static void flock_to_lock(struct flock *flock, struct lock *lock)
2249{
2250 memset(lock, 0, sizeof(struct lock));
2251 lock->type = flock->l_type;
2252 lock->start = flock->l_start;
2253 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2254 lock->pid = flock->l_pid;
2255}
2256
2257static void lock_to_flock(struct lock *lock, struct flock *flock)
2258{
2259 flock->l_type = lock->type;
2260 flock->l_start = lock->start;
2261 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2262 flock->l_pid = lock->pid;
2263}
2264
2265static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
2266 struct fuse_file_info *fi, uint64_t owner)
2267{
2268 struct fuse *f = req_fuse_prepare(req);
2269 char *path;
2270 int err;
2271
2272 err = -ENOENT;
2273 pthread_rwlock_rdlock(&f->tree_lock);
2274 path = get_path(f, ino);
2275 if (path != NULL) {
2276 if (f->conf.debug) {
2277 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2278 fflush(stdout);
2279 }
2280 err = -ENOSYS;
2281 if (f->op.flush) {
2282 struct fuse_intr_data d;
2283 fuse_prepare_interrupt(f, req, &d);
2284 err = f->op.flush(path, fi);
2285 fuse_finish_interrupt(f, req, &d);
2286 }
2287 free(path);
2288 }
2289 if (f->op.lock) {
2290 struct flock lock;
2291 struct lock l;
2292 memset(&lock, 0, sizeof(lock));
2293 lock.l_type = F_UNLCK;
2294 lock.l_whence = SEEK_SET;
2295 fuse_do_lock(f, req, path, fi, F_SETLK, &lock, owner);
2296 flock_to_lock(&lock, &l);
2297 l.owner = owner;
2298 pthread_mutex_lock(&f->lock);
2299 locks_insert(get_node(f, ino), &l);
2300 pthread_mutex_unlock(&f->lock);
2301
2302 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2303 if (err == -ENOSYS)
2304 err = 0;
2305 }
2306 pthread_rwlock_unlock(&f->tree_lock);
2307 reply_err(req, err);
2308}
2309
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002310static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2311 struct fuse_file_info *fi, struct flock *lock,
2312 uint64_t owner, int cmd)
2313{
2314 struct fuse *f = req_fuse_prepare(req);
2315 char *path;
2316 int err;
2317
2318 err = -ENOENT;
2319 pthread_rwlock_rdlock(&f->tree_lock);
2320 path = get_path(f, ino);
2321 if (path != NULL) {
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002322 err = fuse_do_lock(f, req, path, fi, cmd, lock, owner);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002323 free(path);
2324 }
2325 pthread_rwlock_unlock(&f->tree_lock);
2326 return err;
2327}
2328
2329static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
2330 struct fuse_file_info *fi, struct flock *lock,
2331 uint64_t owner)
2332{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002333 int err;
2334 struct lock l;
2335 struct lock *conflict;
2336 struct fuse *f = req_fuse(req);
2337
2338 flock_to_lock(lock, &l);
2339 l.owner = owner;
2340 pthread_mutex_lock(&f->lock);
2341 conflict = locks_conflict(get_node(f, ino), &l);
2342 if (conflict)
2343 lock_to_flock(conflict, lock);
2344 pthread_mutex_unlock(&f->lock);
2345 if (!conflict)
2346 err = fuse_lock_common(req, ino, fi, lock, owner, F_GETLK);
2347 else
2348 err = 0;
2349
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002350 if (!err)
2351 fuse_reply_lock(req, lock);
2352 else
2353 reply_err(req, err);
2354}
2355
2356static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2357 struct fuse_file_info *fi, struct flock *lock,
2358 uint64_t owner, int sleep)
2359{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002360 int err = fuse_lock_common(req, ino, fi, lock, owner,
2361 sleep ? F_SETLKW : F_SETLK);
2362 if (!err) {
2363 struct fuse *f = req_fuse(req);
2364 struct lock l;
2365 flock_to_lock(lock, &l);
2366 l.owner = owner;
2367 pthread_mutex_lock(&f->lock);
2368 locks_insert(get_node(f, ino), &l);
2369 pthread_mutex_unlock(&f->lock);
2370 }
2371 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002372}
2373
Miklos Szeredia1482422005-08-14 23:00:27 +00002374static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002375 .init = fuse_data_init,
2376 .destroy = fuse_data_destroy,
2377 .lookup = fuse_lookup,
2378 .forget = fuse_forget,
2379 .getattr = fuse_getattr,
2380 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002381 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002382 .readlink = fuse_readlink,
2383 .mknod = fuse_mknod,
2384 .mkdir = fuse_mkdir,
2385 .unlink = fuse_unlink,
2386 .rmdir = fuse_rmdir,
2387 .symlink = fuse_symlink,
2388 .rename = fuse_rename,
2389 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002390 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002391 .open = fuse_open,
2392 .read = fuse_read,
2393 .write = fuse_write,
2394 .flush = fuse_flush,
2395 .release = fuse_release,
2396 .fsync = fuse_fsync,
2397 .opendir = fuse_opendir,
2398 .readdir = fuse_readdir,
2399 .releasedir = fuse_releasedir,
2400 .fsyncdir = fuse_fsyncdir,
2401 .statfs = fuse_statfs,
2402 .setxattr = fuse_setxattr,
2403 .getxattr = fuse_getxattr,
2404 .listxattr = fuse_listxattr,
2405 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002406 .getlk = fuse_getlk,
2407 .setlk = fuse_setlk,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002408};
2409
Miklos Szeredia1482422005-08-14 23:00:27 +00002410static void free_cmd(struct fuse_cmd *cmd)
2411{
2412 free(cmd->buf);
2413 free(cmd);
2414}
2415
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002416void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002417{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002418 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002419 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002420}
2421
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002422int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002423{
Miklos Szeredia1482422005-08-14 23:00:27 +00002424 return fuse_session_exited(f->se);
2425}
2426
2427struct fuse_session *fuse_get_session(struct fuse *f)
2428{
2429 return f->se;
2430}
2431
2432static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2433{
2434 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2435 if (cmd == NULL) {
2436 fprintf(stderr, "fuse: failed to allocate cmd\n");
2437 return NULL;
2438 }
2439 cmd->buf = (char *) malloc(bufsize);
2440 if (cmd->buf == NULL) {
2441 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2442 free(cmd);
2443 return NULL;
2444 }
2445 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002446}
2447
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002448struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002449{
Miklos Szeredia1482422005-08-14 23:00:27 +00002450 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2451 size_t bufsize = fuse_chan_bufsize(ch);
2452 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2453 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002454 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002455 if (res <= 0) {
2456 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002457 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002458 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002459 return NULL;
2460 }
2461 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002462 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002463 }
2464 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002465}
2466
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002467int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002468{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002469 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002470 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002471 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002472 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002473}
2474
Miklos Szeredi891b8742004-07-29 09:27:49 +00002475int fuse_invalidate(struct fuse *f, const char *path)
2476{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002477 (void) f;
2478 (void) path;
2479 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002480}
2481
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002482void fuse_exit(struct fuse *f)
2483{
Miklos Szeredia1482422005-08-14 23:00:27 +00002484 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002485}
2486
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002487struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002488{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002489 return &fuse_get_context_internal()->ctx;
2490}
2491
2492int fuse_interrupted(void)
2493{
2494 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002495}
2496
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002497void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002498{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002499 (void) func;
2500 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002501}
2502
Miklos Szerediad005972006-01-07 10:14:34 +00002503enum {
2504 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002505};
2506
Miklos Szeredi659743b2005-12-09 17:41:42 +00002507#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2508
2509static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002510 FUSE_OPT_KEY("-h", KEY_HELP),
2511 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002512 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2513 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002514 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002515 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002516 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2517 FUSE_LIB_OPT("use_ino", use_ino, 1),
2518 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2519 FUSE_LIB_OPT("direct_io", direct_io, 1),
2520 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002521 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2522 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002523 FUSE_LIB_OPT("umask=", set_mode, 1),
2524 FUSE_LIB_OPT("umask=%o", umask, 0),
2525 FUSE_LIB_OPT("uid=", set_uid, 1),
2526 FUSE_LIB_OPT("uid=%d", uid, 0),
2527 FUSE_LIB_OPT("gid=", set_gid, 1),
2528 FUSE_LIB_OPT("gid=%d", gid, 0),
2529 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2530 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002531 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2532 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002533 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002534 FUSE_LIB_OPT("intr", intr, 1),
2535 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002536 FUSE_OPT_END
2537};
2538
Miklos Szerediad005972006-01-07 10:14:34 +00002539static void fuse_lib_help(void)
2540{
2541 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002542" -o hard_remove immediate removal (don't hide files)\n"
2543" -o use_ino let filesystem set inode numbers\n"
2544" -o readdir_ino try to fill in d_ino in readdir\n"
2545" -o direct_io use direct I/O\n"
2546" -o kernel_cache cache files in kernel\n"
2547" -o [no]auto_cache enable caching based on modification times\n"
2548" -o umask=M set file permissions (octal)\n"
2549" -o uid=N set file owner\n"
2550" -o gid=N set file group\n"
2551" -o entry_timeout=T cache timeout for names (1.0s)\n"
2552" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002553" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2554" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002555" -o intr allow requests to be interrupted\n"
2556" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2557"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002558}
2559
2560static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2561 struct fuse_args *outargs)
2562{
2563 (void) data; (void) arg; (void) outargs;
2564
2565 if (key == KEY_HELP)
2566 fuse_lib_help();
2567
2568 return 1;
2569}
2570
2571
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002572int fuse_is_lib_option(const char *opt)
2573{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002574 return fuse_lowlevel_is_lib_option(opt) ||
2575 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002576}
2577
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002578static int fuse_init_intr_signal(int signum, int *installed)
2579{
2580 struct sigaction old_sa;
2581
2582 if (sigaction(signum, NULL, &old_sa) == -1) {
2583 perror("fuse: cannot get old signal handler");
2584 return -1;
2585 }
2586
2587 if (old_sa.sa_handler == SIG_DFL) {
2588 struct sigaction sa;
2589
2590 memset(&sa, 0, sizeof(struct sigaction));
2591 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002592 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002593
2594 if (sigaction(signum, &sa, NULL) == -1) {
2595 perror("fuse: cannot set interrupt signal handler");
2596 return -1;
2597 }
2598 *installed = 1;
2599 }
2600 return 0;
2601}
2602
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002603static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002604{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002605 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002606
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002607 memset(&sa, 0, sizeof(struct sigaction));
2608 sa.sa_handler = SIG_DFL;
2609 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002610}
2611
Miklos Szeredi6f385412006-03-17 15:05:40 +00002612struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002613 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002614 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002615{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002616 struct fuse *f;
2617 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002618 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002619
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002620 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002621 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002622 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002623 }
2624
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002625 if (fuse_create_context_key() == -1)
2626 goto out;
2627
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002628 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002629 if (f == NULL) {
2630 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002631 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002632 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002633
Miklos Szeredi6f385412006-03-17 15:05:40 +00002634 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002635 f->conf.entry_timeout = 1.0;
2636 f->conf.attr_timeout = 1.0;
2637 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002638 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002639
Miklos Szerediad005972006-01-07 10:14:34 +00002640 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002641 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002642
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002643 if (!f->conf.ac_attr_timeout_set)
2644 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2645
Miklos Szeredi659743b2005-12-09 17:41:42 +00002646#ifdef __FreeBSD__
2647 /*
2648 * In FreeBSD, we always use these settings as inode numbers are needed to
2649 * make getcwd(3) work.
2650 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002651 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002652#endif
2653
Miklos Szeredi065f2222006-01-20 15:15:21 +00002654 if (compat && compat <= 25) {
2655 if (fuse_sync_compat_args(args) == -1)
2656 goto out_free;
2657 }
2658
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002659 memcpy(&f->op, op, op_size);
2660 if (!f->op.lock) {
2661 llop.getlk = NULL;
2662 llop.setlk = NULL;
2663 }
2664
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002665 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002666 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002667 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002668
Miklos Szeredia1482422005-08-14 23:00:27 +00002669 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002670
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002671 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002672 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002673 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002674 f->name_table_size = 14057;
2675 f->name_table = (struct node **)
2676 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002677 if (f->name_table == NULL) {
2678 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002679 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002680 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002681
Miklos Szeredia13d9002004-11-02 17:32:03 +00002682 f->id_table_size = 14057;
2683 f->id_table = (struct node **)
2684 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002685 if (f->id_table == NULL) {
2686 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002687 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002688 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002689
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002690 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002691 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002692 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002693
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002694 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002695 if (root == NULL) {
2696 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002697 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002698 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002699
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002700 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002701 if (root->name == NULL) {
2702 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002703 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002704 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002705
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002706 if (f->conf.intr &&
2707 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2708 goto out_free_root_name;
2709
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002710 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002711 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002712 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002713 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002714 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002715 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002716
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002717 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002718
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002719 out_free_root_name:
2720 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002721 out_free_root:
2722 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002723 out_free_id_table:
2724 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002725 out_free_name_table:
2726 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002727 out_free_session:
2728 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002729 out_free:
2730 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002731 out_delete_context_key:
2732 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002733 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002734 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002735}
2736
Miklos Szeredi6f385412006-03-17 15:05:40 +00002737struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2738 const struct fuse_operations *op, size_t op_size,
2739 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002740{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002741 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002742}
2743
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002744void fuse_destroy(struct fuse *f)
2745{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002746 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002747 struct fuse_context_i *c = fuse_get_context_internal();
2748
2749 if (f->conf.intr && f->intr_installed)
2750 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002751
2752 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002753 c->ctx.fuse = f;
2754 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002755
Miklos Szeredia13d9002004-11-02 17:32:03 +00002756 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002757 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002758
Miklos Szeredia13d9002004-11-02 17:32:03 +00002759 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002760 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002761 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002762 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002763 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002764 free(path);
2765 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002766 }
2767 }
2768 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002769 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002770 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002771 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002772
Miklos Szeredia13d9002004-11-02 17:32:03 +00002773 for (node = f->id_table[i]; node != NULL; node = next) {
2774 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002775 free_node(node);
2776 }
2777 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002778 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002779 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002780 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002781 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002782 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002783 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002784 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002785}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002786
Miklos Szeredieafdf422006-09-22 19:30:17 +00002787#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002788#include "fuse_compat.h"
2789
Miklos Szeredi6f385412006-03-17 15:05:40 +00002790static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2791 const struct fuse_operations *op,
2792 size_t op_size, int compat)
2793{
2794 struct fuse *f = NULL;
2795 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2796
2797 if (ch)
2798 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2799
2800 return f;
2801}
2802
Miklos Szeredi065f2222006-01-20 15:15:21 +00002803#ifndef __FreeBSD__
2804
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002805static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2806 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002807{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002808 int err;
2809 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002810 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002811 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002812 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002813 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002814 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002815 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002816 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002817 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002818 memcpy(fi, &tmp, sizeof(tmp));
2819 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002820 } else {
2821 fuse_prepare_interrupt(f, req, &d);
2822 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002823 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002824 fuse_finish_interrupt(f, req, &d);
2825 }
2826 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002827}
2828
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002829static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2830 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002831{
2832 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002833 fuse_do_release(f, req, path ? path : "-", fi);
2834 else if (path) {
2835 struct fuse_intr_data d;
2836 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002837 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002838 fuse_finish_interrupt(f, req, &d);
2839 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002840}
2841
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002842static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2843 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002844{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002845 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002846 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002847 } else {
2848 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002849 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002850 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002851 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002852 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002853 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002854 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002855 memcpy(fi, &tmp, sizeof(tmp));
2856 fi->fh = tmp.fh;
2857 return err;
2858 }
2859}
2860
2861static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2862 struct statvfs *stbuf)
2863{
2864 stbuf->f_bsize = compatbuf->block_size;
2865 stbuf->f_blocks = compatbuf->blocks;
2866 stbuf->f_bfree = compatbuf->blocks_free;
2867 stbuf->f_bavail = compatbuf->blocks_free;
2868 stbuf->f_files = compatbuf->files;
2869 stbuf->f_ffree = compatbuf->files_free;
2870 stbuf->f_namemax = compatbuf->namelen;
2871}
2872
2873static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2874{
2875 stbuf->f_bsize = oldbuf->f_bsize;
2876 stbuf->f_blocks = oldbuf->f_blocks;
2877 stbuf->f_bfree = oldbuf->f_bfree;
2878 stbuf->f_bavail = oldbuf->f_bavail;
2879 stbuf->f_files = oldbuf->f_files;
2880 stbuf->f_ffree = oldbuf->f_ffree;
2881 stbuf->f_namemax = oldbuf->f_namelen;
2882}
2883
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002884static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2885 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002886{
2887 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002888 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002889
Miklos Szeredi065f2222006-01-20 15:15:21 +00002890 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002891 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002892 } else if (f->compat > 11) {
2893 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002894 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002895 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002896 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002897 if (!err)
2898 convert_statfs_old(&oldbuf, buf);
2899 } else {
2900 struct fuse_statfs_compat1 compatbuf;
2901 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002902 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002903 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002904 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002905 if (!err)
2906 convert_statfs_compat(&compatbuf, buf);
2907 }
2908 return err;
2909}
2910
Miklos Szeredi95da8602006-01-06 18:29:40 +00002911static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2912 const struct fuse_operations *op,
2913 size_t op_size, int compat)
2914{
2915 struct fuse *f;
2916 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2917
2918 if (opts &&
2919 (fuse_opt_add_arg(&args, "") == -1 ||
2920 fuse_opt_add_arg(&args, "-o") == -1 ||
2921 fuse_opt_add_arg(&args, opts) == -1)) {
2922 fuse_opt_free_args(&args);
2923 return NULL;
2924 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002925 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002926 fuse_opt_free_args(&args);
2927
2928 return f;
2929}
2930
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002931struct fuse *fuse_new_compat22(int fd, const char *opts,
2932 const struct fuse_operations_compat22 *op,
2933 size_t op_size)
2934{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002935 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2936 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002937}
2938
2939struct fuse *fuse_new_compat2(int fd, const char *opts,
2940 const struct fuse_operations_compat2 *op)
2941{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002942 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2943 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002944}
2945
2946struct fuse *fuse_new_compat1(int fd, int flags,
2947 const struct fuse_operations_compat1 *op)
2948{
2949 const char *opts = NULL;
2950 if (flags & FUSE_DEBUG_COMPAT1)
2951 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002952 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2953 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002954}
2955
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002956__asm__(".symver fuse_exited,__fuse_exited@");
2957__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2958__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2959__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2960__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002961__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002962
2963#else /* __FreeBSD__ */
2964
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002965static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2966 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002967{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002968 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002969}
2970
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002971static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2972 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002973{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002974 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002975}
2976
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002977static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2978 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002979{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002980 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002981}
2982
Csaba Henk3e3a1252006-09-24 14:53:29 +00002983static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002984{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002985 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002986}
2987
2988#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00002989
2990struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
2991 const struct fuse_operations_compat25 *op,
2992 size_t op_size)
2993{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002994 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
2995 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00002996}
2997
2998__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");