blob: c87bff3b4e09c9c5f6738d81cb1e13a6580c6f08 [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
Miklos Szeredi4fca4322006-10-01 14:41:04 +0000586static int fuse_do_flush(struct fuse *f, fuse_req_t req, const char *path,
587 struct fuse_file_info *fi)
588{
589 int res;
590 struct fuse_intr_data d;
591 fuse_prepare_interrupt(f, req, &d);
592 res = f->op.flush(path, fi);
593 fuse_finish_interrupt(f, req, &d);
594 return res;
595}
596
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000597static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
598 struct statvfs *buf)
599{
600 int res;
601 struct fuse_intr_data d;
602 fuse_prepare_interrupt(f, req, &d);
603 res = f->op.statfs(path, buf);
604 fuse_finish_interrupt(f, req, &d);
605 return res;
606}
607
608static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
609 const char *path, struct fuse_file_info *fi)
610{
611 struct fuse_intr_data d;
612 fuse_prepare_interrupt(f, req, &d);
613 f->op.releasedir(path, fi);
614 fuse_finish_interrupt(f, req, &d);
615}
616
617static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
618 mode_t mode, struct fuse_file_info *fi)
619{
620 int res;
621 struct fuse_intr_data d;
622 fuse_prepare_interrupt(f, req, &d);
623 res = f->op.create(path, mode, fi);
624 fuse_finish_interrupt(f, req, &d);
625 return res;
626}
627
628static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
Miklos Szeredi07407852006-09-30 20:03:52 +0000629 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000630{
631 int res;
632 struct fuse_intr_data d;
633 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi07407852006-09-30 20:03:52 +0000634 res = f->op.lock(path, fi, cmd, lock);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000635 fuse_finish_interrupt(f, req, &d);
636 return res;
637}
638
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000639static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000640{
641 struct node *node;
642 int isopen = 0;
643 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000644 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000645 if (node && node->open_count > 0)
646 isopen = 1;
647 pthread_mutex_unlock(&f->lock);
648 return isopen;
649}
650
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000651static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
652 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000653{
654 struct stat buf;
655 struct node *node;
656 struct node *newnode;
657 char *newpath;
658 int res;
659 int failctr = 10;
660
661 if (!f->op.getattr)
662 return NULL;
663
664 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000665 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000666 node = lookup_node(f, dir, oldname);
667 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000668 pthread_mutex_unlock(&f->lock);
669 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000670 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000671 do {
672 f->hidectr ++;
673 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000674 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000675 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000676 } while(newnode);
677 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000678
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000679 newpath = get_path_name(f, dir, newname);
680 if (!newpath)
681 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000682
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000683 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000684 if (res != 0)
685 break;
686 free(newpath);
687 newpath = NULL;
688 } while(--failctr);
689
690 return newpath;
691}
692
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000693static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
694 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000695{
696 char newname[64];
697 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000698 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000699
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000700 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000701 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000702 if (newpath) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000703 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000704 if (res == 0)
705 err = rename_node(f, dir, oldname, dir, newname, 1);
706 free(newpath);
707 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000708 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000709 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000710}
711
Miklos Szeredi320abe42006-01-30 18:14:51 +0000712static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
713{
714 return stbuf->st_mtime == ts->tv_sec
Csaba Henk3e3a1252006-09-24 14:53:29 +0000715#ifdef FUSE_STAT_HAS_NANOSEC
716 && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec
Miklos Szeredi320abe42006-01-30 18:14:51 +0000717#endif
718 ;
719}
720
721static void mtime_set(const struct stat *stbuf, struct timespec *ts)
722{
Csaba Henk3e3a1252006-09-24 14:53:29 +0000723#ifdef FUSE_STAT_HAS_NANOSEC
724 *ts = ST_MTIM(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +0000725#else
726 ts->tv_sec = stbuf->st_mtime;
727#endif
728}
729
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000730#ifndef CLOCK_MONOTONIC
731#define CLOCK_MONOTONIC CLOCK_REALTIME
732#endif
733
Miklos Szeredi320abe42006-01-30 18:14:51 +0000734static void curr_time(struct timespec *now)
735{
736 static clockid_t clockid = CLOCK_MONOTONIC;
737 int res = clock_gettime(clockid, now);
738 if (res == -1 && errno == EINVAL) {
739 clockid = CLOCK_REALTIME;
740 res = clock_gettime(clockid, now);
741 }
742 if (res == -1) {
743 perror("fuse: clock_gettime");
744 abort();
745 }
746}
747
748static void update_stat(struct node *node, const struct stat *stbuf)
749{
750 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
751 stbuf->st_size != node->size))
752 node->cache_valid = 0;
753 mtime_set(stbuf, &node->mtime);
754 node->size = stbuf->st_size;
755 curr_time(&node->stat_updated);
756}
757
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000758static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
759 const char *name, const char *path,
760 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000761{
762 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000763
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000764 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000765 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000766 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000767 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000768 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000770 struct node *node;
771
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000772 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000773 if (node == NULL)
774 res = -ENOMEM;
775 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000776 e->ino = node->nodeid;
777 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000778 e->entry_timeout = f->conf.entry_timeout;
779 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000780 if (f->conf.auto_cache) {
781 pthread_mutex_lock(&f->lock);
782 update_stat(node, &e->attr);
783 pthread_mutex_unlock(&f->lock);
784 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000785 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000786 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000787 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000788 fflush(stdout);
789 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000790 }
791 }
792 return res;
793}
794
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000795static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000796{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000797 struct fuse_context_i *c;
798
799 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
800 if (c == NULL) {
801 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
802 if (c == NULL) {
803 /* This is hard to deal with properly, so just abort. If
804 memory is so low that the context cannot be allocated,
805 there's not much hope for the filesystem anyway */
806 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
807 abort();
808 }
809 pthread_setspecific(fuse_context_key, c);
810 }
811 return c;
812}
813
814static void fuse_freecontext(void *data)
815{
816 free(data);
817}
818
819static int fuse_create_context_key(void)
820{
821 int err = 0;
822 pthread_mutex_lock(&fuse_context_lock);
823 if (!fuse_context_ref) {
824 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
825 if (err) {
826 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
827 strerror(err));
828 pthread_mutex_unlock(&fuse_context_lock);
829 return -1;
830 }
831 }
832 fuse_context_ref++;
833 pthread_mutex_unlock(&fuse_context_lock);
834 return 0;
835}
836
837static void fuse_delete_context_key(void)
838{
839 pthread_mutex_lock(&fuse_context_lock);
840 fuse_context_ref--;
841 if (!fuse_context_ref) {
842 free(pthread_getspecific(fuse_context_key));
843 pthread_key_delete(fuse_context_key);
844 }
845 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000846}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000847
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000848static struct fuse *req_fuse_prepare(fuse_req_t req)
849{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000850 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000851 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000852 c->req = req;
853 c->ctx.fuse = req_fuse(req);
854 c->ctx.uid = ctx->uid;
855 c->ctx.gid = ctx->gid;
856 c->ctx.pid = ctx->pid;
857 c->ctx.private_data = c->ctx.fuse->user_data;
858 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000859}
860
861static inline void reply_err(fuse_req_t req, int err)
862{
863 /* fuse_reply_err() uses non-negated errno values */
864 fuse_reply_err(req, -err);
865}
866
867static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
868 int err)
869{
870 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000871 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000872 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000873 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000874 } else
875 reply_err(req, err);
876}
877
Miklos Szeredi065f2222006-01-20 15:15:21 +0000878static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000879{
880 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000881 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000882
883 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000884 c->ctx.fuse = f;
885 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000886
887 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000888 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000889}
890
891static void fuse_data_destroy(void *data)
892{
893 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000894 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000895
896 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000897 c->ctx.fuse = f;
898 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000899
900 if (f->op.destroy)
901 f->op.destroy(f->user_data);
902}
903
904static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
905{
906 struct fuse *f = req_fuse_prepare(req);
907 struct fuse_entry_param e;
908 char *path;
909 int err;
910
911 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000912 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000913 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000914 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000915 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000916 printf("LOOKUP %s\n", path);
917 fflush(stdout);
918 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000919 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000920 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000921 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000922 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000923 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000924 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000925 err = 0;
926 }
927 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000928 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000929 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000930 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000931 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000932}
933
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000934static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000935{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000936 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000937 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000938 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000939 fflush(stdout);
940 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000941 forget_node(f, ino, nlookup);
942 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000943}
944
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000945static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
946 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000947{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000948 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000949 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000950 char *path;
951 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000952
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000953 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000954 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000955
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000956 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000957 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000958 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000959 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000960 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000961 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000962 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000963 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000964 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000965 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000966 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000967 if (f->conf.auto_cache) {
968 pthread_mutex_lock(&f->lock);
969 update_stat(get_node(f, ino), &buf);
970 pthread_mutex_unlock(&f->lock);
971 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000972 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000973 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000974 } else
975 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000976}
977
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000978static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
979 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000980{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000981 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000982
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000983 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000984 if (f->op.chmod) {
985 struct fuse_intr_data d;
986 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000987 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000988 fuse_finish_interrupt(f, req, &d);
989 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000990
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000991 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000992}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000993
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000994static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
995 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000996{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000997 int err;
998 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
999 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +00001000
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001001 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001002 if (f->op.chown) {
1003 struct fuse_intr_data d;
1004 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001005 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001006 fuse_finish_interrupt(f, req, &d);
1007 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001008
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001009 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001010}
1011
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001012static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1013 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001014{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001015 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001016 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001017
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001018 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001019 if (fi && f->op.ftruncate) {
1020 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001021 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001022 fuse_finish_interrupt(f, req, &d);
1023 } else if (f->op.truncate) {
1024 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001025 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001026 fuse_finish_interrupt(f, req, &d);
1027 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001028 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001029}
1030
Miklos Szeredic3b76812006-09-16 08:52:09 +00001031static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1032 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001033{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001034 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001035 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001036
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001037 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001038 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001039 struct timespec tv[2];
Csaba Henk3e3a1252006-09-24 14:53:29 +00001040#ifdef FUSE_STAT_HAS_NANOSEC
1041 tv[0] = ST_ATIM(attr);
1042 tv[1] = ST_MTIM(attr);
1043#else
1044 tv[0].tv_sec = attr->st_atime;
1045 tv[0].tv_nsec = 0;
1046 tv[1].tv_sec = attr->st_mtime;
1047 tv[1].tv_nsec = 0;
1048#endif
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001049 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001050 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001051 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001052 } else if (f->op.utime) {
1053 struct utimbuf buf;
1054 buf.actime = attr->st_atime;
1055 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001056 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001057 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001058 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001059 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001060
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001061 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001062}
1063
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001064static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001065 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001066{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001067 struct fuse *f = req_fuse_prepare(req);
1068 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001069 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001070 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001071
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001072 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001073 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001074 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001075 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001076 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001077 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001078 err = 0;
1079 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001080 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001081 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001082 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001083 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001084 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001085 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 +00001086 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001087 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001088 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001089 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001090 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001091 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001092 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001093 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001094 if (f->conf.auto_cache) {
1095 pthread_mutex_lock(&f->lock);
1096 update_stat(get_node(f, ino), &buf);
1097 pthread_mutex_unlock(&f->lock);
1098 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001099 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001100 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001101 } else
1102 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001103}
1104
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001105static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1106{
1107 struct fuse *f = req_fuse_prepare(req);
1108 char *path;
1109 int err;
1110
1111 err = -ENOENT;
1112 pthread_rwlock_rdlock(&f->tree_lock);
1113 path = get_path(f, ino);
1114 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001115 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001116 printf("ACCESS %s 0%o\n", path, mask);
1117 fflush(stdout);
1118 }
1119 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001120 if (f->op.access) {
1121 struct fuse_intr_data d;
1122 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001123 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001124 fuse_finish_interrupt(f, req, &d);
1125 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001126 free(path);
1127 }
1128 pthread_rwlock_unlock(&f->tree_lock);
1129 reply_err(req, err);
1130}
1131
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001132static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001133{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001134 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001135 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001136 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001137 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001138
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001139 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001140 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001141 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001142 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001143 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001144 if (f->op.readlink) {
1145 struct fuse_intr_data d;
1146 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001147 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001148 fuse_finish_interrupt(f, req, &d);
1149 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001150 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001151 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001152 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001153 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001154 linkname[PATH_MAX] = '\0';
1155 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001156 } else
1157 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001158}
1159
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001160static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1161 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001162{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001163 struct fuse *f = req_fuse_prepare(req);
1164 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001165 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001166 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001167
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001168 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001169 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001170 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001171 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001172 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001173 printf("MKNOD %s\n", path);
1174 fflush(stdout);
1175 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001176 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001177 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1178 struct fuse_file_info fi;
1179
1180 memset(&fi, 0, sizeof(fi));
1181 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001182 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001183 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001184 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001185 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001186 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001187 }
1188 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001189 struct fuse_intr_data d;
1190 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001191 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001192 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001193 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001194 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001195 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001196 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001197 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001198 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001199 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001200}
1201
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001202static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1203 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001204{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001205 struct fuse *f = req_fuse_prepare(req);
1206 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001207 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001208 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001209
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001210 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001211 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001212 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001213 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001214 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001215 printf("MKDIR %s\n", path);
1216 fflush(stdout);
1217 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001218 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001219 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001220 struct fuse_intr_data d;
1221 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001222 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001223 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001224 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001225 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001226 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001227 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001228 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001229 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001230 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001231}
1232
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001233static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001234{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001235 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001236 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001237 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001238
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001239 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001240 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001241 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001242 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001243 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001244 printf("UNLINK %s\n", path);
1245 fflush(stdout);
1246 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001247 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001248 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001249 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001250 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001251 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001252 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001253 if (!err)
1254 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001255 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001256 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001257 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001258 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001259 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001260 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001261}
1262
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001263static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001264{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001265 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001266 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001267 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001268
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001269 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001270 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001271 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001272 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001273 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001274 printf("RMDIR %s\n", path);
1275 fflush(stdout);
1276 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001277 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001278 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001279 struct fuse_intr_data d;
1280 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001281 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001282 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001283 if (!err)
1284 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001285 }
1286 free(path);
1287 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001288 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001289 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001290}
1291
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001292static void fuse_symlink(fuse_req_t req, const char *linkname,
1293 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001294{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001295 struct fuse *f = req_fuse_prepare(req);
1296 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001297 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001298 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001299
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001300 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001301 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001302 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001303 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001304 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001305 printf("SYMLINK %s\n", path);
1306 fflush(stdout);
1307 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001308 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001309 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001310 struct fuse_intr_data d;
1311 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001312 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001313 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001314 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001315 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001316 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001317 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001318 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001319 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001320 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001321}
1322
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001323static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1324 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001325{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001326 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001327 char *oldpath;
1328 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001329 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001330
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001331 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001332 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001333 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001334 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001335 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001336 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001337 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001338 printf("RENAME %s -> %s\n", oldpath, newpath);
1339 fflush(stdout);
1340 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001341 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001342 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001343 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001344 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001345 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001346 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001347 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001348 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001349 if (!err)
1350 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001351 }
1352 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001353 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001354 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001355 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001356 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001357 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001358 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001359}
1360
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001361static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1362 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001363{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001364 struct fuse *f = req_fuse_prepare(req);
1365 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001366 char *oldpath;
1367 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001368 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001369
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001370 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001371 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001372 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001373 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001374 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001375 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001376 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001377 printf("LINK %s\n", newpath);
1378 fflush(stdout);
1379 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001380 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001381 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001382 struct fuse_intr_data d;
1383 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001384 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001385 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001386 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001387 err = lookup_path(f, req, newparent, newname, newpath, &e,
1388 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001389 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001390 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001391 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001392 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001393 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001394 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001395 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001396}
1397
Miklos Szeredid9079a72005-10-26 15:29:06 +00001398static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1399 mode_t mode, struct fuse_file_info *fi)
1400{
1401 struct fuse *f = req_fuse_prepare(req);
1402 struct fuse_entry_param e;
1403 char *path;
1404 int err;
1405
1406 err = -ENOENT;
1407 pthread_rwlock_rdlock(&f->tree_lock);
1408 path = get_path_name(f, parent, name);
1409 if (path != NULL) {
1410 err = -ENOSYS;
1411 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001412 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001413 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001414 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001415 printf("CREATE[%llu] flags: 0x%x %s\n",
1416 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001417 fflush(stdout);
1418 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001419 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001420 if (err) {
1421 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001422 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001423 } else if (!S_ISREG(e.attr.st_mode)) {
1424 err = -EIO;
1425 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001426 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001427 forget_node(f, e.ino, 1);
1428 }
1429 }
1430 }
1431 }
1432
1433 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001434 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001435 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001436 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001437 fi->keep_cache = 1;
1438
1439 pthread_mutex_lock(&f->lock);
1440 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1441 /* The open syscall was interrupted, so it must be cancelled */
1442 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001443 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001444 forget_node(f, e.ino, 1);
1445 } else {
1446 struct node *node = get_node(f, e.ino);
1447 node->open_count ++;
1448 }
1449 pthread_mutex_unlock(&f->lock);
1450 } else
1451 reply_err(req, err);
1452
1453 if (path)
1454 free(path);
1455 pthread_rwlock_unlock(&f->tree_lock);
1456}
1457
Miklos Szeredi320abe42006-01-30 18:14:51 +00001458static double diff_timespec(const struct timespec *t1,
1459 const struct timespec *t2)
1460{
1461 return (t1->tv_sec - t2->tv_sec) +
1462 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1463}
1464
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001465static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1466 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001467{
1468 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001469 if (node->cache_valid) {
1470 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001471
Miklos Szeredi08dab162006-02-01 13:39:15 +00001472 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001473 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001474 struct stat stbuf;
1475 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001476
Miklos Szeredi08dab162006-02-01 13:39:15 +00001477 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001478 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001479 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001480 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001481
1482 if (!err)
1483 update_stat(node, &stbuf);
1484 else
1485 node->cache_valid = 0;
1486 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001487 }
1488 if (node->cache_valid)
1489 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001490
1491 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001492}
1493
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001494static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1495 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001496{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001497 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001498 char *path = NULL;
1499 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001500
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001501 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001502 if (f->op.open) {
1503 err = -ENOENT;
1504 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001505 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001506 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001507 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001508 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001509 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001510 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1511 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001512 fflush(stdout);
1513 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001514
Miklos Szeredi659743b2005-12-09 17:41:42 +00001515 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001516 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001517 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001518 fi->keep_cache = 1;
1519
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001520 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001521 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001522 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001523
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001524 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001525 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001526 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001527 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001528 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001529 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001530 node->open_count ++;
1531 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001532 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001533 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001534 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001535
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001536 if (path)
1537 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001538 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001539}
1540
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001541static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1542 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001543{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001544 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001545 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001546 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001547 int res;
1548
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001549 buf = (char *) malloc(size);
1550 if (buf == NULL) {
1551 reply_err(req, -ENOMEM);
1552 return;
1553 }
1554
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001555 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001556 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001557 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001558 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001559 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001560 printf("READ[%llu] %lu bytes from %llu\n",
1561 (unsigned long long) fi->fh, (unsigned long) size,
1562 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001563 fflush(stdout);
1564 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001565
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001566 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001567 if (f->op.read) {
1568 struct fuse_intr_data d;
1569 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001570 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001571 fuse_finish_interrupt(f, req, &d);
1572 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001573 free(path);
1574 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001575 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001576
1577 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001578 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001579 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1580 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001581 fflush(stdout);
1582 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001583 if ((size_t) res > size)
1584 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001585 fuse_reply_buf(req, buf, res);
1586 } else
1587 reply_err(req, res);
1588
1589 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001590}
1591
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001592static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1593 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001594{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001595 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001596 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001597 int res;
1598
1599 res = -ENOENT;
1600 pthread_rwlock_rdlock(&f->tree_lock);
1601 path = get_path(f, ino);
1602 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001603 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001604 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001605 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001606 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001607 fflush(stdout);
1608 }
1609
1610 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001611 if (f->op.write) {
1612 struct fuse_intr_data d;
1613 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001614 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001615 fuse_finish_interrupt(f, req, &d);
1616 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001617 free(path);
1618 }
1619 pthread_rwlock_unlock(&f->tree_lock);
1620
Miklos Szeredif412d072005-10-14 21:24:32 +00001621 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001622 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001623 printf(" WRITE%s[%llu] %u bytes\n",
1624 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1625 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001626 fflush(stdout);
1627 }
1628 if ((size_t) res > size)
1629 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001630 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001631 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001632 reply_err(req, res);
1633}
1634
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001635static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1636 struct fuse_file_info *fi)
1637{
1638 struct fuse *f = req_fuse_prepare(req);
1639 char *path;
1640 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001641 int unlink_hidden = 0;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001642 int err = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001643
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001644 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001645 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001646 if (f->conf.debug) {
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001647 printf("RELEASE%s[%llu] flags: 0x%x\n", fi->flush ? "+FLUSH" : "",
1648 (unsigned long long) fi->fh, fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001649 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001650 }
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001651 if (fi->flush && path && f->op.flush)
1652 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001653 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001654 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001655
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001656 pthread_mutex_lock(&f->lock);
1657 node = get_node(f, ino);
1658 assert(node->open_count > 0);
1659 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001660 if (node->is_hidden && !node->open_count) {
1661 unlink_hidden = 1;
1662 node->is_hidden = 0;
1663 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001664 pthread_mutex_unlock(&f->lock);
1665
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001666 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001667 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001668
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001669 if (path)
1670 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001671 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001672
Miklos Szeredi4fca4322006-10-01 14:41:04 +00001673 reply_err(req, err);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001674}
1675
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001676static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1677 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001678{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001679 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001680 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001681 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001682
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001683 err = -ENOENT;
1684 pthread_rwlock_rdlock(&f->tree_lock);
1685 path = get_path(f, ino);
1686 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001687 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001688 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001689 fflush(stdout);
1690 }
1691 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001692 if (f->op.fsync) {
1693 struct fuse_intr_data d;
1694 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001695 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001696 fuse_finish_interrupt(f, req, &d);
1697 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001698 free(path);
1699 }
1700 pthread_rwlock_unlock(&f->tree_lock);
1701 reply_err(req, err);
1702}
1703
1704static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1705 struct fuse_file_info *fi)
1706{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001707 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001708 memset(fi, 0, sizeof(struct fuse_file_info));
1709 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001710 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001711 return dh;
1712}
1713
1714static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1715 struct fuse_file_info *llfi)
1716{
1717 struct fuse *f = req_fuse_prepare(req);
1718 struct fuse_dirhandle *dh;
1719
1720 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1721 if (dh == NULL) {
1722 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001723 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001724 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001725 memset(dh, 0, sizeof(struct fuse_dirhandle));
1726 dh->fuse = f;
1727 dh->contents = NULL;
1728 dh->len = 0;
1729 dh->filled = 0;
1730 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001731 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001732
Miklos Szeredi3a770472005-11-11 21:32:42 +00001733 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001734
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001735 if (f->op.opendir) {
1736 struct fuse_file_info fi;
1737 char *path;
1738 int err;
1739
1740 memset(&fi, 0, sizeof(fi));
1741 fi.flags = llfi->flags;
1742
1743 err = -ENOENT;
1744 pthread_rwlock_rdlock(&f->tree_lock);
1745 path = get_path(f, ino);
1746 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001747 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001748 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001749 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001750 if (!err) {
1751 pthread_mutex_lock(&f->lock);
1752 if (fuse_reply_open(req, llfi) == -ENOENT) {
1753 /* The opendir syscall was interrupted, so it must be
1754 cancelled */
1755 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001756 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001757 pthread_mutex_destroy(&dh->lock);
1758 free(dh);
1759 }
1760 pthread_mutex_unlock(&f->lock);
1761 } else {
1762 reply_err(req, err);
1763 free(dh);
1764 }
Miklos Szerediab974562005-04-07 15:40:21 +00001765 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001766 pthread_rwlock_unlock(&f->tree_lock);
1767 } else
1768 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001769}
Miklos Szeredib483c932001-10-29 14:57:57 +00001770
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001771static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1772{
1773 if (minsize > dh->size) {
1774 char *newptr;
1775 unsigned newsize = dh->size;
1776 if (!newsize)
1777 newsize = 1024;
1778 while (newsize < minsize)
1779 newsize *= 2;
1780
1781 newptr = (char *) realloc(dh->contents, newsize);
1782 if (!newptr) {
1783 dh->error = -ENOMEM;
1784 return -1;
1785 }
1786 dh->contents = newptr;
1787 dh->size = newsize;
1788 }
1789 return 0;
1790}
1791
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001792static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001793 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001794{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001795 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001796 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001797
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001798 if (statp)
1799 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001800 else {
1801 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001802 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001803 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001804
Miklos Szeredi659743b2005-12-09 17:41:42 +00001805 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001806 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001807 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001808 struct node *node;
1809 pthread_mutex_lock(&dh->fuse->lock);
1810 node = lookup_node(dh->fuse, dh->nodeid, name);
1811 if (node)
1812 stbuf.st_ino = (ino_t) node->nodeid;
1813 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001814 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001815 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001816
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001817 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001818 if (extend_contents(dh, dh->needlen) == -1)
1819 return 1;
1820
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001821 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001822 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1823 dh->needlen - dh->len, name,
1824 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001825 if (newlen > dh->needlen)
1826 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001827 } else {
1828 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1829 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001830 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001831
1832 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1833 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001834 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001835 dh->len = newlen;
1836 return 0;
1837}
1838
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001839static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001840 off_t off)
1841{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001842 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001843}
1844
1845static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1846 ino_t ino)
1847{
1848 struct stat stbuf;
1849
1850 memset(&stbuf, 0, sizeof(stbuf));
1851 stbuf.st_mode = type << 12;
1852 stbuf.st_ino = ino;
1853
1854 fill_dir_common(dh, name, &stbuf, 0);
1855 return dh->error;
1856}
1857
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001858static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1859 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001860 struct fuse_file_info *fi)
1861{
1862 int err = -ENOENT;
1863 char *path;
1864 pthread_rwlock_rdlock(&f->tree_lock);
1865 path = get_path(f, ino);
1866 if (path != NULL) {
1867 dh->len = 0;
1868 dh->error = 0;
1869 dh->needlen = size;
1870 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001871 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001872 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001873 if (f->op.readdir) {
1874 struct fuse_intr_data d;
1875 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001876 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001877 fuse_finish_interrupt(f, req, &d);
1878 } else if (f->op.getdir) {
1879 struct fuse_intr_data d;
1880 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001881 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001882 fuse_finish_interrupt(f, req, &d);
1883 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001884 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001885 if (!err)
1886 err = dh->error;
1887 if (err)
1888 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001889 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001890 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001891 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001892 return err;
1893}
Miklos Szeredie5183742005-02-02 11:14:04 +00001894
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001895static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1896 off_t off, struct fuse_file_info *llfi)
1897{
1898 struct fuse *f = req_fuse_prepare(req);
1899 struct fuse_file_info fi;
1900 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1901
1902 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001903 /* According to SUS, directory contents need to be refreshed on
1904 rewinddir() */
1905 if (!off)
1906 dh->filled = 0;
1907
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001908 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001909 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001910 if (err) {
1911 reply_err(req, err);
1912 goto out;
1913 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001914 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001915 if (dh->filled) {
1916 if (off < dh->len) {
1917 if (off + size > dh->len)
1918 size = dh->len - off;
1919 } else
1920 size = 0;
1921 } else {
1922 size = dh->len;
1923 off = 0;
1924 }
1925 fuse_reply_buf(req, dh->contents + off, size);
1926 out:
1927 pthread_mutex_unlock(&dh->lock);
1928}
Miklos Szeredia181e612001-11-06 12:03:23 +00001929
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001930static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1931 struct fuse_file_info *llfi)
1932{
1933 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001934 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001935 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1936 if (f->op.releasedir) {
1937 char *path;
1938
1939 pthread_rwlock_rdlock(&f->tree_lock);
1940 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001941 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001942 free(path);
1943 pthread_rwlock_unlock(&f->tree_lock);
1944 }
1945 pthread_mutex_lock(&dh->lock);
1946 pthread_mutex_unlock(&dh->lock);
1947 pthread_mutex_destroy(&dh->lock);
1948 free(dh->contents);
1949 free(dh);
1950 reply_err(req, 0);
1951}
1952
1953static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1954 struct fuse_file_info *llfi)
1955{
1956 struct fuse *f = req_fuse_prepare(req);
1957 struct fuse_file_info fi;
1958 char *path;
1959 int err;
1960
1961 get_dirhandle(llfi, &fi);
1962
1963 err = -ENOENT;
1964 pthread_rwlock_rdlock(&f->tree_lock);
1965 path = get_path(f, ino);
1966 if (path != NULL) {
1967 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001968 if (f->op.fsyncdir) {
1969 struct fuse_intr_data d;
1970 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001971 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001972 fuse_finish_interrupt(f, req, &d);
1973 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001974 free(path);
1975 }
1976 pthread_rwlock_unlock(&f->tree_lock);
1977 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001978}
1979
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001980static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001981{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001982 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001983 buf->f_bsize = 512;
1984 return 0;
1985}
1986
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001987static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001988{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001989 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001990 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001991 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001992
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001993 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001994 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001995 if (ino && (!f->compat || f->compat >= 26)) {
1996 char *path;
1997 pthread_rwlock_rdlock(&f->tree_lock);
1998 err = -ENOENT;
1999 path = get_path(f, ino);
2000 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002001 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00002002 free(path);
2003 }
2004 pthread_rwlock_unlock(&f->tree_lock);
2005 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002006 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00002007 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002008 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00002009
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002010 if (!err)
2011 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002012 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002013 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002014}
2015
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002016static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2017 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002018{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002019 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002020 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002021 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002022
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002023 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002024 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002025 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002026 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002027 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002028 if (f->op.setxattr) {
2029 struct fuse_intr_data d;
2030 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002031 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002032 fuse_finish_interrupt(f, req, &d);
2033 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002034 free(path);
2035 }
2036 pthread_rwlock_unlock(&f->tree_lock);
2037 reply_err(req, err);
2038}
2039
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002040static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2041 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002042{
2043 int err;
2044 char *path;
2045
2046 err = -ENOENT;
2047 pthread_rwlock_rdlock(&f->tree_lock);
2048 path = get_path(f, ino);
2049 if (path != NULL) {
2050 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002051 if (f->op.getxattr) {
2052 struct fuse_intr_data d;
2053 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002054 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002055 fuse_finish_interrupt(f, req, &d);
2056 }
Miklos Szerediab974562005-04-07 15:40:21 +00002057 free(path);
2058 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002059 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002060 return err;
2061}
2062
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002063static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2064 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002065{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002066 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002067 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002068
2069 if (size) {
2070 char *value = (char *) malloc(size);
2071 if (value == NULL) {
2072 reply_err(req, -ENOMEM);
2073 return;
2074 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002075 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002076 if (res > 0)
2077 fuse_reply_buf(req, value, res);
2078 else
2079 reply_err(req, res);
2080 free(value);
2081 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002082 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002083 if (res >= 0)
2084 fuse_reply_xattr(req, res);
2085 else
2086 reply_err(req, res);
2087 }
2088}
2089
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002090static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2091 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002092{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002093 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002094 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002095
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002096 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002097 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002098 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002099 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002100 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002101 if (f->op.listxattr) {
2102 struct fuse_intr_data d;
2103 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002104 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002105 fuse_finish_interrupt(f, req, &d);
2106 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002107 free(path);
2108 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002109 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002110 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002111}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002112
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002113static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002114{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002115 struct fuse *f = req_fuse_prepare(req);
2116 int res;
2117
2118 if (size) {
2119 char *list = (char *) malloc(size);
2120 if (list == NULL) {
2121 reply_err(req, -ENOMEM);
2122 return;
2123 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002124 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002125 if (res > 0)
2126 fuse_reply_buf(req, list, res);
2127 else
2128 reply_err(req, res);
2129 free(list);
2130 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002131 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002132 if (res >= 0)
2133 fuse_reply_xattr(req, res);
2134 else
2135 reply_err(req, res);
2136 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002137}
2138
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002139static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2140{
2141 struct fuse *f = req_fuse_prepare(req);
2142 char *path;
2143 int err;
2144
2145 err = -ENOENT;
2146 pthread_rwlock_rdlock(&f->tree_lock);
2147 path = get_path(f, ino);
2148 if (path != NULL) {
2149 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002150 if (f->op.removexattr) {
2151 struct fuse_intr_data d;
2152 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002153 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002154 fuse_finish_interrupt(f, req, &d);
2155 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002156 free(path);
2157 }
2158 pthread_rwlock_unlock(&f->tree_lock);
2159 reply_err(req, err);
2160}
2161
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002162static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2163{
2164 struct lock *l;
2165
2166 for (l = node->locks; l; l = l->next)
2167 if (l->owner != lock->owner &&
2168 lock->start <= l->end && l->start <= lock->end &&
2169 (l->type == F_WRLCK || lock->type == F_WRLCK))
2170 break;
2171
2172 return l;
2173}
2174
2175static void delete_lock(struct lock **lockp)
2176{
2177 struct lock *l = *lockp;
2178 *lockp = l->next;
2179 free(l);
2180}
2181
2182static void insert_lock(struct lock **pos, struct lock *lock)
2183{
2184 lock->next = *pos;
2185 *pos = lock;
2186}
2187
2188static int locks_insert(struct node *node, struct lock *lock)
2189{
2190 struct lock **lp;
2191 struct lock *newl1 = NULL;
2192 struct lock *newl2 = NULL;
2193
2194 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2195 newl1 = malloc(sizeof(struct lock));
2196 newl2 = malloc(sizeof(struct lock));
2197
2198 if (!newl1 || !newl2) {
2199 free(newl1);
2200 free(newl2);
2201 return -ENOLCK;
2202 }
2203 }
2204
2205 for (lp = &node->locks; *lp;) {
2206 struct lock *l = *lp;
2207 if (l->owner != lock->owner)
2208 goto skip;
2209
2210 if (lock->type == l->type) {
2211 if (l->end < lock->start - 1)
2212 goto skip;
2213 if (lock->end < l->start - 1)
2214 break;
2215 if (l->start <= lock->start && lock->end <= l->end)
2216 goto out;
2217 if (l->start < lock->start)
2218 lock->start = l->start;
2219 if (lock->end < l->end)
2220 lock->end = l->end;
2221 goto delete;
2222 } else {
2223 if (l->end < lock->start)
2224 goto skip;
2225 if (lock->end < l->start)
2226 break;
2227 if (lock->start <= l->start && l->end <= lock->end)
2228 goto delete;
2229 if (l->end <= lock->end) {
2230 l->end = lock->start - 1;
2231 goto skip;
2232 }
2233 if (lock->start <= l->start) {
2234 l->start = lock->end + 1;
2235 break;
2236 }
2237 *newl2 = *l;
2238 newl2->start = lock->end + 1;
2239 l->end = lock->start - 1;
2240 insert_lock(&l->next, newl2);
2241 newl2 = NULL;
2242 }
2243 skip:
2244 lp = &l->next;
2245 continue;
2246
2247 delete:
2248 delete_lock(lp);
2249 }
2250 if (lock->type != F_UNLCK) {
2251 *newl1 = *lock;
2252 insert_lock(lp, newl1);
2253 newl1 = NULL;
2254 }
2255out:
2256 free(newl1);
2257 free(newl2);
2258 return 0;
2259}
2260
2261static void flock_to_lock(struct flock *flock, struct lock *lock)
2262{
2263 memset(lock, 0, sizeof(struct lock));
2264 lock->type = flock->l_type;
2265 lock->start = flock->l_start;
2266 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2267 lock->pid = flock->l_pid;
2268}
2269
2270static void lock_to_flock(struct lock *lock, struct flock *flock)
2271{
2272 flock->l_type = lock->type;
2273 flock->l_start = lock->start;
2274 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2275 flock->l_pid = lock->pid;
2276}
2277
2278static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002279 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002280{
2281 struct fuse *f = req_fuse_prepare(req);
2282 char *path;
2283 int err;
2284
2285 err = -ENOENT;
2286 pthread_rwlock_rdlock(&f->tree_lock);
2287 path = get_path(f, ino);
2288 if (path != NULL) {
2289 if (f->conf.debug) {
2290 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2291 fflush(stdout);
2292 }
2293 err = -ENOSYS;
Miklos Szeredi4fca4322006-10-01 14:41:04 +00002294 if (f->op.flush)
2295 err = fuse_do_flush(f, req, path, fi);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002296 free(path);
2297 }
2298 if (f->op.lock) {
2299 struct flock lock;
2300 struct lock l;
2301 memset(&lock, 0, sizeof(lock));
2302 lock.l_type = F_UNLCK;
2303 lock.l_whence = SEEK_SET;
Miklos Szeredi07407852006-09-30 20:03:52 +00002304 fuse_do_lock(f, req, path, fi, F_SETLK, &lock);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002305 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002306 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002307 pthread_mutex_lock(&f->lock);
2308 locks_insert(get_node(f, ino), &l);
2309 pthread_mutex_unlock(&f->lock);
2310
2311 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2312 if (err == -ENOSYS)
2313 err = 0;
2314 }
2315 pthread_rwlock_unlock(&f->tree_lock);
2316 reply_err(req, err);
2317}
2318
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002319static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2320 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002321 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002322{
2323 struct fuse *f = req_fuse_prepare(req);
2324 char *path;
2325 int err;
2326
2327 err = -ENOENT;
2328 pthread_rwlock_rdlock(&f->tree_lock);
2329 path = get_path(f, ino);
2330 if (path != NULL) {
Miklos Szeredi07407852006-09-30 20:03:52 +00002331 err = fuse_do_lock(f, req, path, fi, cmd, lock);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002332 free(path);
2333 }
2334 pthread_rwlock_unlock(&f->tree_lock);
2335 return err;
2336}
2337
2338static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002339 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002340{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002341 int err;
2342 struct lock l;
2343 struct lock *conflict;
2344 struct fuse *f = req_fuse(req);
2345
2346 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002347 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002348 pthread_mutex_lock(&f->lock);
2349 conflict = locks_conflict(get_node(f, ino), &l);
2350 if (conflict)
2351 lock_to_flock(conflict, lock);
2352 pthread_mutex_unlock(&f->lock);
2353 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002354 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002355 else
2356 err = 0;
2357
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002358 if (!err)
2359 fuse_reply_lock(req, lock);
2360 else
2361 reply_err(req, err);
2362}
2363
2364static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2365 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002366 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002367{
Miklos Szeredi07407852006-09-30 20:03:52 +00002368 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002369 if (!err) {
2370 struct fuse *f = req_fuse(req);
2371 struct lock l;
2372 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002373 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002374 pthread_mutex_lock(&f->lock);
2375 locks_insert(get_node(f, ino), &l);
2376 pthread_mutex_unlock(&f->lock);
2377 }
2378 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002379}
2380
Miklos Szeredi708b4812006-09-30 16:02:25 +00002381static void fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2382 uint64_t idx)
2383{
2384 struct fuse *f = req_fuse_prepare(req);
2385 char *path;
2386 int err;
2387
2388 err = -ENOENT;
2389 pthread_rwlock_rdlock(&f->tree_lock);
2390 path = get_path(f, ino);
2391 if (path != NULL) {
2392 err = -ENOSYS;
2393 if (f->op.bmap)
2394 err = f->op.bmap(path, blocksize, &idx);
2395 free(path);
2396 }
2397 pthread_rwlock_unlock(&f->tree_lock);
2398 if (!err)
2399 fuse_reply_bmap(req, idx);
2400 else
2401 reply_err(req, err);
2402}
2403
Miklos Szeredia1482422005-08-14 23:00:27 +00002404static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002405 .init = fuse_data_init,
2406 .destroy = fuse_data_destroy,
2407 .lookup = fuse_lookup,
2408 .forget = fuse_forget,
2409 .getattr = fuse_getattr,
2410 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002411 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002412 .readlink = fuse_readlink,
2413 .mknod = fuse_mknod,
2414 .mkdir = fuse_mkdir,
2415 .unlink = fuse_unlink,
2416 .rmdir = fuse_rmdir,
2417 .symlink = fuse_symlink,
2418 .rename = fuse_rename,
2419 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002420 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002421 .open = fuse_open,
2422 .read = fuse_read,
2423 .write = fuse_write,
2424 .flush = fuse_flush,
2425 .release = fuse_release,
2426 .fsync = fuse_fsync,
2427 .opendir = fuse_opendir,
2428 .readdir = fuse_readdir,
2429 .releasedir = fuse_releasedir,
2430 .fsyncdir = fuse_fsyncdir,
2431 .statfs = fuse_statfs,
2432 .setxattr = fuse_setxattr,
2433 .getxattr = fuse_getxattr,
2434 .listxattr = fuse_listxattr,
2435 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002436 .getlk = fuse_getlk,
2437 .setlk = fuse_setlk,
Miklos Szeredi708b4812006-09-30 16:02:25 +00002438 .bmap = fuse_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002439};
2440
Miklos Szeredia1482422005-08-14 23:00:27 +00002441static void free_cmd(struct fuse_cmd *cmd)
2442{
2443 free(cmd->buf);
2444 free(cmd);
2445}
2446
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002447void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002448{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002449 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002450 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002451}
2452
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002453int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002454{
Miklos Szeredia1482422005-08-14 23:00:27 +00002455 return fuse_session_exited(f->se);
2456}
2457
2458struct fuse_session *fuse_get_session(struct fuse *f)
2459{
2460 return f->se;
2461}
2462
2463static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2464{
2465 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2466 if (cmd == NULL) {
2467 fprintf(stderr, "fuse: failed to allocate cmd\n");
2468 return NULL;
2469 }
2470 cmd->buf = (char *) malloc(bufsize);
2471 if (cmd->buf == NULL) {
2472 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2473 free(cmd);
2474 return NULL;
2475 }
2476 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002477}
2478
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002479struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002480{
Miklos Szeredia1482422005-08-14 23:00:27 +00002481 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2482 size_t bufsize = fuse_chan_bufsize(ch);
2483 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2484 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002485 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002486 if (res <= 0) {
2487 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002488 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002489 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002490 return NULL;
2491 }
2492 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002493 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002494 }
2495 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002496}
2497
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002498int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002499{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002500 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002501 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002502 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002503 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002504}
2505
Miklos Szeredi891b8742004-07-29 09:27:49 +00002506int fuse_invalidate(struct fuse *f, const char *path)
2507{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002508 (void) f;
2509 (void) path;
2510 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002511}
2512
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002513void fuse_exit(struct fuse *f)
2514{
Miklos Szeredia1482422005-08-14 23:00:27 +00002515 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002516}
2517
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002518struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002519{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002520 return &fuse_get_context_internal()->ctx;
2521}
2522
2523int fuse_interrupted(void)
2524{
2525 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002526}
2527
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002528void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002529{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002530 (void) func;
2531 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002532}
2533
Miklos Szerediad005972006-01-07 10:14:34 +00002534enum {
2535 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002536};
2537
Miklos Szeredi659743b2005-12-09 17:41:42 +00002538#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2539
2540static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002541 FUSE_OPT_KEY("-h", KEY_HELP),
2542 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002543 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2544 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002545 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002546 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002547 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2548 FUSE_LIB_OPT("use_ino", use_ino, 1),
2549 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2550 FUSE_LIB_OPT("direct_io", direct_io, 1),
2551 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002552 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2553 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002554 FUSE_LIB_OPT("umask=", set_mode, 1),
2555 FUSE_LIB_OPT("umask=%o", umask, 0),
2556 FUSE_LIB_OPT("uid=", set_uid, 1),
2557 FUSE_LIB_OPT("uid=%d", uid, 0),
2558 FUSE_LIB_OPT("gid=", set_gid, 1),
2559 FUSE_LIB_OPT("gid=%d", gid, 0),
2560 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2561 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002562 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2563 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002564 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002565 FUSE_LIB_OPT("intr", intr, 1),
2566 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002567 FUSE_OPT_END
2568};
2569
Miklos Szerediad005972006-01-07 10:14:34 +00002570static void fuse_lib_help(void)
2571{
2572 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002573" -o hard_remove immediate removal (don't hide files)\n"
2574" -o use_ino let filesystem set inode numbers\n"
2575" -o readdir_ino try to fill in d_ino in readdir\n"
2576" -o direct_io use direct I/O\n"
2577" -o kernel_cache cache files in kernel\n"
2578" -o [no]auto_cache enable caching based on modification times\n"
2579" -o umask=M set file permissions (octal)\n"
2580" -o uid=N set file owner\n"
2581" -o gid=N set file group\n"
2582" -o entry_timeout=T cache timeout for names (1.0s)\n"
2583" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002584" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2585" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002586" -o intr allow requests to be interrupted\n"
2587" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2588"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002589}
2590
2591static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2592 struct fuse_args *outargs)
2593{
2594 (void) data; (void) arg; (void) outargs;
2595
2596 if (key == KEY_HELP)
2597 fuse_lib_help();
2598
2599 return 1;
2600}
2601
2602
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002603int fuse_is_lib_option(const char *opt)
2604{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002605 return fuse_lowlevel_is_lib_option(opt) ||
2606 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002607}
2608
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002609static int fuse_init_intr_signal(int signum, int *installed)
2610{
2611 struct sigaction old_sa;
2612
2613 if (sigaction(signum, NULL, &old_sa) == -1) {
2614 perror("fuse: cannot get old signal handler");
2615 return -1;
2616 }
2617
2618 if (old_sa.sa_handler == SIG_DFL) {
2619 struct sigaction sa;
2620
2621 memset(&sa, 0, sizeof(struct sigaction));
2622 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002623 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002624
2625 if (sigaction(signum, &sa, NULL) == -1) {
2626 perror("fuse: cannot set interrupt signal handler");
2627 return -1;
2628 }
2629 *installed = 1;
2630 }
2631 return 0;
2632}
2633
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002634static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002635{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002636 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002637
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002638 memset(&sa, 0, sizeof(struct sigaction));
2639 sa.sa_handler = SIG_DFL;
2640 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002641}
2642
Miklos Szeredi6f385412006-03-17 15:05:40 +00002643struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002644 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002645 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002646{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002647 struct fuse *f;
2648 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002649 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002650
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002651 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002652 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002653 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002654 }
2655
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002656 if (fuse_create_context_key() == -1)
2657 goto out;
2658
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002659 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002660 if (f == NULL) {
2661 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002662 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002663 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002664
Miklos Szeredi6f385412006-03-17 15:05:40 +00002665 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002666 f->conf.entry_timeout = 1.0;
2667 f->conf.attr_timeout = 1.0;
2668 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002669 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002670
Miklos Szerediad005972006-01-07 10:14:34 +00002671 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002672 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002673
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002674 if (!f->conf.ac_attr_timeout_set)
2675 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2676
Miklos Szeredi659743b2005-12-09 17:41:42 +00002677#ifdef __FreeBSD__
2678 /*
2679 * In FreeBSD, we always use these settings as inode numbers are needed to
2680 * make getcwd(3) work.
2681 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002682 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002683#endif
2684
Miklos Szeredi065f2222006-01-20 15:15:21 +00002685 if (compat && compat <= 25) {
2686 if (fuse_sync_compat_args(args) == -1)
2687 goto out_free;
2688 }
2689
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002690 memcpy(&f->op, op, op_size);
2691 if (!f->op.lock) {
2692 llop.getlk = NULL;
2693 llop.setlk = NULL;
2694 }
2695
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002696 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002697 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002698 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002699
Miklos Szeredia1482422005-08-14 23:00:27 +00002700 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002701
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002702 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002703 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002704 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002705 f->name_table_size = 14057;
2706 f->name_table = (struct node **)
2707 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002708 if (f->name_table == NULL) {
2709 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002710 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002711 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002712
Miklos Szeredia13d9002004-11-02 17:32:03 +00002713 f->id_table_size = 14057;
2714 f->id_table = (struct node **)
2715 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002716 if (f->id_table == NULL) {
2717 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002718 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002719 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002720
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002721 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002722 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002723 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002724
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002725 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002726 if (root == NULL) {
2727 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002728 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002729 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002730
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002731 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002732 if (root->name == NULL) {
2733 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002734 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002735 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002736
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002737 if (f->conf.intr &&
2738 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2739 goto out_free_root_name;
2740
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002741 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002742 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002743 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002744 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002745 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002746 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002747
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002748 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002749
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002750 out_free_root_name:
2751 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002752 out_free_root:
2753 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002754 out_free_id_table:
2755 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002756 out_free_name_table:
2757 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002758 out_free_session:
2759 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002760 out_free:
2761 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002762 out_delete_context_key:
2763 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002764 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002765 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002766}
2767
Miklos Szeredi6f385412006-03-17 15:05:40 +00002768struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2769 const struct fuse_operations *op, size_t op_size,
2770 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002771{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002772 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002773}
2774
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002775void fuse_destroy(struct fuse *f)
2776{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002777 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002778 struct fuse_context_i *c = fuse_get_context_internal();
2779
2780 if (f->conf.intr && f->intr_installed)
2781 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002782
2783 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002784 c->ctx.fuse = f;
2785 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002786
Miklos Szeredia13d9002004-11-02 17:32:03 +00002787 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002788 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002789
Miklos Szeredia13d9002004-11-02 17:32:03 +00002790 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002791 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002792 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002793 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002794 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002795 free(path);
2796 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002797 }
2798 }
2799 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002800 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002801 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002802 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002803
Miklos Szeredia13d9002004-11-02 17:32:03 +00002804 for (node = f->id_table[i]; node != NULL; node = next) {
2805 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002806 free_node(node);
2807 }
2808 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002809 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002810 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002811 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002812 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002813 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002814 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002815 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002816}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002817
Miklos Szeredieafdf422006-09-22 19:30:17 +00002818#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002819#include "fuse_compat.h"
2820
Miklos Szeredi6f385412006-03-17 15:05:40 +00002821static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2822 const struct fuse_operations *op,
2823 size_t op_size, int compat)
2824{
2825 struct fuse *f = NULL;
2826 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2827
2828 if (ch)
2829 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2830
2831 return f;
2832}
2833
Miklos Szeredi065f2222006-01-20 15:15:21 +00002834#ifndef __FreeBSD__
2835
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002836static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2837 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002838{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002839 int err;
2840 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002841 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002842 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002843 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002844 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002845 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002846 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002847 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002848 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002849 memcpy(fi, &tmp, sizeof(tmp));
2850 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002851 } else {
2852 fuse_prepare_interrupt(f, req, &d);
2853 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002854 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002855 fuse_finish_interrupt(f, req, &d);
2856 }
2857 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002858}
2859
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002860static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2861 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002862{
2863 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002864 fuse_do_release(f, req, path ? path : "-", fi);
2865 else if (path) {
2866 struct fuse_intr_data d;
2867 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002868 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002869 fuse_finish_interrupt(f, req, &d);
2870 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002871}
2872
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002873static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2874 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002875{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002876 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002877 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002878 } else {
2879 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002880 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002881 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002882 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002883 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002884 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002885 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002886 memcpy(fi, &tmp, sizeof(tmp));
2887 fi->fh = tmp.fh;
2888 return err;
2889 }
2890}
2891
2892static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2893 struct statvfs *stbuf)
2894{
2895 stbuf->f_bsize = compatbuf->block_size;
2896 stbuf->f_blocks = compatbuf->blocks;
2897 stbuf->f_bfree = compatbuf->blocks_free;
2898 stbuf->f_bavail = compatbuf->blocks_free;
2899 stbuf->f_files = compatbuf->files;
2900 stbuf->f_ffree = compatbuf->files_free;
2901 stbuf->f_namemax = compatbuf->namelen;
2902}
2903
2904static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2905{
2906 stbuf->f_bsize = oldbuf->f_bsize;
2907 stbuf->f_blocks = oldbuf->f_blocks;
2908 stbuf->f_bfree = oldbuf->f_bfree;
2909 stbuf->f_bavail = oldbuf->f_bavail;
2910 stbuf->f_files = oldbuf->f_files;
2911 stbuf->f_ffree = oldbuf->f_ffree;
2912 stbuf->f_namemax = oldbuf->f_namelen;
2913}
2914
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002915static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2916 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002917{
2918 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002919 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002920
Miklos Szeredi065f2222006-01-20 15:15:21 +00002921 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002922 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002923 } else if (f->compat > 11) {
2924 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002925 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002926 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002927 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002928 if (!err)
2929 convert_statfs_old(&oldbuf, buf);
2930 } else {
2931 struct fuse_statfs_compat1 compatbuf;
2932 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002933 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002934 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002935 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002936 if (!err)
2937 convert_statfs_compat(&compatbuf, buf);
2938 }
2939 return err;
2940}
2941
Miklos Szeredi95da8602006-01-06 18:29:40 +00002942static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2943 const struct fuse_operations *op,
2944 size_t op_size, int compat)
2945{
2946 struct fuse *f;
2947 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2948
2949 if (opts &&
2950 (fuse_opt_add_arg(&args, "") == -1 ||
2951 fuse_opt_add_arg(&args, "-o") == -1 ||
2952 fuse_opt_add_arg(&args, opts) == -1)) {
2953 fuse_opt_free_args(&args);
2954 return NULL;
2955 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002956 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002957 fuse_opt_free_args(&args);
2958
2959 return f;
2960}
2961
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002962struct fuse *fuse_new_compat22(int fd, const char *opts,
2963 const struct fuse_operations_compat22 *op,
2964 size_t op_size)
2965{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002966 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2967 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002968}
2969
2970struct fuse *fuse_new_compat2(int fd, const char *opts,
2971 const struct fuse_operations_compat2 *op)
2972{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002973 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2974 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002975}
2976
2977struct fuse *fuse_new_compat1(int fd, int flags,
2978 const struct fuse_operations_compat1 *op)
2979{
2980 const char *opts = NULL;
2981 if (flags & FUSE_DEBUG_COMPAT1)
2982 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002983 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2984 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002985}
2986
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002987__asm__(".symver fuse_exited,__fuse_exited@");
2988__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2989__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2990__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2991__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002992__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002993
2994#else /* __FreeBSD__ */
2995
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002996static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2997 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002998{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002999 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003000}
3001
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003002static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
3003 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003004{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003005 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003006}
3007
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003008static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
3009 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003010{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003011 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003012}
3013
Csaba Henk3e3a1252006-09-24 14:53:29 +00003014static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003015{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003016 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003017}
3018
3019#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003020
3021struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3022 const struct fuse_operations_compat25 *op,
3023 size_t op_size)
3024{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003025 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3026 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003027}
3028
3029__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");