blob: c28528eba06a2f05dec149ad47090ac9ba38bb16 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
Miklos Szeredie2aa2e22005-07-15 13:31:36 +00009
10/* For pthread_rwlock_t */
11#define _GNU_SOURCE
12
Miklos Szeredi178451d2005-08-15 13:19:07 +000013#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000014#include "fuse_lowlevel.h"
Miklos Szeredi659743b2005-12-09 17:41:42 +000015#include "fuse_opt.h"
Miklos Szeredi38f152c2006-09-03 18:28:52 +000016#include "fuse_misc.h"
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017
Miklos Szeredi0f62d722005-01-04 12:45:54 +000018#include <stdio.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000020#include <stdlib.h>
Miklos Szeredi659743b2005-12-09 17:41:42 +000021#include <stddef.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022#include <unistd.h>
Miklos Szeredi320abe42006-01-30 18:14:51 +000023#include <time.h>
Miklos Szeredib3f99722005-11-16 13:00:24 +000024#include <fcntl.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000025#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026#include <errno.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000027#include <signal.h>
Miklos Szeredi0f62d722005-01-04 12:45:54 +000028#include <assert.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000029#include <sys/param.h>
Miklos Szerediab974562005-04-07 15:40:21 +000030#include <sys/uio.h>
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000031#include <sys/time.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000032
Miklos Szeredi97c61e92001-11-07 12:09:43 +000033#define FUSE_MAX_PATH 4096
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000034#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
Miklos Szeredi30e093a2005-04-03 17:44:54 +000035
Miklos Szeredie248e4b2005-12-14 16:18:32 +000036#define FUSE_UNKNOWN_INO 0xffffffff
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000037#define OFFSET_MAX 0x7fffffffffffffffLL
Miklos Szeredie248e4b2005-12-14 16:18:32 +000038
Miklos Szeredi659743b2005-12-09 17:41:42 +000039struct fuse_config {
Miklos Szeredi659743b2005-12-09 17:41:42 +000040 unsigned int uid;
41 unsigned int gid;
42 unsigned int umask;
43 double entry_timeout;
44 double negative_timeout;
45 double attr_timeout;
Miklos Szeredi6e806e92006-02-16 16:59:39 +000046 double ac_attr_timeout;
47 int ac_attr_timeout_set;
Miklos Szeredi659743b2005-12-09 17:41:42 +000048 int debug;
49 int hard_remove;
50 int use_ino;
51 int readdir_ino;
52 int set_mode;
53 int set_uid;
54 int set_gid;
55 int direct_io;
56 int kernel_cache;
Miklos Szeredi320abe42006-01-30 18:14:51 +000057 int auto_cache;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000058 int intr;
59 int intr_signal;
Miklos Szeredi659743b2005-12-09 17:41:42 +000060};
61
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000062struct fuse {
Miklos Szeredia1482422005-08-14 23:00:27 +000063 struct fuse_session *se;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000064 struct fuse_operations op;
65 int compat;
66 struct node **name_table;
67 size_t name_table_size;
68 struct node **id_table;
69 size_t id_table_size;
70 fuse_ino_t ctr;
71 unsigned int generation;
72 unsigned int hidectr;
73 pthread_mutex_t lock;
74 pthread_rwlock_t tree_lock;
75 void *user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +000076 struct fuse_config conf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +000077 int intr_installed;
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000078};
79
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +000080struct lock {
81 int type;
82 off_t start;
83 off_t end;
84 pid_t pid;
85 uint64_t owner;
86 struct lock *next;
87};
88
Miklos Szeredi0f62d722005-01-04 12:45:54 +000089struct node {
90 struct node *name_next;
91 struct node *id_next;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000092 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000093 unsigned int generation;
94 int refctr;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000095 fuse_ino_t parent;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000096 char *name;
Miklos Szeredi38009022005-05-08 19:47:22 +000097 uint64_t nlookup;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000098 int open_count;
99 int is_hidden;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000100 struct timespec stat_updated;
101 struct timespec mtime;
102 off_t size;
103 int cache_valid;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +0000104 struct lock *locks;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105};
106
107struct fuse_dirhandle {
Miklos Szerediab974562005-04-07 15:40:21 +0000108 pthread_mutex_t lock;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000109 struct fuse *fuse;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +0000110 fuse_req_t req;
Miklos Szeredi1b188022005-07-28 11:07:29 +0000111 char *contents;
Miklos Szerediab974562005-04-07 15:40:21 +0000112 int allocated;
Miklos Szeredib92d9782005-02-07 16:10:49 +0000113 unsigned len;
Miklos Szeredic4c12ae2005-10-20 14:48:50 +0000114 unsigned size;
Miklos Szerediab974562005-04-07 15:40:21 +0000115 unsigned needlen;
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000116 int filled;
Miklos Szeredi3a770472005-11-11 21:32:42 +0000117 uint64_t fh;
Miklos Szerediab974562005-04-07 15:40:21 +0000118 int error;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000119 fuse_ino_t nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000120};
121
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000122struct fuse_context_i {
123 struct fuse_context ctx;
124 fuse_req_t req;
125};
Miklos Szeredid169f312004-09-22 08:48:26 +0000126
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000127static pthread_key_t fuse_context_key;
128static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
129static int fuse_context_ref;
130
131static int fuse_compat_open(struct fuse *, fuse_req_t, char *,
132 struct fuse_file_info *);
133static void fuse_compat_release(struct fuse *, fuse_req_t, char *,
134 struct fuse_file_info *);
135static int fuse_compat_opendir(struct fuse *, fuse_req_t, char *,
136 struct fuse_file_info *);
137static int fuse_compat_statfs(struct fuse *, fuse_req_t, struct statvfs *);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +0000138
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000139static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000140{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000141 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000142 struct node *node;
143
Miklos Szeredia13d9002004-11-02 17:32:03 +0000144 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
145 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 return node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000149}
150
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000151static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +0000152{
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000153 struct node *node = get_node_nocheck(f, nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000154 if (!node) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000155 fprintf(stderr, "fuse internal error: node %llu not found\n",
156 (unsigned long long) nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000157 abort();
158 }
159 return node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000160}
161
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000162static void free_node(struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000163{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000164 free(node->name);
165 free(node);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000166}
167
Miklos Szeredia13d9002004-11-02 17:32:03 +0000168static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000169{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000170 size_t hash = node->nodeid % f->id_table_size;
171 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172
Miklos Szeredie5183742005-02-02 11:14:04 +0000173 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000174 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000175 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176 return;
177 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000178}
179
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000180static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181{
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000182 size_t hash = node->nodeid % f->id_table_size;
183 node->id_next = f->id_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000184 f->id_table[hash] = node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000185}
186
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000187static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000188{
189 unsigned int hash = *name;
190
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000191 if (hash)
192 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000193 hash = (hash << 5) - hash + *name;
194
195 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196}
197
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000198static void unref_node(struct fuse *f, struct node *node);
199
200static void unhash_name(struct fuse *f, struct node *node)
201{
202 if (node->name) {
203 size_t hash = name_hash(f, node->parent, node->name);
204 struct node **nodep = &f->name_table[hash];
Miklos Szeredie5183742005-02-02 11:14:04 +0000205
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000206 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
207 if (*nodep == node) {
208 *nodep = node->name_next;
209 node->name_next = NULL;
210 unref_node(f, get_node(f, node->parent));
211 free(node->name);
212 node->name = NULL;
213 node->parent = 0;
214 return;
215 }
Miklos Szeredi3a770472005-11-11 21:32:42 +0000216 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
217 (unsigned long long) node->nodeid);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000218 abort();
219 }
220}
221
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000222static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000223 const char *name)
224{
225 size_t hash = name_hash(f, parent, name);
226 node->name = strdup(name);
227 if (node->name == NULL)
228 return -1;
229
230 get_node(f, parent)->refctr ++;
231 node->parent = parent;
232 node->name_next = f->name_table[hash];
233 f->name_table[hash] = node;
234 return 0;
235}
236
237static void delete_node(struct fuse *f, struct node *node)
238{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000239 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000240 printf("delete: %llu\n", (unsigned long long) node->nodeid);
Miklos Szeredi38009022005-05-08 19:47:22 +0000241 fflush(stdout);
242 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000243 assert(!node->name);
244 unhash_id(f, node);
245 free_node(node);
246}
247
248static void unref_node(struct fuse *f, struct node *node)
249{
250 assert(node->refctr > 0);
251 node->refctr --;
252 if (!node->refctr)
253 delete_node(f, node);
254}
255
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000256static fuse_ino_t next_id(struct fuse *f)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000257{
258 do {
259 f->ctr++;
260 if (!f->ctr)
261 f->generation ++;
262 } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
263 return f->ctr;
264}
265
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000266static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000267 const char *name)
268{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000269 size_t hash = name_hash(f, parent, name);
270 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000271
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
273 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000274 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000275
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000277}
278
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000279static struct node *find_node(struct fuse *f, fuse_ino_t parent,
280 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000281{
282 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000283
Miklos Szeredia181e612001-11-06 12:03:23 +0000284 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000285 node = lookup_node(f, parent, name);
Miklos Szeredie331c4b2005-07-06 13:34:02 +0000286 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000287 node = (struct node *) calloc(1, sizeof(struct node));
288 if (node == NULL)
289 goto out_err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000290
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000291 node->refctr = 1;
292 node->nodeid = next_id(f);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000293 node->open_count = 0;
294 node->is_hidden = 0;
295 node->generation = f->generation;
296 if (hash_name(f, node, parent, name) == -1) {
297 free(node);
298 node = NULL;
299 goto out_err;
300 }
301 hash_id(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000302 }
Miklos Szeredi38009022005-05-08 19:47:22 +0000303 node->nlookup ++;
Miklos Szeredic2309912004-09-21 13:40:38 +0000304 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000305 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000306 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000307}
308
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000309static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000310{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 size_t len = strlen(name);
312 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
315 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000316 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 strncpy(s, name, len);
318 s--;
319 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000321 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000322}
323
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000324static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000325{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000326 char buf[FUSE_MAX_PATH];
327 char *s = buf + FUSE_MAX_PATH - 1;
328 struct node *node;
Miklos Szeredie5183742005-02-02 11:14:04 +0000329
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000330 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000331
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000333 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000335 return NULL;
336 }
337
338 pthread_mutex_lock(&f->lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000339 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
340 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000341 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342 s = NULL;
343 break;
344 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000345
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000346 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000347 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000348 break;
349 }
350 pthread_mutex_unlock(&f->lock);
351
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000352 if (node == NULL || s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000354 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000355 return strdup("/");
356 else
357 return strdup(s);
358}
Miklos Szeredia181e612001-11-06 12:03:23 +0000359
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000360static char *get_path(struct fuse *f, fuse_ino_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000361{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000362 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000363}
364
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000365static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
Miklos Szeredi38009022005-05-08 19:47:22 +0000366{
367 struct node *node;
368 if (nodeid == FUSE_ROOT_ID)
369 return;
370 pthread_mutex_lock(&f->lock);
371 node = get_node(f, nodeid);
372 assert(node->nlookup >= nlookup);
373 node->nlookup -= nlookup;
374 if (!node->nlookup) {
375 unhash_name(f, node);
376 unref_node(f, node);
377 }
378 pthread_mutex_unlock(&f->lock);
379}
380
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000381static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000382{
Miklos Szeredia181e612001-11-06 12:03:23 +0000383 struct node *node;
384
385 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000386 node = lookup_node(f, dir, name);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000387 if (node != NULL)
388 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000389 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000390}
391
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000392static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
393 fuse_ino_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000394{
Miklos Szeredia181e612001-11-06 12:03:23 +0000395 struct node *node;
396 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000397 int err = 0;
Miklos Szeredie5183742005-02-02 11:14:04 +0000398
Miklos Szeredia181e612001-11-06 12:03:23 +0000399 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000400 node = lookup_node(f, olddir, oldname);
401 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000402 if (node == NULL)
403 goto out;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000404
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000405 if (newnode != NULL) {
406 if (hide) {
407 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000408 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000409 goto out;
410 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000411 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000412 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000413
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000414 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000415 if (hash_name(f, node, newdir, newname) == -1) {
416 err = -ENOMEM;
417 goto out;
418 }
Miklos Szeredie5183742005-02-02 11:14:04 +0000419
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000420 if (hide)
421 node->is_hidden = 1;
422
423 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000424 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000425 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000426}
427
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000428static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429{
Miklos Szeredi659743b2005-12-09 17:41:42 +0000430 if (!f->conf.use_ino)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000431 stbuf->st_ino = nodeid;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000432 if (f->conf.set_mode)
433 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
434 if (f->conf.set_uid)
435 stbuf->st_uid = f->conf.uid;
436 if (f->conf.set_gid)
437 stbuf->st_gid = f->conf.gid;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000438}
439
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000440static struct fuse *req_fuse(fuse_req_t req)
441{
442 return (struct fuse *) fuse_req_userdata(req);
443}
444
445static void fuse_intr_sighandler(int sig)
446{
447 (void) sig;
448 /* Nothing to do */
449}
450
451struct fuse_intr_data {
452 pthread_t id;
453 pthread_cond_t cond;
454 int finished;
455};
456
457static void fuse_interrupt(fuse_req_t req, void *d_)
458{
459 struct fuse_intr_data *d = d_;
460 struct fuse *f = req_fuse(req);
461
462 if (d->id == pthread_self())
463 return;
464
465 pthread_mutex_lock(&f->lock);
466 while (!d->finished) {
467 struct timeval now;
468 struct timespec timeout;
469
470 pthread_kill(d->id, f->conf.intr_signal);
471 gettimeofday(&now, NULL);
472 timeout.tv_sec = now.tv_sec + 1;
473 timeout.tv_nsec = now.tv_usec * 1000;
474 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
475 }
476 pthread_mutex_unlock(&f->lock);
477}
478
479static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
480 struct fuse_intr_data *d)
481{
482 pthread_mutex_lock(&f->lock);
483 d->finished = 1;
484 pthread_cond_broadcast(&d->cond);
485 pthread_mutex_unlock(&f->lock);
486 fuse_req_interrupt_func(req, NULL, NULL);
487 pthread_cond_destroy(&d->cond);
488}
489
490static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
491{
492 d->id = pthread_self();
493 pthread_cond_init(&d->cond, NULL);
494 d->finished = 0;
495 fuse_req_interrupt_func(req, fuse_interrupt, d);
496}
497
498static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
499 struct fuse_intr_data *d)
500{
501 if (f->conf.intr)
502 fuse_do_finish_interrupt(f, req, d);
503}
504
505static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
506 struct fuse_intr_data *d)
507{
508 if (f->conf.intr)
509 fuse_do_prepare_interrupt(req, d);
510}
511
512static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path,
513 struct stat *buf)
514{
515 int res;
516 struct fuse_intr_data d;
517 fuse_prepare_interrupt(f, req, &d);
518 res = f->op.getattr(path, buf);
519 fuse_finish_interrupt(f, req, &d);
520 return res;
521}
522
523static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path,
524 struct stat *buf, struct fuse_file_info *fi)
525{
526 int res;
527 struct fuse_intr_data d;
528 fuse_prepare_interrupt(f, req, &d);
529 res = f->op.fgetattr(path, buf, fi);
530 fuse_finish_interrupt(f, req, &d);
531 return res;
532}
533
534static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath,
535 const char *newpath)
536{
537 int res;
538 struct fuse_intr_data d;
539 fuse_prepare_interrupt(f, req, &d);
540 res = f->op.rename(oldpath, newpath);
541 fuse_finish_interrupt(f, req, &d);
542 return res;
543}
544
545static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path)
546{
547 int res;
548 struct fuse_intr_data d;
549 fuse_prepare_interrupt(f, req, &d);
550 res = f->op.unlink(path);
551 fuse_finish_interrupt(f, req, &d);
552 return res;
553}
554
555static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path,
556 struct fuse_file_info *fi)
557{
558 struct fuse_intr_data d;
559 fuse_prepare_interrupt(f, req, &d);
560 f->op.release(path, fi);
561 fuse_finish_interrupt(f, req, &d);
562}
563
564static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path,
565 struct fuse_file_info *fi)
566{
567 int res;
568 struct fuse_intr_data d;
569 fuse_prepare_interrupt(f, req, &d);
570 res = f->op.opendir(path, fi);
571 fuse_finish_interrupt(f, req, &d);
572 return res;
573}
574
575static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path,
576 struct fuse_file_info *fi)
577{
578 int res;
579 struct fuse_intr_data d;
580 fuse_prepare_interrupt(f, req, &d);
581 res = f->op.open(path, fi);
582 fuse_finish_interrupt(f, req, &d);
583 return res;
584}
585
586static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path,
587 struct statvfs *buf)
588{
589 int res;
590 struct fuse_intr_data d;
591 fuse_prepare_interrupt(f, req, &d);
592 res = f->op.statfs(path, buf);
593 fuse_finish_interrupt(f, req, &d);
594 return res;
595}
596
597static void fuse_do_releasedir(struct fuse *f, fuse_req_t req,
598 const char *path, struct fuse_file_info *fi)
599{
600 struct fuse_intr_data d;
601 fuse_prepare_interrupt(f, req, &d);
602 f->op.releasedir(path, fi);
603 fuse_finish_interrupt(f, req, &d);
604}
605
606static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path,
607 mode_t mode, struct fuse_file_info *fi)
608{
609 int res;
610 struct fuse_intr_data d;
611 fuse_prepare_interrupt(f, req, &d);
612 res = f->op.create(path, mode, fi);
613 fuse_finish_interrupt(f, req, &d);
614 return res;
615}
616
617static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path,
Miklos Szeredi07407852006-09-30 20:03:52 +0000618 struct fuse_file_info *fi, int cmd, struct flock *lock)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000619{
620 int res;
621 struct fuse_intr_data d;
622 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi07407852006-09-30 20:03:52 +0000623 res = f->op.lock(path, fi, cmd, lock);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000624 fuse_finish_interrupt(f, req, &d);
625 return res;
626}
627
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000628static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000629{
630 struct node *node;
631 int isopen = 0;
632 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000633 node = lookup_node(f, dir, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000634 if (node && node->open_count > 0)
635 isopen = 1;
636 pthread_mutex_unlock(&f->lock);
637 return isopen;
638}
639
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000640static char *hidden_name(struct fuse *f, fuse_req_t req, fuse_ino_t dir,
641 const char *oldname, char *newname, size_t bufsize)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000642{
643 struct stat buf;
644 struct node *node;
645 struct node *newnode;
646 char *newpath;
647 int res;
648 int failctr = 10;
649
650 if (!f->op.getattr)
651 return NULL;
652
653 do {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000654 pthread_mutex_lock(&f->lock);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000655 node = lookup_node(f, dir, oldname);
656 if (node == NULL) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000657 pthread_mutex_unlock(&f->lock);
658 return NULL;
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000659 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000660 do {
661 f->hidectr ++;
662 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000663 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000664 newnode = lookup_node(f, dir, newname);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000665 } while(newnode);
666 pthread_mutex_unlock(&f->lock);
Miklos Szeredie5183742005-02-02 11:14:04 +0000667
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000668 newpath = get_path_name(f, dir, newname);
669 if (!newpath)
670 break;
Miklos Szeredie5183742005-02-02 11:14:04 +0000671
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000672 res = fuse_do_getattr(f, req, newpath, &buf);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000673 if (res != 0)
674 break;
675 free(newpath);
676 newpath = NULL;
677 } while(--failctr);
678
679 return newpath;
680}
681
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000682static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath,
683 fuse_ino_t dir, const char *oldname)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000684{
685 char newname[64];
686 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000687 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000688
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000689 if (f->op.rename && f->op.unlink) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000690 newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000691 if (newpath) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000692 int res = fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000693 if (res == 0)
694 err = rename_node(f, dir, oldname, dir, newname, 1);
695 free(newpath);
696 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000697 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000698 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000699}
700
Miklos Szeredi320abe42006-01-30 18:14:51 +0000701static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
702{
703 return stbuf->st_mtime == ts->tv_sec
Csaba Henk3e3a1252006-09-24 14:53:29 +0000704#ifdef FUSE_STAT_HAS_NANOSEC
705 && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec
Miklos Szeredi320abe42006-01-30 18:14:51 +0000706#endif
707 ;
708}
709
710static void mtime_set(const struct stat *stbuf, struct timespec *ts)
711{
Csaba Henk3e3a1252006-09-24 14:53:29 +0000712#ifdef FUSE_STAT_HAS_NANOSEC
713 *ts = ST_MTIM(stbuf);
Miklos Szeredi320abe42006-01-30 18:14:51 +0000714#else
715 ts->tv_sec = stbuf->st_mtime;
716#endif
717}
718
Miklos Szeredi2512aaa2006-05-03 14:54:59 +0000719#ifndef CLOCK_MONOTONIC
720#define CLOCK_MONOTONIC CLOCK_REALTIME
721#endif
722
Miklos Szeredi320abe42006-01-30 18:14:51 +0000723static void curr_time(struct timespec *now)
724{
725 static clockid_t clockid = CLOCK_MONOTONIC;
726 int res = clock_gettime(clockid, now);
727 if (res == -1 && errno == EINVAL) {
728 clockid = CLOCK_REALTIME;
729 res = clock_gettime(clockid, now);
730 }
731 if (res == -1) {
732 perror("fuse: clock_gettime");
733 abort();
734 }
735}
736
737static void update_stat(struct node *node, const struct stat *stbuf)
738{
739 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
740 stbuf->st_size != node->size))
741 node->cache_valid = 0;
742 mtime_set(stbuf, &node->mtime);
743 node->size = stbuf->st_size;
744 curr_time(&node->stat_updated);
745}
746
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000747static int lookup_path(struct fuse *f, fuse_req_t req, fuse_ino_t nodeid,
748 const char *name, const char *path,
749 struct fuse_entry_param *e, struct fuse_file_info *fi)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000750{
751 int res;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000752
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000753 memset(e, 0, sizeof(struct fuse_entry_param));
Miklos Szeredif7eec032005-10-28 13:09:50 +0000754 if (fi && f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000755 res = fuse_do_fgetattr(f, req, path, &e->attr, fi);
Miklos Szeredif7eec032005-10-28 13:09:50 +0000756 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000757 res = fuse_do_getattr(f, req, path, &e->attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000758 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000759 struct node *node;
760
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000761 node = find_node(f, nodeid, name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000762 if (node == NULL)
763 res = -ENOMEM;
764 else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000765 e->ino = node->nodeid;
766 e->generation = node->generation;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000767 e->entry_timeout = f->conf.entry_timeout;
768 e->attr_timeout = f->conf.attr_timeout;
Miklos Szeredi320abe42006-01-30 18:14:51 +0000769 if (f->conf.auto_cache) {
770 pthread_mutex_lock(&f->lock);
771 update_stat(node, &e->attr);
772 pthread_mutex_unlock(&f->lock);
773 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000774 set_stat(f, e->ino, &e->attr);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000775 if (f->conf.debug) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000776 printf(" NODEID: %lu\n", (unsigned long) e->ino);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000777 fflush(stdout);
778 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000779 }
780 }
781 return res;
782}
783
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000784static struct fuse_context_i *fuse_get_context_internal(void)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000785{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000786 struct fuse_context_i *c;
787
788 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
789 if (c == NULL) {
790 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
791 if (c == NULL) {
792 /* This is hard to deal with properly, so just abort. If
793 memory is so low that the context cannot be allocated,
794 there's not much hope for the filesystem anyway */
795 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
796 abort();
797 }
798 pthread_setspecific(fuse_context_key, c);
799 }
800 return c;
801}
802
803static void fuse_freecontext(void *data)
804{
805 free(data);
806}
807
808static int fuse_create_context_key(void)
809{
810 int err = 0;
811 pthread_mutex_lock(&fuse_context_lock);
812 if (!fuse_context_ref) {
813 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
814 if (err) {
815 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
816 strerror(err));
817 pthread_mutex_unlock(&fuse_context_lock);
818 return -1;
819 }
820 }
821 fuse_context_ref++;
822 pthread_mutex_unlock(&fuse_context_lock);
823 return 0;
824}
825
826static void fuse_delete_context_key(void)
827{
828 pthread_mutex_lock(&fuse_context_lock);
829 fuse_context_ref--;
830 if (!fuse_context_ref) {
831 free(pthread_getspecific(fuse_context_key));
832 pthread_key_delete(fuse_context_key);
833 }
834 pthread_mutex_unlock(&fuse_context_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000835}
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000836
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000837static struct fuse *req_fuse_prepare(fuse_req_t req)
838{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000839 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000840 const struct fuse_ctx *ctx = fuse_req_ctx(req);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000841 c->req = req;
842 c->ctx.fuse = req_fuse(req);
843 c->ctx.uid = ctx->uid;
844 c->ctx.gid = ctx->gid;
845 c->ctx.pid = ctx->pid;
846 c->ctx.private_data = c->ctx.fuse->user_data;
847 return c->ctx.fuse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000848}
849
850static inline void reply_err(fuse_req_t req, int err)
851{
852 /* fuse_reply_err() uses non-negated errno values */
853 fuse_reply_err(req, -err);
854}
855
856static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
857 int err)
858{
859 if (!err) {
Miklos Szeredib67f2162006-02-20 10:55:33 +0000860 struct fuse *f = req_fuse(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000861 if (fuse_reply_entry(req, e) == -ENOENT)
Miklos Szeredib67f2162006-02-20 10:55:33 +0000862 forget_node(f, e->ino, 1);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000863 } else
864 reply_err(req, err);
865}
866
Miklos Szeredi065f2222006-01-20 15:15:21 +0000867static void fuse_data_init(void *data, struct fuse_conn_info *conn)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000868{
869 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000870 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000871
872 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000873 c->ctx.fuse = f;
874 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000875
876 if (f->op.init)
Miklos Szeredi065f2222006-01-20 15:15:21 +0000877 f->user_data = f->op.init(conn);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000878}
879
880static void fuse_data_destroy(void *data)
881{
882 struct fuse *f = (struct fuse *) data;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000883 struct fuse_context_i *c = fuse_get_context_internal();
Miklos Szeredi4f5df5e2005-10-07 12:39:58 +0000884
885 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000886 c->ctx.fuse = f;
887 c->ctx.private_data = f->user_data;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000888
889 if (f->op.destroy)
890 f->op.destroy(f->user_data);
891}
892
893static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
894{
895 struct fuse *f = req_fuse_prepare(req);
896 struct fuse_entry_param e;
897 char *path;
898 int err;
899
900 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000901 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000902 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +0000904 if (f->conf.debug) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000905 printf("LOOKUP %s\n", path);
906 fflush(stdout);
907 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000908 err = -ENOSYS;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000909 if (f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000910 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000911 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000912 e.ino = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +0000913 e.entry_timeout = f->conf.negative_timeout;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000914 err = 0;
915 }
916 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000917 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000918 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000919 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000920 reply_entry(req, &e, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000921}
922
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000923static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000924{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000925 struct fuse *f = req_fuse(req);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000926 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +0000927 printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
Miklos Szeredi43696432001-11-18 19:15:05 +0000928 fflush(stdout);
929 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000930 forget_node(f, ino, nlookup);
931 fuse_reply_none(req);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000932}
933
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000934static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
935 struct fuse_file_info *fi)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000936{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000937 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000938 struct stat buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000939 char *path;
940 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000941
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000942 (void) fi;
Miklos Szeredi16dbf942006-09-02 13:20:40 +0000943 memset(&buf, 0, sizeof(buf));
Miklos Szerediecce1bf2005-08-25 15:19:06 +0000944
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000945 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000946 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000947 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000948 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000949 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000950 if (f->op.getattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000951 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000952 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000953 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +0000954 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000955 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +0000956 if (f->conf.auto_cache) {
957 pthread_mutex_lock(&f->lock);
958 update_stat(get_node(f, ino), &buf);
959 pthread_mutex_unlock(&f->lock);
960 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000961 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +0000962 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000963 } else
964 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000965}
966
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000967static int do_chmod(struct fuse *f, fuse_req_t req, const char *path,
968 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000969{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000970 int err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000971
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000972 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000973 if (f->op.chmod) {
974 struct fuse_intr_data d;
975 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000976 err = f->op.chmod(path, attr->st_mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000977 fuse_finish_interrupt(f, req, &d);
978 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000979
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000980 return err;
Miklos Szeredie5183742005-02-02 11:14:04 +0000981}
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000982
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000983static int do_chown(struct fuse *f, fuse_req_t req, const char *path,
984 struct stat *attr, int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000985{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000986 int err;
987 uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
988 gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
Miklos Szeredie5183742005-02-02 11:14:04 +0000989
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000990 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000991 if (f->op.chown) {
992 struct fuse_intr_data d;
993 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000994 err = f->op.chown(path, uid, gid);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +0000995 fuse_finish_interrupt(f, req, &d);
996 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000997
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000998 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000999}
1000
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001001static int do_truncate(struct fuse *f, fuse_req_t req, const char *path,
1002 struct stat *attr, struct fuse_file_info *fi)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001003{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001004 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001005 struct fuse_intr_data d;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001006
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001007 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001008 if (fi && f->op.ftruncate) {
1009 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001010 err = f->op.ftruncate(path, attr->st_size, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001011 fuse_finish_interrupt(f, req, &d);
1012 } else if (f->op.truncate) {
1013 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001014 err = f->op.truncate(path, attr->st_size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001015 fuse_finish_interrupt(f, req, &d);
1016 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001017 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001018}
1019
Miklos Szeredic3b76812006-09-16 08:52:09 +00001020static int do_utimens(struct fuse *f, fuse_req_t req, const char *path,
1021 struct stat *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001022{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001023 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001024 struct fuse_intr_data d;
Miklos Szeredifa440772006-09-02 09:51:08 +00001025
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001026 err = -ENOSYS;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001027 if (f->op.utimens) {
Miklos Szeredifa440772006-09-02 09:51:08 +00001028 struct timespec tv[2];
Csaba Henk3e3a1252006-09-24 14:53:29 +00001029#ifdef FUSE_STAT_HAS_NANOSEC
1030 tv[0] = ST_ATIM(attr);
1031 tv[1] = ST_MTIM(attr);
1032#else
1033 tv[0].tv_sec = attr->st_atime;
1034 tv[0].tv_nsec = 0;
1035 tv[1].tv_sec = attr->st_mtime;
1036 tv[1].tv_nsec = 0;
1037#endif
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001038 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredic3b76812006-09-16 08:52:09 +00001039 err = f->op.utimens(path, tv);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001040 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001041 } else if (f->op.utime) {
1042 struct utimbuf buf;
1043 buf.actime = attr->st_atime;
1044 buf.modtime = attr->st_mtime;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001045 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001046 err = f->op.utime(path, &buf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001047 fuse_finish_interrupt(f, req, &d);
Miklos Szeredifa440772006-09-02 09:51:08 +00001048 }
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001049
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001050 return err;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +00001051}
1052
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001053static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
Miklos Szerediecce1bf2005-08-25 15:19:06 +00001054 int valid, struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001055{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001056 struct fuse *f = req_fuse_prepare(req);
1057 struct stat buf;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001058 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001059 int err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001060
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001061 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001062 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001063 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001064 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001065 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001066 if (f->op.getattr) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001067 err = 0;
1068 if (!err && (valid & FUSE_SET_ATTR_MODE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001069 err = do_chmod(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001070 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001071 err = do_chown(f, req, path, attr, valid);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001072 if (!err && (valid & FUSE_SET_ATTR_SIZE))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001073 err = do_truncate(f, req, path, attr, fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001074 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 +00001075 err = do_utimens(f, req, path, attr);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001076 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001077 err = fuse_do_getattr(f, req, path, &buf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001078 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001079 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001080 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001081 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001082 if (!err) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001083 if (f->conf.auto_cache) {
1084 pthread_mutex_lock(&f->lock);
1085 update_stat(get_node(f, ino), &buf);
1086 pthread_mutex_unlock(&f->lock);
1087 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001088 set_stat(f, ino, &buf);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001089 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001090 } else
1091 reply_err(req, err);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001092}
1093
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001094static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1095{
1096 struct fuse *f = req_fuse_prepare(req);
1097 char *path;
1098 int err;
1099
1100 err = -ENOENT;
1101 pthread_rwlock_rdlock(&f->tree_lock);
1102 path = get_path(f, ino);
1103 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001104 if (f->conf.debug) {
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001105 printf("ACCESS %s 0%o\n", path, mask);
1106 fflush(stdout);
1107 }
1108 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001109 if (f->op.access) {
1110 struct fuse_intr_data d;
1111 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001112 err = f->op.access(path, mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001113 fuse_finish_interrupt(f, req, &d);
1114 }
Miklos Szeredib0b13d12005-10-26 12:53:25 +00001115 free(path);
1116 }
1117 pthread_rwlock_unlock(&f->tree_lock);
1118 reply_err(req, err);
1119}
1120
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001121static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001122{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001123 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001124 char linkname[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +00001125 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001126 int err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001127
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001128 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001129 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001130 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001131 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001132 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001133 if (f->op.readlink) {
1134 struct fuse_intr_data d;
1135 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001136 err = f->op.readlink(path, linkname, sizeof(linkname));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001137 fuse_finish_interrupt(f, req, &d);
1138 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001139 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001140 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001141 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001142 if (!err) {
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001143 linkname[PATH_MAX] = '\0';
1144 fuse_reply_readlink(req, linkname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001145 } else
1146 reply_err(req, err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001147}
1148
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001149static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1150 mode_t mode, dev_t rdev)
Miklos Szeredib483c932001-10-29 14:57:57 +00001151{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001152 struct fuse *f = req_fuse_prepare(req);
1153 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001154 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001155 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001156
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001157 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001158 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001159 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001160 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001161 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001162 printf("MKNOD %s\n", path);
1163 fflush(stdout);
1164 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001165 err = -ENOSYS;
Miklos Szeredib3f99722005-11-16 13:00:24 +00001166 if (S_ISREG(mode) && f->op.create && f->op.getattr) {
1167 struct fuse_file_info fi;
1168
1169 memset(&fi, 0, sizeof(fi));
1170 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001171 err = fuse_do_create(f, req, path, mode, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001172 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001173 err = lookup_path(f, req, parent, name, path, &e, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001174 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001175 fuse_do_release(f, req, path, &fi);
Miklos Szeredib3f99722005-11-16 13:00:24 +00001176 }
1177 } else if (f->op.mknod && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001178 struct fuse_intr_data d;
1179 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001180 err = f->op.mknod(path, mode, rdev);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001181 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001182 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001183 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001184 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001185 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001186 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001187 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001188 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001189}
1190
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001191static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1192 mode_t mode)
Miklos Szeredib483c932001-10-29 14:57:57 +00001193{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001194 struct fuse *f = req_fuse_prepare(req);
1195 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001196 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001197 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001198
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001199 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001200 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001201 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001202 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001203 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001204 printf("MKDIR %s\n", path);
1205 fflush(stdout);
1206 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001207 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001208 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001209 struct fuse_intr_data d;
1210 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001211 err = f->op.mkdir(path, mode);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001212 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001213 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001214 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001215 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001216 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001217 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001218 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001219 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001220}
1221
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001222static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001223{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001224 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib483c932001-10-29 14:57:57 +00001225 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001226 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001227
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001228 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001229 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001230 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001231 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001232 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001233 printf("UNLINK %s\n", path);
1234 fflush(stdout);
1235 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001236 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001237 if (f->op.unlink) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001238 if (!f->conf.hard_remove && is_open(f, parent, name))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001239 err = hide_node(f, req, path, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001240 else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001241 err = fuse_do_unlink(f, req, path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001242 if (!err)
1243 remove_node(f, parent, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001244 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001245 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001246 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +00001247 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001248 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001249 reply_err(req, err);
Miklos Szeredib5958612004-02-20 14:10:49 +00001250}
1251
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001252static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
Miklos Szeredib5958612004-02-20 14:10:49 +00001253{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001254 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredib5958612004-02-20 14:10:49 +00001255 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001256 int err;
Miklos Szeredib5958612004-02-20 14:10:49 +00001257
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001258 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001259 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001260 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001261 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001262 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001263 printf("RMDIR %s\n", path);
1264 fflush(stdout);
1265 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001266 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001267 if (f->op.rmdir) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001268 struct fuse_intr_data d;
1269 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001270 err = f->op.rmdir(path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001271 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001272 if (!err)
1273 remove_node(f, parent, name);
Miklos Szeredib5958612004-02-20 14:10:49 +00001274 }
1275 free(path);
1276 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001277 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001278 reply_err(req, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001279}
1280
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001281static void fuse_symlink(fuse_req_t req, const char *linkname,
1282 fuse_ino_t parent, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +00001283{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001284 struct fuse *f = req_fuse_prepare(req);
1285 struct fuse_entry_param e;
Miklos Szeredib483c932001-10-29 14:57:57 +00001286 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001287 int err;
Miklos Szeredib483c932001-10-29 14:57:57 +00001288
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001289 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001290 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001291 path = get_path_name(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001292 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001293 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001294 printf("SYMLINK %s\n", path);
1295 fflush(stdout);
1296 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001297 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001298 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001299 struct fuse_intr_data d;
1300 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001301 err = f->op.symlink(linkname, path);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001302 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001303 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001304 err = lookup_path(f, req, parent, name, path, &e, NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001305 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001306 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001307 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001308 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001309 reply_entry(req, &e, err);
Miklos Szeredib483c932001-10-29 14:57:57 +00001310}
1311
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001312static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
1313 fuse_ino_t newdir, const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001314{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001315 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001316 char *oldpath;
1317 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001318 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001319
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001320 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001321 pthread_rwlock_wrlock(&f->tree_lock);
Miklos Szeredia181e612001-11-06 12:03:23 +00001322 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001323 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001324 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001325 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001326 if (f->conf.debug) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001327 printf("RENAME %s -> %s\n", oldpath, newpath);
1328 fflush(stdout);
1329 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001330 err = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001331 if (f->op.rename) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001332 err = 0;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001333 if (!f->conf.hard_remove &&
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001334 is_open(f, newdir, newname))
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001335 err = hide_node(f, req, newpath, newdir, newname);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001336 if (!err) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001337 fuse_do_rename(f, req, oldpath, newpath);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001338 if (!err)
1339 err = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001340 }
1341 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001342 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001343 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001344 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001345 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001346 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001347 reply_err(req, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001348}
1349
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001350static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1351 const char *newname)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001352{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001353 struct fuse *f = req_fuse_prepare(req);
1354 struct fuse_entry_param e;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001355 char *oldpath;
1356 char *newpath;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001357 int err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001358
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001359 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001360 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001361 oldpath = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001362 if (oldpath != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001363 newpath = get_path_name(f, newparent, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001364 if (newpath != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001365 if (f->conf.debug) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001366 printf("LINK %s\n", newpath);
1367 fflush(stdout);
1368 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001369 err = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001370 if (f->op.link && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001371 struct fuse_intr_data d;
1372 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001373 err = f->op.link(oldpath, newpath);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001374 fuse_finish_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001375 if (!err)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001376 err = lookup_path(f, req, newparent, newname, newpath, &e,
1377 NULL);
Miklos Szeredi76f65782004-02-19 16:55:40 +00001378 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001379 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001380 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001381 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001382 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001383 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001384 reply_entry(req, &e, err);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001385}
1386
Miklos Szeredid9079a72005-10-26 15:29:06 +00001387static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1388 mode_t mode, struct fuse_file_info *fi)
1389{
1390 struct fuse *f = req_fuse_prepare(req);
1391 struct fuse_entry_param e;
1392 char *path;
1393 int err;
1394
1395 err = -ENOENT;
1396 pthread_rwlock_rdlock(&f->tree_lock);
1397 path = get_path_name(f, parent, name);
1398 if (path != NULL) {
1399 err = -ENOSYS;
1400 if (f->op.create && f->op.getattr) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001401 err = fuse_do_create(f, req, path, mode, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001402 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001403 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001404 printf("CREATE[%llu] flags: 0x%x %s\n",
1405 (unsigned long long) fi->fh, fi->flags, path);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001406 fflush(stdout);
1407 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001408 err = lookup_path(f, req, parent, name, path, &e, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001409 if (err) {
1410 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001411 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001412 } else if (!S_ISREG(e.attr.st_mode)) {
1413 err = -EIO;
1414 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001415 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001416 forget_node(f, e.ino, 1);
1417 }
1418 }
1419 }
1420 }
1421
1422 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001423 if (f->conf.direct_io)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001424 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001425 if (f->conf.kernel_cache)
Miklos Szeredid9079a72005-10-26 15:29:06 +00001426 fi->keep_cache = 1;
1427
1428 pthread_mutex_lock(&f->lock);
1429 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1430 /* The open syscall was interrupted, so it must be cancelled */
1431 if(f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001432 fuse_do_release(f, req, path, fi);
Miklos Szeredid9079a72005-10-26 15:29:06 +00001433 forget_node(f, e.ino, 1);
1434 } else {
1435 struct node *node = get_node(f, e.ino);
1436 node->open_count ++;
1437 }
1438 pthread_mutex_unlock(&f->lock);
1439 } else
1440 reply_err(req, err);
1441
1442 if (path)
1443 free(path);
1444 pthread_rwlock_unlock(&f->tree_lock);
1445}
1446
Miklos Szeredi320abe42006-01-30 18:14:51 +00001447static double diff_timespec(const struct timespec *t1,
1448 const struct timespec *t2)
1449{
1450 return (t1->tv_sec - t2->tv_sec) +
1451 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1452}
1453
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001454static void open_auto_cache(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1455 const char *path, struct fuse_file_info *fi)
Miklos Szeredi320abe42006-01-30 18:14:51 +00001456{
1457 struct node *node = get_node(f, ino);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001458 if (node->cache_valid) {
1459 struct timespec now;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001460
Miklos Szeredi08dab162006-02-01 13:39:15 +00001461 curr_time(&now);
Miklos Szeredi6e806e92006-02-16 16:59:39 +00001462 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
Miklos Szeredi08dab162006-02-01 13:39:15 +00001463 struct stat stbuf;
1464 int err;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001465
Miklos Szeredi08dab162006-02-01 13:39:15 +00001466 if (f->op.fgetattr)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001467 err = fuse_do_fgetattr(f, req, path, &stbuf, fi);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001468 else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001469 err = fuse_do_getattr(f, req, path, &stbuf);
Miklos Szeredi08dab162006-02-01 13:39:15 +00001470
1471 if (!err)
1472 update_stat(node, &stbuf);
1473 else
1474 node->cache_valid = 0;
1475 }
Miklos Szeredi320abe42006-01-30 18:14:51 +00001476 }
1477 if (node->cache_valid)
1478 fi->keep_cache = 1;
Miklos Szeredi08dab162006-02-01 13:39:15 +00001479
1480 node->cache_valid = 1;
Miklos Szeredi320abe42006-01-30 18:14:51 +00001481}
1482
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001483static void fuse_open(fuse_req_t req, fuse_ino_t ino,
1484 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001485{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001486 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001487 char *path = NULL;
1488 int err = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001489
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001490 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredi31066bb2005-08-01 14:49:31 +00001491 if (f->op.open) {
1492 err = -ENOENT;
1493 path = get_path(f, ino);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001494 if (path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001495 err = fuse_compat_open(f, req, path, fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001496 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001497 if (!err) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001498 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001499 printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1500 fi->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001501 fflush(stdout);
1502 }
Miklos Szeredie5183742005-02-02 11:14:04 +00001503
Miklos Szeredi659743b2005-12-09 17:41:42 +00001504 if (f->conf.direct_io)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001505 fi->direct_io = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001506 if (f->conf.kernel_cache)
Miklos Szeredie77cc072005-08-01 11:58:51 +00001507 fi->keep_cache = 1;
1508
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001509 pthread_mutex_lock(&f->lock);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001510 if (f->conf.auto_cache)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001511 open_auto_cache(f, req, ino, path, fi);
Miklos Szeredi320abe42006-01-30 18:14:51 +00001512
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001513 if (fuse_reply_open(req, fi) == -ENOENT) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001514 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001515 if(f->op.release && path != NULL)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001516 fuse_compat_release(f, req, path, fi);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001517 } else {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001518 struct node *node = get_node(f, ino);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001519 node->open_count ++;
1520 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001521 pthread_mutex_unlock(&f->lock);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001522 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001523 reply_err(req, err);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001524
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001525 if (path)
1526 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001527 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001528}
1529
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001530static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1531 struct fuse_file_info *fi)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001532{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001533 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001534 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001535 char *buf;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001536 int res;
1537
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001538 buf = (char *) malloc(size);
1539 if (buf == NULL) {
1540 reply_err(req, -ENOMEM);
1541 return;
1542 }
1543
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001544 res = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001545 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001546 path = get_path(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001547 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001548 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001549 printf("READ[%llu] %lu bytes from %llu\n",
1550 (unsigned long long) fi->fh, (unsigned long) size,
1551 (unsigned long long) off);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001552 fflush(stdout);
1553 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001554
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001555 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001556 if (f->op.read) {
1557 struct fuse_intr_data d;
1558 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001559 res = f->op.read(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001560 fuse_finish_interrupt(f, req, &d);
1561 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001562 free(path);
1563 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001564 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001565
1566 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001567 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001568 printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
1569 res);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001570 fflush(stdout);
1571 }
Miklos Szeredif412d072005-10-14 21:24:32 +00001572 if ((size_t) res > size)
1573 fprintf(stderr, "fuse: read too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001574 fuse_reply_buf(req, buf, res);
1575 } else
1576 reply_err(req, res);
1577
1578 free(buf);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001579}
1580
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001581static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1582 size_t size, off_t off, struct fuse_file_info *fi)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001583{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001584 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001585 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001586 int res;
1587
1588 res = -ENOENT;
1589 pthread_rwlock_rdlock(&f->tree_lock);
1590 path = get_path(f, ino);
1591 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001592 if (f->conf.debug) {
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001593 printf("WRITE%s[%llu] %lu bytes to %llu\n",
Miklos Szeredi3a770472005-11-11 21:32:42 +00001594 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
Miklos Szeredia039f8f2006-02-24 16:21:58 +00001595 (unsigned long) size, (unsigned long long) off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001596 fflush(stdout);
1597 }
1598
1599 res = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001600 if (f->op.write) {
1601 struct fuse_intr_data d;
1602 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001603 res = f->op.write(path, buf, size, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001604 fuse_finish_interrupt(f, req, &d);
1605 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001606 free(path);
1607 }
1608 pthread_rwlock_unlock(&f->tree_lock);
1609
Miklos Szeredif412d072005-10-14 21:24:32 +00001610 if (res >= 0) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001611 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001612 printf(" WRITE%s[%llu] %u bytes\n",
1613 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1614 res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001615 fflush(stdout);
1616 }
1617 if ((size_t) res > size)
1618 fprintf(stderr, "fuse: wrote too many bytes");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001619 fuse_reply_write(req, res);
Miklos Szeredif412d072005-10-14 21:24:32 +00001620 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001621 reply_err(req, res);
1622}
1623
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001624static void fuse_release(fuse_req_t req, fuse_ino_t ino,
1625 struct fuse_file_info *fi)
1626{
1627 struct fuse *f = req_fuse_prepare(req);
1628 char *path;
1629 struct node *node;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001630 int unlink_hidden = 0;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001631
Miklos Szerediaa8258e2006-02-25 14:42:03 +00001632 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001633 path = get_path(f, ino);
Miklos Szeredi659743b2005-12-09 17:41:42 +00001634 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001635 printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
1636 fi->flags);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001637 fflush(stdout);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001638 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001639 if (f->op.release)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001640 fuse_compat_release(f, req, path, fi);
Miklos Szeredie5183742005-02-02 11:14:04 +00001641
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001642 pthread_mutex_lock(&f->lock);
1643 node = get_node(f, ino);
1644 assert(node->open_count > 0);
1645 --node->open_count;
Miklos Szeredic3b76812006-09-16 08:52:09 +00001646 if (node->is_hidden && !node->open_count) {
1647 unlink_hidden = 1;
1648 node->is_hidden = 0;
1649 }
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00001650 pthread_mutex_unlock(&f->lock);
1651
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001652 if(unlink_hidden && path)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001653 fuse_do_unlink(f, req, path);
Miklos Szeredie5183742005-02-02 11:14:04 +00001654
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001655 if (path)
1656 free(path);
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001657 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001658
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001659 reply_err(req, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001660}
1661
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001662static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
1663 struct fuse_file_info *fi)
Miklos Szeredi5e183482001-10-31 14:52:35 +00001664{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001665 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001666 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001667 int err;
Miklos Szerediab974562005-04-07 15:40:21 +00001668
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001669 err = -ENOENT;
1670 pthread_rwlock_rdlock(&f->tree_lock);
1671 path = get_path(f, ino);
1672 if (path != NULL) {
Miklos Szeredi659743b2005-12-09 17:41:42 +00001673 if (f->conf.debug) {
Miklos Szeredi3a770472005-11-11 21:32:42 +00001674 printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001675 fflush(stdout);
1676 }
1677 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001678 if (f->op.fsync) {
1679 struct fuse_intr_data d;
1680 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001681 err = f->op.fsync(path, datasync, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001682 fuse_finish_interrupt(f, req, &d);
1683 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001684 free(path);
1685 }
1686 pthread_rwlock_unlock(&f->tree_lock);
1687 reply_err(req, err);
1688}
1689
1690static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
1691 struct fuse_file_info *fi)
1692{
Miklos Szeredi3a770472005-11-11 21:32:42 +00001693 struct fuse_dirhandle *dh = (struct fuse_dirhandle *) (uintptr_t) llfi->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001694 memset(fi, 0, sizeof(struct fuse_file_info));
1695 fi->fh = dh->fh;
Miklos Szerediead7f102005-11-28 16:02:27 +00001696 fi->fh_old = dh->fh;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001697 return dh;
1698}
1699
1700static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1701 struct fuse_file_info *llfi)
1702{
1703 struct fuse *f = req_fuse_prepare(req);
1704 struct fuse_dirhandle *dh;
1705
1706 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1707 if (dh == NULL) {
1708 reply_err(req, -ENOMEM);
Miklos Szerediab974562005-04-07 15:40:21 +00001709 return;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001710 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001711 memset(dh, 0, sizeof(struct fuse_dirhandle));
1712 dh->fuse = f;
1713 dh->contents = NULL;
1714 dh->len = 0;
1715 dh->filled = 0;
1716 dh->nodeid = ino;
Miklos Szeredi38f152c2006-09-03 18:28:52 +00001717 fuse_mutex_init(&dh->lock);
Miklos Szerediab974562005-04-07 15:40:21 +00001718
Miklos Szeredi3a770472005-11-11 21:32:42 +00001719 llfi->fh = (uintptr_t) dh;
Miklos Szerediab974562005-04-07 15:40:21 +00001720
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001721 if (f->op.opendir) {
1722 struct fuse_file_info fi;
1723 char *path;
1724 int err;
1725
1726 memset(&fi, 0, sizeof(fi));
1727 fi.flags = llfi->flags;
1728
1729 err = -ENOENT;
1730 pthread_rwlock_rdlock(&f->tree_lock);
1731 path = get_path(f, ino);
1732 if (path != NULL) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001733 err = fuse_compat_opendir(f, req, path, &fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00001734 dh->fh = fi.fh;
Miklos Szerediab974562005-04-07 15:40:21 +00001735 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001736 if (!err) {
1737 pthread_mutex_lock(&f->lock);
1738 if (fuse_reply_open(req, llfi) == -ENOENT) {
1739 /* The opendir syscall was interrupted, so it must be
1740 cancelled */
1741 if(f->op.releasedir)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001742 fuse_do_releasedir(f, req, path, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001743 pthread_mutex_destroy(&dh->lock);
1744 free(dh);
1745 }
1746 pthread_mutex_unlock(&f->lock);
1747 } else {
1748 reply_err(req, err);
1749 free(dh);
1750 }
Miklos Szerediab974562005-04-07 15:40:21 +00001751 free(path);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001752 pthread_rwlock_unlock(&f->tree_lock);
1753 } else
1754 fuse_reply_open(req, llfi);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001755}
Miklos Szeredib483c932001-10-29 14:57:57 +00001756
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001757static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
1758{
1759 if (minsize > dh->size) {
1760 char *newptr;
1761 unsigned newsize = dh->size;
1762 if (!newsize)
1763 newsize = 1024;
1764 while (newsize < minsize)
1765 newsize *= 2;
1766
1767 newptr = (char *) realloc(dh->contents, newsize);
1768 if (!newptr) {
1769 dh->error = -ENOMEM;
1770 return -1;
1771 }
1772 dh->contents = newptr;
1773 dh->size = newsize;
1774 }
1775 return 0;
1776}
1777
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001778static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001779 const struct stat *statp, off_t off)
Miklos Szeredia181e612001-11-06 12:03:23 +00001780{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001781 struct stat stbuf;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001782 size_t newlen;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001783
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001784 if (statp)
1785 stbuf = *statp;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001786 else {
1787 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001788 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001789 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001790
Miklos Szeredi659743b2005-12-09 17:41:42 +00001791 if (!dh->fuse->conf.use_ino) {
Miklos Szeredie248e4b2005-12-14 16:18:32 +00001792 stbuf.st_ino = FUSE_UNKNOWN_INO;
Miklos Szeredi659743b2005-12-09 17:41:42 +00001793 if (dh->fuse->conf.readdir_ino) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001794 struct node *node;
1795 pthread_mutex_lock(&dh->fuse->lock);
1796 node = lookup_node(dh->fuse, dh->nodeid, name);
1797 if (node)
1798 stbuf.st_ino = (ino_t) node->nodeid;
1799 pthread_mutex_unlock(&dh->fuse->lock);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001800 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001801 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001802
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001803 if (off) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001804 if (extend_contents(dh, dh->needlen) == -1)
1805 return 1;
1806
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001807 dh->filled = 0;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001808 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
1809 dh->needlen - dh->len, name,
1810 &stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001811 if (newlen > dh->needlen)
1812 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001813 } else {
1814 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
1815 if (extend_contents(dh, newlen) == -1)
Miklos Szeredic4c12ae2005-10-20 14:48:50 +00001816 return 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001817
1818 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
1819 name, &stbuf, newlen);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001820 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001821 dh->len = newlen;
1822 return 0;
1823}
1824
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001825static int fill_dir(void *buf, const char *name, const struct stat *stbuf,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001826 off_t off)
1827{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +00001828 return fill_dir_common((struct fuse_dirhandle *) buf, name, stbuf, off);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001829}
1830
1831static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1832 ino_t ino)
1833{
1834 struct stat stbuf;
1835
1836 memset(&stbuf, 0, sizeof(stbuf));
1837 stbuf.st_mode = type << 12;
1838 stbuf.st_ino = ino;
1839
1840 fill_dir_common(dh, name, &stbuf, 0);
1841 return dh->error;
1842}
1843
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001844static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
1845 size_t size, off_t off, struct fuse_dirhandle *dh,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001846 struct fuse_file_info *fi)
1847{
1848 int err = -ENOENT;
1849 char *path;
1850 pthread_rwlock_rdlock(&f->tree_lock);
1851 path = get_path(f, ino);
1852 if (path != NULL) {
1853 dh->len = 0;
1854 dh->error = 0;
1855 dh->needlen = size;
1856 dh->filled = 1;
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001857 dh->req = req;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001858 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001859 if (f->op.readdir) {
1860 struct fuse_intr_data d;
1861 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001862 err = f->op.readdir(path, dh, fill_dir, off, fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001863 fuse_finish_interrupt(f, req, &d);
1864 } else if (f->op.getdir) {
1865 struct fuse_intr_data d;
1866 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001867 err = f->op.getdir(path, dh, fill_dir_old);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001868 fuse_finish_interrupt(f, req, &d);
1869 }
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001870 dh->req = NULL;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001871 if (!err)
1872 err = dh->error;
1873 if (err)
1874 dh->filled = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001875 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001876 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00001877 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001878 return err;
1879}
Miklos Szeredie5183742005-02-02 11:14:04 +00001880
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001881static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1882 off_t off, struct fuse_file_info *llfi)
1883{
1884 struct fuse *f = req_fuse_prepare(req);
1885 struct fuse_file_info fi;
1886 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1887
1888 pthread_mutex_lock(&dh->lock);
Miklos Szeredi77ccf652005-08-19 14:40:27 +00001889 /* According to SUS, directory contents need to be refreshed on
1890 rewinddir() */
1891 if (!off)
1892 dh->filled = 0;
1893
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001894 if (!dh->filled) {
Miklos Szeredi1bf64f42006-02-17 15:49:25 +00001895 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001896 if (err) {
1897 reply_err(req, err);
1898 goto out;
1899 }
Miklos Szeredia181e612001-11-06 12:03:23 +00001900 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001901 if (dh->filled) {
1902 if (off < dh->len) {
1903 if (off + size > dh->len)
1904 size = dh->len - off;
1905 } else
1906 size = 0;
1907 } else {
1908 size = dh->len;
1909 off = 0;
1910 }
1911 fuse_reply_buf(req, dh->contents + off, size);
1912 out:
1913 pthread_mutex_unlock(&dh->lock);
1914}
Miklos Szeredia181e612001-11-06 12:03:23 +00001915
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001916static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
1917 struct fuse_file_info *llfi)
1918{
1919 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi9b813af2005-07-21 07:59:37 +00001920 struct fuse_file_info fi;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001921 struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
1922 if (f->op.releasedir) {
1923 char *path;
1924
1925 pthread_rwlock_rdlock(&f->tree_lock);
1926 path = get_path(f, ino);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001927 fuse_do_releasedir(f, req, path ? path : "-", &fi);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001928 free(path);
1929 pthread_rwlock_unlock(&f->tree_lock);
1930 }
1931 pthread_mutex_lock(&dh->lock);
1932 pthread_mutex_unlock(&dh->lock);
1933 pthread_mutex_destroy(&dh->lock);
1934 free(dh->contents);
1935 free(dh);
1936 reply_err(req, 0);
1937}
1938
1939static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
1940 struct fuse_file_info *llfi)
1941{
1942 struct fuse *f = req_fuse_prepare(req);
1943 struct fuse_file_info fi;
1944 char *path;
1945 int err;
1946
1947 get_dirhandle(llfi, &fi);
1948
1949 err = -ENOENT;
1950 pthread_rwlock_rdlock(&f->tree_lock);
1951 path = get_path(f, ino);
1952 if (path != NULL) {
1953 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001954 if (f->op.fsyncdir) {
1955 struct fuse_intr_data d;
1956 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001957 err = f->op.fsyncdir(path, datasync, &fi);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001958 fuse_finish_interrupt(f, req, &d);
1959 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001960 free(path);
1961 }
1962 pthread_rwlock_unlock(&f->tree_lock);
1963 reply_err(req, err);
Miklos Szeredia181e612001-11-06 12:03:23 +00001964}
1965
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001966static int default_statfs(struct statvfs *buf)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001967{
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001968 buf->f_namemax = 255;
Miklos Szeredi77f39942004-03-25 11:17:52 +00001969 buf->f_bsize = 512;
1970 return 0;
1971}
1972
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001973static void fuse_statfs(fuse_req_t req, fuse_ino_t ino)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001974{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001975 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001976 struct statvfs buf;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001977 int err;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001978
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001979 memset(&buf, 0, sizeof(buf));
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001980 if (f->op.statfs) {
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001981 if (ino && (!f->compat || f->compat >= 26)) {
1982 char *path;
1983 pthread_rwlock_rdlock(&f->tree_lock);
1984 err = -ENOENT;
1985 path = get_path(f, ino);
1986 if (path) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001987 err = fuse_do_statfs(f, req, path, &buf);
Miklos Szeredi3ded1a32006-08-18 18:43:50 +00001988 free(path);
1989 }
1990 pthread_rwlock_unlock(&f->tree_lock);
1991 } else
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00001992 err = fuse_compat_statfs(f, req, &buf);
Miklos Szeredi52cb09d2005-11-07 11:59:00 +00001993 } else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001994 err = default_statfs(&buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001995
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001996 if (!err)
1997 fuse_reply_statfs(req, &buf);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001998 else
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001999 reply_err(req, err);
Miklos Szeredi03cebae2004-03-31 10:19:18 +00002000}
2001
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002002static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2003 const char *value, size_t size, int flags)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002004{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002005 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002006 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002007 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002008
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002009 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002010 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002011 path = get_path(f, ino);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00002012 if (path != NULL) {
Miklos Szerediab974562005-04-07 15:40:21 +00002013 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002014 if (f->op.setxattr) {
2015 struct fuse_intr_data d;
2016 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002017 err = f->op.setxattr(path, name, value, size, flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002018 fuse_finish_interrupt(f, req, &d);
2019 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002020 free(path);
2021 }
2022 pthread_rwlock_unlock(&f->tree_lock);
2023 reply_err(req, err);
2024}
2025
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002026static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2027 const char *name, char *value, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002028{
2029 int err;
2030 char *path;
2031
2032 err = -ENOENT;
2033 pthread_rwlock_rdlock(&f->tree_lock);
2034 path = get_path(f, ino);
2035 if (path != NULL) {
2036 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002037 if (f->op.getxattr) {
2038 struct fuse_intr_data d;
2039 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002040 err = f->op.getxattr(path, name, value, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002041 fuse_finish_interrupt(f, req, &d);
2042 }
Miklos Szerediab974562005-04-07 15:40:21 +00002043 free(path);
2044 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002045 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szerediab974562005-04-07 15:40:21 +00002046 return err;
2047}
2048
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002049static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2050 size_t size)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002051{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002052 struct fuse *f = req_fuse_prepare(req);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002053 int res;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002054
2055 if (size) {
2056 char *value = (char *) malloc(size);
2057 if (value == NULL) {
2058 reply_err(req, -ENOMEM);
2059 return;
2060 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002061 res = common_getxattr(f, req, ino, name, value, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002062 if (res > 0)
2063 fuse_reply_buf(req, value, res);
2064 else
2065 reply_err(req, res);
2066 free(value);
2067 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002068 res = common_getxattr(f, req, ino, name, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002069 if (res >= 0)
2070 fuse_reply_xattr(req, res);
2071 else
2072 reply_err(req, res);
2073 }
2074}
2075
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002076static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2077 char *list, size_t size)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002078{
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002079 char *path;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002080 int err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002081
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002082 err = -ENOENT;
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002083 pthread_rwlock_rdlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002084 path = get_path(f, ino);
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002085 if (path != NULL) {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002086 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002087 if (f->op.listxattr) {
2088 struct fuse_intr_data d;
2089 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002090 err = f->op.listxattr(path, list, size);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002091 fuse_finish_interrupt(f, req, &d);
2092 }
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002093 free(path);
2094 }
Miklos Szeredic2a33ee2005-05-09 13:29:17 +00002095 pthread_rwlock_unlock(&f->tree_lock);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002096 return err;
Miklos Szeredi4283ee72005-03-21 12:09:04 +00002097}
Miklos Szeredi3ead28e2005-01-18 21:23:41 +00002098
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002099static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
Miklos Szeredi43696432001-11-18 19:15:05 +00002100{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002101 struct fuse *f = req_fuse_prepare(req);
2102 int res;
2103
2104 if (size) {
2105 char *list = (char *) malloc(size);
2106 if (list == NULL) {
2107 reply_err(req, -ENOMEM);
2108 return;
2109 }
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002110 res = common_listxattr(f, req, ino, list, size);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002111 if (res > 0)
2112 fuse_reply_buf(req, list, res);
2113 else
2114 reply_err(req, res);
2115 free(list);
2116 } else {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002117 res = common_listxattr(f, req, ino, NULL, 0);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002118 if (res >= 0)
2119 fuse_reply_xattr(req, res);
2120 else
2121 reply_err(req, res);
2122 }
Miklos Szeredi43696432001-11-18 19:15:05 +00002123}
2124
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002125static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
2126{
2127 struct fuse *f = req_fuse_prepare(req);
2128 char *path;
2129 int err;
2130
2131 err = -ENOENT;
2132 pthread_rwlock_rdlock(&f->tree_lock);
2133 path = get_path(f, ino);
2134 if (path != NULL) {
2135 err = -ENOSYS;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002136 if (f->op.removexattr) {
2137 struct fuse_intr_data d;
2138 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002139 err = f->op.removexattr(path, name);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002140 fuse_finish_interrupt(f, req, &d);
2141 }
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002142 free(path);
2143 }
2144 pthread_rwlock_unlock(&f->tree_lock);
2145 reply_err(req, err);
2146}
2147
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002148static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2149{
2150 struct lock *l;
2151
2152 for (l = node->locks; l; l = l->next)
2153 if (l->owner != lock->owner &&
2154 lock->start <= l->end && l->start <= lock->end &&
2155 (l->type == F_WRLCK || lock->type == F_WRLCK))
2156 break;
2157
2158 return l;
2159}
2160
2161static void delete_lock(struct lock **lockp)
2162{
2163 struct lock *l = *lockp;
2164 *lockp = l->next;
2165 free(l);
2166}
2167
2168static void insert_lock(struct lock **pos, struct lock *lock)
2169{
2170 lock->next = *pos;
2171 *pos = lock;
2172}
2173
2174static int locks_insert(struct node *node, struct lock *lock)
2175{
2176 struct lock **lp;
2177 struct lock *newl1 = NULL;
2178 struct lock *newl2 = NULL;
2179
2180 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2181 newl1 = malloc(sizeof(struct lock));
2182 newl2 = malloc(sizeof(struct lock));
2183
2184 if (!newl1 || !newl2) {
2185 free(newl1);
2186 free(newl2);
2187 return -ENOLCK;
2188 }
2189 }
2190
2191 for (lp = &node->locks; *lp;) {
2192 struct lock *l = *lp;
2193 if (l->owner != lock->owner)
2194 goto skip;
2195
2196 if (lock->type == l->type) {
2197 if (l->end < lock->start - 1)
2198 goto skip;
2199 if (lock->end < l->start - 1)
2200 break;
2201 if (l->start <= lock->start && lock->end <= l->end)
2202 goto out;
2203 if (l->start < lock->start)
2204 lock->start = l->start;
2205 if (lock->end < l->end)
2206 lock->end = l->end;
2207 goto delete;
2208 } else {
2209 if (l->end < lock->start)
2210 goto skip;
2211 if (lock->end < l->start)
2212 break;
2213 if (lock->start <= l->start && l->end <= lock->end)
2214 goto delete;
2215 if (l->end <= lock->end) {
2216 l->end = lock->start - 1;
2217 goto skip;
2218 }
2219 if (lock->start <= l->start) {
2220 l->start = lock->end + 1;
2221 break;
2222 }
2223 *newl2 = *l;
2224 newl2->start = lock->end + 1;
2225 l->end = lock->start - 1;
2226 insert_lock(&l->next, newl2);
2227 newl2 = NULL;
2228 }
2229 skip:
2230 lp = &l->next;
2231 continue;
2232
2233 delete:
2234 delete_lock(lp);
2235 }
2236 if (lock->type != F_UNLCK) {
2237 *newl1 = *lock;
2238 insert_lock(lp, newl1);
2239 newl1 = NULL;
2240 }
2241out:
2242 free(newl1);
2243 free(newl2);
2244 return 0;
2245}
2246
2247static void flock_to_lock(struct flock *flock, struct lock *lock)
2248{
2249 memset(lock, 0, sizeof(struct lock));
2250 lock->type = flock->l_type;
2251 lock->start = flock->l_start;
2252 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2253 lock->pid = flock->l_pid;
2254}
2255
2256static void lock_to_flock(struct lock *lock, struct flock *flock)
2257{
2258 flock->l_type = lock->type;
2259 flock->l_start = lock->start;
2260 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2261 flock->l_pid = lock->pid;
2262}
2263
2264static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002265 struct fuse_file_info *fi)
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002266{
2267 struct fuse *f = req_fuse_prepare(req);
2268 char *path;
2269 int err;
2270
2271 err = -ENOENT;
2272 pthread_rwlock_rdlock(&f->tree_lock);
2273 path = get_path(f, ino);
2274 if (path != NULL) {
2275 if (f->conf.debug) {
2276 printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
2277 fflush(stdout);
2278 }
2279 err = -ENOSYS;
2280 if (f->op.flush) {
2281 struct fuse_intr_data d;
2282 fuse_prepare_interrupt(f, req, &d);
2283 err = f->op.flush(path, fi);
2284 fuse_finish_interrupt(f, req, &d);
2285 }
2286 free(path);
2287 }
2288 if (f->op.lock) {
2289 struct flock lock;
2290 struct lock l;
2291 memset(&lock, 0, sizeof(lock));
2292 lock.l_type = F_UNLCK;
2293 lock.l_whence = SEEK_SET;
Miklos Szeredi07407852006-09-30 20:03:52 +00002294 fuse_do_lock(f, req, path, fi, F_SETLK, &lock);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002295 flock_to_lock(&lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002296 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002297 pthread_mutex_lock(&f->lock);
2298 locks_insert(get_node(f, ino), &l);
2299 pthread_mutex_unlock(&f->lock);
2300
2301 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2302 if (err == -ENOSYS)
2303 err = 0;
2304 }
2305 pthread_rwlock_unlock(&f->tree_lock);
2306 reply_err(req, err);
2307}
2308
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002309static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2310 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002311 int cmd)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002312{
2313 struct fuse *f = req_fuse_prepare(req);
2314 char *path;
2315 int err;
2316
2317 err = -ENOENT;
2318 pthread_rwlock_rdlock(&f->tree_lock);
2319 path = get_path(f, ino);
2320 if (path != NULL) {
Miklos Szeredi07407852006-09-30 20:03:52 +00002321 err = fuse_do_lock(f, req, path, fi, cmd, lock);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002322 free(path);
2323 }
2324 pthread_rwlock_unlock(&f->tree_lock);
2325 return err;
2326}
2327
2328static void fuse_getlk(fuse_req_t req, fuse_ino_t ino,
Miklos Szeredi07407852006-09-30 20:03:52 +00002329 struct fuse_file_info *fi, struct flock *lock)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002330{
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002331 int err;
2332 struct lock l;
2333 struct lock *conflict;
2334 struct fuse *f = req_fuse(req);
2335
2336 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002337 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002338 pthread_mutex_lock(&f->lock);
2339 conflict = locks_conflict(get_node(f, ino), &l);
2340 if (conflict)
2341 lock_to_flock(conflict, lock);
2342 pthread_mutex_unlock(&f->lock);
2343 if (!conflict)
Miklos Szeredi07407852006-09-30 20:03:52 +00002344 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002345 else
2346 err = 0;
2347
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002348 if (!err)
2349 fuse_reply_lock(req, lock);
2350 else
2351 reply_err(req, err);
2352}
2353
2354static void fuse_setlk(fuse_req_t req, fuse_ino_t ino,
2355 struct fuse_file_info *fi, struct flock *lock,
Miklos Szeredi07407852006-09-30 20:03:52 +00002356 int sleep)
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002357{
Miklos Szeredi07407852006-09-30 20:03:52 +00002358 int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK);
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002359 if (!err) {
2360 struct fuse *f = req_fuse(req);
2361 struct lock l;
2362 flock_to_lock(lock, &l);
Miklos Szeredi07407852006-09-30 20:03:52 +00002363 l.owner = fi->lock_owner;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002364 pthread_mutex_lock(&f->lock);
2365 locks_insert(get_node(f, ino), &l);
2366 pthread_mutex_unlock(&f->lock);
2367 }
2368 reply_err(req, err);
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002369}
2370
Miklos Szeredi708b4812006-09-30 16:02:25 +00002371static void fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2372 uint64_t idx)
2373{
2374 struct fuse *f = req_fuse_prepare(req);
2375 char *path;
2376 int err;
2377
2378 err = -ENOENT;
2379 pthread_rwlock_rdlock(&f->tree_lock);
2380 path = get_path(f, ino);
2381 if (path != NULL) {
2382 err = -ENOSYS;
2383 if (f->op.bmap)
2384 err = f->op.bmap(path, blocksize, &idx);
2385 free(path);
2386 }
2387 pthread_rwlock_unlock(&f->tree_lock);
2388 if (!err)
2389 fuse_reply_bmap(req, idx);
2390 else
2391 reply_err(req, err);
2392}
2393
Miklos Szeredia1482422005-08-14 23:00:27 +00002394static struct fuse_lowlevel_ops fuse_path_ops = {
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002395 .init = fuse_data_init,
2396 .destroy = fuse_data_destroy,
2397 .lookup = fuse_lookup,
2398 .forget = fuse_forget,
2399 .getattr = fuse_getattr,
2400 .setattr = fuse_setattr,
Miklos Szeredib0b13d12005-10-26 12:53:25 +00002401 .access = fuse_access,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002402 .readlink = fuse_readlink,
2403 .mknod = fuse_mknod,
2404 .mkdir = fuse_mkdir,
2405 .unlink = fuse_unlink,
2406 .rmdir = fuse_rmdir,
2407 .symlink = fuse_symlink,
2408 .rename = fuse_rename,
2409 .link = fuse_link,
Miklos Szeredid9079a72005-10-26 15:29:06 +00002410 .create = fuse_create,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002411 .open = fuse_open,
2412 .read = fuse_read,
2413 .write = fuse_write,
2414 .flush = fuse_flush,
2415 .release = fuse_release,
2416 .fsync = fuse_fsync,
2417 .opendir = fuse_opendir,
2418 .readdir = fuse_readdir,
2419 .releasedir = fuse_releasedir,
2420 .fsyncdir = fuse_fsyncdir,
2421 .statfs = fuse_statfs,
2422 .setxattr = fuse_setxattr,
2423 .getxattr = fuse_getxattr,
2424 .listxattr = fuse_listxattr,
2425 .removexattr = fuse_removexattr,
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002426 .getlk = fuse_getlk,
2427 .setlk = fuse_setlk,
Miklos Szeredi708b4812006-09-30 16:02:25 +00002428 .bmap = fuse_bmap,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002429};
2430
Miklos Szeredia1482422005-08-14 23:00:27 +00002431static void free_cmd(struct fuse_cmd *cmd)
2432{
2433 free(cmd->buf);
2434 free(cmd);
2435}
2436
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002437void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00002438{
Miklos Szeredi178451d2005-08-15 13:19:07 +00002439 fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch);
Miklos Szeredifa829b52005-12-02 11:05:41 +00002440 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00002441}
2442
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002443int fuse_exited(struct fuse *f)
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002444{
Miklos Szeredia1482422005-08-14 23:00:27 +00002445 return fuse_session_exited(f->se);
2446}
2447
2448struct fuse_session *fuse_get_session(struct fuse *f)
2449{
2450 return f->se;
2451}
2452
2453static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
2454{
2455 struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
2456 if (cmd == NULL) {
2457 fprintf(stderr, "fuse: failed to allocate cmd\n");
2458 return NULL;
2459 }
2460 cmd->buf = (char *) malloc(bufsize);
2461 if (cmd->buf == NULL) {
2462 fprintf(stderr, "fuse: failed to allocate read buffer\n");
2463 free(cmd);
2464 return NULL;
2465 }
2466 return cmd;
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00002467}
2468
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002469struct fuse_cmd *fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002470{
Miklos Szeredia1482422005-08-14 23:00:27 +00002471 struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
2472 size_t bufsize = fuse_chan_bufsize(ch);
2473 struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
2474 if (cmd != NULL) {
Miklos Szeredi8d975f62006-03-17 15:56:05 +00002475 int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
Miklos Szeredia1482422005-08-14 23:00:27 +00002476 if (res <= 0) {
2477 free_cmd(cmd);
Miklos Szeredi5d9ce362006-03-01 12:10:13 +00002478 if (res < 0 && res != -EINTR && res != -EAGAIN)
Miklos Szeredifa829b52005-12-02 11:05:41 +00002479 fuse_exit(f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002480 return NULL;
2481 }
2482 cmd->buflen = res;
Miklos Szeredi178451d2005-08-15 13:19:07 +00002483 cmd->ch = ch;
Miklos Szeredia1482422005-08-14 23:00:27 +00002484 }
2485 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002486}
2487
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002488int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002489{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002490 if (f)
Miklos Szeredia1482422005-08-14 23:00:27 +00002491 return fuse_session_loop(f->se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002492 else
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002493 return -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002494}
2495
Miklos Szeredi891b8742004-07-29 09:27:49 +00002496int fuse_invalidate(struct fuse *f, const char *path)
2497{
Miklos Szeredie56818b2004-12-12 11:45:24 +00002498 (void) f;
2499 (void) path;
2500 return -EINVAL;
Miklos Szeredi891b8742004-07-29 09:27:49 +00002501}
2502
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002503void fuse_exit(struct fuse *f)
2504{
Miklos Szeredia1482422005-08-14 23:00:27 +00002505 fuse_session_exit(f->se);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00002506}
2507
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002508struct fuse_context *fuse_get_context(void)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002509{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002510 return &fuse_get_context_internal()->ctx;
2511}
2512
2513int fuse_interrupted(void)
2514{
2515 return fuse_req_interrupted(fuse_get_context_internal()->req);
Miklos Szeredid169f312004-09-22 08:48:26 +00002516}
2517
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002518void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
Miklos Szeredid169f312004-09-22 08:48:26 +00002519{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002520 (void) func;
2521 /* no-op */
Miklos Szeredi2e50d432001-12-20 12:17:25 +00002522}
2523
Miklos Szerediad005972006-01-07 10:14:34 +00002524enum {
2525 KEY_HELP,
Miklos Szerediad005972006-01-07 10:14:34 +00002526};
2527
Miklos Szeredi659743b2005-12-09 17:41:42 +00002528#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2529
2530static const struct fuse_opt fuse_lib_opts[] = {
Miklos Szerediad005972006-01-07 10:14:34 +00002531 FUSE_OPT_KEY("-h", KEY_HELP),
2532 FUSE_OPT_KEY("--help", KEY_HELP),
Miklos Szeredi065f2222006-01-20 15:15:21 +00002533 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2534 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002535 FUSE_LIB_OPT("debug", debug, 1),
Miklos Szeredi95da8602006-01-06 18:29:40 +00002536 FUSE_LIB_OPT("-d", debug, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002537 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2538 FUSE_LIB_OPT("use_ino", use_ino, 1),
2539 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2540 FUSE_LIB_OPT("direct_io", direct_io, 1),
2541 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
Miklos Szeredi320abe42006-01-30 18:14:51 +00002542 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2543 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002544 FUSE_LIB_OPT("umask=", set_mode, 1),
2545 FUSE_LIB_OPT("umask=%o", umask, 0),
2546 FUSE_LIB_OPT("uid=", set_uid, 1),
2547 FUSE_LIB_OPT("uid=%d", uid, 0),
2548 FUSE_LIB_OPT("gid=", set_gid, 1),
2549 FUSE_LIB_OPT("gid=%d", gid, 0),
2550 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2551 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002552 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2553 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002554 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002555 FUSE_LIB_OPT("intr", intr, 1),
2556 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
Miklos Szeredi659743b2005-12-09 17:41:42 +00002557 FUSE_OPT_END
2558};
2559
Miklos Szerediad005972006-01-07 10:14:34 +00002560static void fuse_lib_help(void)
2561{
2562 fprintf(stderr,
Miklos Szeredi06091462006-02-16 16:38:34 +00002563" -o hard_remove immediate removal (don't hide files)\n"
2564" -o use_ino let filesystem set inode numbers\n"
2565" -o readdir_ino try to fill in d_ino in readdir\n"
2566" -o direct_io use direct I/O\n"
2567" -o kernel_cache cache files in kernel\n"
2568" -o [no]auto_cache enable caching based on modification times\n"
2569" -o umask=M set file permissions (octal)\n"
2570" -o uid=N set file owner\n"
2571" -o gid=N set file group\n"
2572" -o entry_timeout=T cache timeout for names (1.0s)\n"
2573" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002574" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2575" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002576" -o intr allow requests to be interrupted\n"
2577" -o intr_signal=NUM signal to send on interrupt (%i)\n"
2578"\n", FUSE_DEFAULT_INTR_SIGNAL);
Miklos Szerediad005972006-01-07 10:14:34 +00002579}
2580
2581static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2582 struct fuse_args *outargs)
2583{
2584 (void) data; (void) arg; (void) outargs;
2585
2586 if (key == KEY_HELP)
2587 fuse_lib_help();
2588
2589 return 1;
2590}
2591
2592
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002593int fuse_is_lib_option(const char *opt)
2594{
Miklos Szeredi659743b2005-12-09 17:41:42 +00002595 return fuse_lowlevel_is_lib_option(opt) ||
2596 fuse_opt_match(fuse_lib_opts, opt);
Miklos Szeredibd7661b2004-07-23 17:16:29 +00002597}
2598
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002599static int fuse_init_intr_signal(int signum, int *installed)
2600{
2601 struct sigaction old_sa;
2602
2603 if (sigaction(signum, NULL, &old_sa) == -1) {
2604 perror("fuse: cannot get old signal handler");
2605 return -1;
2606 }
2607
2608 if (old_sa.sa_handler == SIG_DFL) {
2609 struct sigaction sa;
2610
2611 memset(&sa, 0, sizeof(struct sigaction));
2612 sa.sa_handler = fuse_intr_sighandler;
Miklos Szeredi0c59ebf2006-09-10 20:53:36 +00002613 sigemptyset(&sa.sa_mask);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002614
2615 if (sigaction(signum, &sa, NULL) == -1) {
2616 perror("fuse: cannot set interrupt signal handler");
2617 return -1;
2618 }
2619 *installed = 1;
2620 }
2621 return 0;
2622}
2623
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002624static void fuse_restore_intr_signal(int signum)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002625{
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002626 struct sigaction sa;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002627
Miklos Szeredi349bdda2006-09-07 11:48:16 +00002628 memset(&sa, 0, sizeof(struct sigaction));
2629 sa.sa_handler = SIG_DFL;
2630 sigaction(signum, &sa, NULL);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002631}
2632
Miklos Szeredi6f385412006-03-17 15:05:40 +00002633struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002634 const struct fuse_operations *op,
Miklos Szeredi6f385412006-03-17 15:05:40 +00002635 size_t op_size, void *user_data, int compat)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002636{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002637 struct fuse *f;
2638 struct node *root;
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002639 struct fuse_lowlevel_ops llop = fuse_path_ops;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002640
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002641 if (sizeof(struct fuse_operations) < op_size) {
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002642 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002643 op_size = sizeof(struct fuse_operations);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002644 }
2645
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002646 if (fuse_create_context_key() == -1)
2647 goto out;
2648
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002649 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002650 if (f == NULL) {
2651 fprintf(stderr, "fuse: failed to allocate fuse object\n");
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002652 goto out_delete_context_key;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002653 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +00002654
Miklos Szeredi6f385412006-03-17 15:05:40 +00002655 f->user_data = user_data;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002656 f->conf.entry_timeout = 1.0;
2657 f->conf.attr_timeout = 1.0;
2658 f->conf.negative_timeout = 0.0;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002659 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
Miklos Szeredi6c0209a2005-08-02 13:31:28 +00002660
Miklos Szerediad005972006-01-07 10:14:34 +00002661 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
Miklos Szeredi659743b2005-12-09 17:41:42 +00002662 goto out_free;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002663
Miklos Szeredi6e806e92006-02-16 16:59:39 +00002664 if (!f->conf.ac_attr_timeout_set)
2665 f->conf.ac_attr_timeout = f->conf.attr_timeout;
2666
Miklos Szeredi659743b2005-12-09 17:41:42 +00002667#ifdef __FreeBSD__
2668 /*
2669 * In FreeBSD, we always use these settings as inode numbers are needed to
2670 * make getcwd(3) work.
2671 */
Miklos Szeredi76fc3de2005-12-12 09:34:45 +00002672 f->conf.readdir_ino = 1;
Miklos Szeredi659743b2005-12-09 17:41:42 +00002673#endif
2674
Miklos Szeredi065f2222006-01-20 15:15:21 +00002675 if (compat && compat <= 25) {
2676 if (fuse_sync_compat_args(args) == -1)
2677 goto out_free;
2678 }
2679
Miklos Szeredi9a5c11d2006-07-30 17:33:40 +00002680 memcpy(&f->op, op, op_size);
2681 if (!f->op.lock) {
2682 llop.getlk = NULL;
2683 llop.setlk = NULL;
2684 }
2685
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002686 f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);
Miklos Szeredia1482422005-08-14 23:00:27 +00002687 if (f->se == NULL)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002688 goto out_free;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +00002689
Miklos Szeredia1482422005-08-14 23:00:27 +00002690 fuse_session_add_chan(f->se, ch);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00002691
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002692 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002693 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00002694 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002695 f->name_table_size = 14057;
2696 f->name_table = (struct node **)
2697 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002698 if (f->name_table == NULL) {
2699 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia1482422005-08-14 23:00:27 +00002700 goto out_free_session;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002701 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002702
Miklos Szeredia13d9002004-11-02 17:32:03 +00002703 f->id_table_size = 14057;
2704 f->id_table = (struct node **)
2705 calloc(1, sizeof(struct node *) * f->id_table_size);
Miklos Szeredie56818b2004-12-12 11:45:24 +00002706 if (f->id_table == NULL) {
2707 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002708 goto out_free_name_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002709 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002710
Miklos Szeredi38f152c2006-09-03 18:28:52 +00002711 fuse_mutex_init(&f->lock);
Miklos Szeredid0a777a2006-04-05 07:18:00 +00002712 pthread_rwlock_init(&f->tree_lock, NULL);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002713 f->compat = compat;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002714
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002715 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredie56818b2004-12-12 11:45:24 +00002716 if (root == NULL) {
2717 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredia13d9002004-11-02 17:32:03 +00002718 goto out_free_id_table;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002719 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002720
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002721 root->name = strdup("/");
Miklos Szeredie56818b2004-12-12 11:45:24 +00002722 if (root->name == NULL) {
2723 fprintf(stderr, "fuse: memory allocation failed\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002724 goto out_free_root;
Miklos Szeredie56818b2004-12-12 11:45:24 +00002725 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002726
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002727 if (f->conf.intr &&
2728 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
2729 goto out_free_root_name;
2730
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002731 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002732 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00002733 root->generation = 0;
Miklos Szeredi0f62d722005-01-04 12:45:54 +00002734 root->refctr = 1;
Miklos Szeredi38009022005-05-08 19:47:22 +00002735 root->nlookup = 1;
Miklos Szeredia13d9002004-11-02 17:32:03 +00002736 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002737
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002738 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002739
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002740 out_free_root_name:
2741 free(root->name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002742 out_free_root:
2743 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00002744 out_free_id_table:
2745 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002746 out_free_name_table:
2747 free(f->name_table);
Miklos Szeredia1482422005-08-14 23:00:27 +00002748 out_free_session:
2749 fuse_session_destroy(f->se);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002750 out_free:
2751 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002752 out_delete_context_key:
2753 fuse_delete_context_key();
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002754 out:
Miklos Szeredib2cf9562004-09-16 08:42:40 +00002755 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002756}
2757
Miklos Szeredi6f385412006-03-17 15:05:40 +00002758struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
2759 const struct fuse_operations *op, size_t op_size,
2760 void *user_data)
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002761{
Miklos Szeredi6f385412006-03-17 15:05:40 +00002762 return fuse_new_common(ch, args, op, op_size, user_data, 0);
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002763}
2764
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002765void fuse_destroy(struct fuse *f)
2766{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002767 size_t i;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002768 struct fuse_context_i *c = fuse_get_context_internal();
2769
2770 if (f->conf.intr && f->intr_installed)
2771 fuse_restore_intr_signal(f->conf.intr_signal);
Miklos Szerediad519562006-07-31 11:07:40 +00002772
2773 memset(c, 0, sizeof(*c));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002774 c->ctx.fuse = f;
2775 c->ctx.private_data = f->user_data;
Miklos Szerediad519562006-07-31 11:07:40 +00002776
Miklos Szeredia13d9002004-11-02 17:32:03 +00002777 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002778 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002779
Miklos Szeredia13d9002004-11-02 17:32:03 +00002780 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002781 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00002782 char *path = get_path(f, node->nodeid);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002783 if (path) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002784 f->op.unlink(path);
Miklos Szeredi21019c92005-05-09 11:22:41 +00002785 free(path);
2786 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002787 }
2788 }
2789 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002790 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002791 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002792 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00002793
Miklos Szeredia13d9002004-11-02 17:32:03 +00002794 for (node = f->id_table[i]; node != NULL; node = next) {
2795 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002796 free_node(node);
2797 }
2798 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00002799 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002800 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00002801 pthread_mutex_destroy(&f->lock);
Miklos Szeredi55a84102006-06-06 10:16:38 +00002802 pthread_rwlock_destroy(&f->tree_lock);
Miklos Szeredia1482422005-08-14 23:00:27 +00002803 fuse_session_destroy(f->se);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00002804 free(f);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002805 fuse_delete_context_key();
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00002806}
Miklos Szeredi0b6a0ad2004-12-04 00:40:50 +00002807
Miklos Szeredieafdf422006-09-22 19:30:17 +00002808#include "fuse_common_compat.h"
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002809#include "fuse_compat.h"
2810
Miklos Szeredi6f385412006-03-17 15:05:40 +00002811static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args,
2812 const struct fuse_operations *op,
2813 size_t op_size, int compat)
2814{
2815 struct fuse *f = NULL;
2816 struct fuse_chan *ch = fuse_kern_chan_new(fd);
2817
2818 if (ch)
2819 f = fuse_new_common(ch, args, op, op_size, NULL, compat);
2820
2821 return f;
2822}
2823
Miklos Szeredi065f2222006-01-20 15:15:21 +00002824#ifndef __FreeBSD__
2825
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002826static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2827 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002828{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002829 int err;
2830 struct fuse_intr_data d;
Miklos Szeredi065f2222006-01-20 15:15:21 +00002831 if (!f->compat || f->compat >= 25)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002832 err = fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002833 else if (f->compat == 22) {
Miklos Szeredieafdf422006-09-22 19:30:17 +00002834 struct fuse_file_info_compat tmp;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002835 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002836 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002837 err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002838 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002839 memcpy(fi, &tmp, sizeof(tmp));
2840 fi->fh = tmp.fh;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002841 } else {
2842 fuse_prepare_interrupt(f, req, &d);
2843 err =
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002844 ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002845 fuse_finish_interrupt(f, req, &d);
2846 }
2847 return err;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002848}
2849
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002850static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2851 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002852{
2853 if (!f->compat || f->compat >= 22)
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002854 fuse_do_release(f, req, path ? path : "-", fi);
2855 else if (path) {
2856 struct fuse_intr_data d;
2857 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002858 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002859 fuse_finish_interrupt(f, req, &d);
2860 }
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002861}
2862
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002863static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2864 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002865{
Miklos Szeredi065f2222006-01-20 15:15:21 +00002866 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002867 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002868 } else {
2869 int err;
Miklos Szeredieafdf422006-09-22 19:30:17 +00002870 struct fuse_file_info_compat tmp;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002871 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002872 memcpy(&tmp, fi, sizeof(tmp));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002873 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002874 err = ((struct fuse_operations_compat22 *) &f->op)->opendir(path, &tmp);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002875 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002876 memcpy(fi, &tmp, sizeof(tmp));
2877 fi->fh = tmp.fh;
2878 return err;
2879 }
2880}
2881
2882static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
2883 struct statvfs *stbuf)
2884{
2885 stbuf->f_bsize = compatbuf->block_size;
2886 stbuf->f_blocks = compatbuf->blocks;
2887 stbuf->f_bfree = compatbuf->blocks_free;
2888 stbuf->f_bavail = compatbuf->blocks_free;
2889 stbuf->f_files = compatbuf->files;
2890 stbuf->f_ffree = compatbuf->files_free;
2891 stbuf->f_namemax = compatbuf->namelen;
2892}
2893
2894static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf)
2895{
2896 stbuf->f_bsize = oldbuf->f_bsize;
2897 stbuf->f_blocks = oldbuf->f_blocks;
2898 stbuf->f_bfree = oldbuf->f_bfree;
2899 stbuf->f_bavail = oldbuf->f_bavail;
2900 stbuf->f_files = oldbuf->f_files;
2901 stbuf->f_ffree = oldbuf->f_ffree;
2902 stbuf->f_namemax = oldbuf->f_namelen;
2903}
2904
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002905static int fuse_compat_statfs(struct fuse *f, fuse_req_t req,
2906 struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002907{
2908 int err;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002909 struct fuse_intr_data d;
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002910
Miklos Szeredi065f2222006-01-20 15:15:21 +00002911 if (!f->compat || f->compat >= 25) {
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002912 err = fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002913 } else if (f->compat > 11) {
2914 struct statfs oldbuf;
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002915 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002916 err = ((struct fuse_operations_compat22 *) &f->op)->statfs("/", &oldbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002917 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002918 if (!err)
2919 convert_statfs_old(&oldbuf, buf);
2920 } else {
2921 struct fuse_statfs_compat1 compatbuf;
2922 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002923 fuse_prepare_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002924 err = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002925 fuse_finish_interrupt(f, req, &d);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002926 if (!err)
2927 convert_statfs_compat(&compatbuf, buf);
2928 }
2929 return err;
2930}
2931
Miklos Szeredi95da8602006-01-06 18:29:40 +00002932static struct fuse *fuse_new_common_compat(int fd, const char *opts,
2933 const struct fuse_operations *op,
2934 size_t op_size, int compat)
2935{
2936 struct fuse *f;
2937 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2938
2939 if (opts &&
2940 (fuse_opt_add_arg(&args, "") == -1 ||
2941 fuse_opt_add_arg(&args, "-o") == -1 ||
2942 fuse_opt_add_arg(&args, opts) == -1)) {
2943 fuse_opt_free_args(&args);
2944 return NULL;
2945 }
Miklos Szeredi6f385412006-03-17 15:05:40 +00002946 f = fuse_new_common_compat25(fd, &args, op, op_size, compat);
Miklos Szeredi95da8602006-01-06 18:29:40 +00002947 fuse_opt_free_args(&args);
2948
2949 return f;
2950}
2951
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002952struct fuse *fuse_new_compat22(int fd, const char *opts,
2953 const struct fuse_operations_compat22 *op,
2954 size_t op_size)
2955{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002956 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2957 op_size, 22);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002958}
2959
2960struct fuse *fuse_new_compat2(int fd, const char *opts,
2961 const struct fuse_operations_compat2 *op)
2962{
Miklos Szeredi95da8602006-01-06 18:29:40 +00002963 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2964 sizeof(struct fuse_operations_compat2), 21);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002965}
2966
2967struct fuse *fuse_new_compat1(int fd, int flags,
2968 const struct fuse_operations_compat1 *op)
2969{
2970 const char *opts = NULL;
2971 if (flags & FUSE_DEBUG_COMPAT1)
2972 opts = "debug";
Miklos Szeredi95da8602006-01-06 18:29:40 +00002973 return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op,
2974 sizeof(struct fuse_operations_compat1), 11);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002975}
2976
Miklos Szeredif458b8c2004-12-07 16:46:42 +00002977__asm__(".symver fuse_exited,__fuse_exited@");
2978__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");
2979__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");
2980__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");
2981__asm__(".symver fuse_new_compat2,fuse_new@");
Miklos Szeredi3a770472005-11-11 21:32:42 +00002982__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002983
2984#else /* __FreeBSD__ */
2985
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002986static int fuse_compat_open(struct fuse *f, fuse_req_t req, char *path,
2987 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002988{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002989 return fuse_do_open(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002990}
2991
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002992static void fuse_compat_release(struct fuse *f, fuse_req_t req, char *path,
2993 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002994{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002995 fuse_do_release(f, req, path ? path : "-", fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00002996}
2997
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00002998static int fuse_compat_opendir(struct fuse *f, fuse_req_t req, char *path,
2999 struct fuse_file_info *fi)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003000{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003001 return fuse_do_opendir(f, req, path, fi);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003002}
3003
Csaba Henk3e3a1252006-09-24 14:53:29 +00003004static int fuse_compat_statfs(struct fuse *f, fuse_req_t req, struct statvfs *buf)
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003005{
Miklos Szeredi288ed4e2006-09-07 06:02:44 +00003006 return fuse_do_statfs(f, req, "/", buf);
Miklos Szeredi9c2ccb42005-11-17 17:11:48 +00003007}
3008
3009#endif /* __FreeBSD__ */
Miklos Szeredi065f2222006-01-20 15:15:21 +00003010
3011struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
3012 const struct fuse_operations_compat25 *op,
3013 size_t op_size)
3014{
Miklos Szeredi6f385412006-03-17 15:05:40 +00003015 return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op,
3016 op_size, 25);
Miklos Szeredi065f2222006-01-20 15:15:21 +00003017}
3018
3019__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5");