blob: 6b42252bfcdeb08a6ef0498a7a9f5fd5e433fcc9 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 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 Szeredicb264512004-06-23 18:52:50 +00009#include <config.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000010#include "fuse_i.h"
11#include <linux/fuse.h>
12
13#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000014#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000015#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000016#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000017#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000018#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredi97c61e92001-11-07 12:09:43 +000020#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000021#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023#define ENTRY_REVALIDATE_TIME 1 /* sec */
24#define ATTR_REVALIDATE_TIME 1 /* sec */
25
Miklos Szeredid169f312004-09-22 08:48:26 +000026static struct fuse_context *(*fuse_getcontext)(void) = NULL;
27
Miklos Szeredic8ba2372002-12-10 12:26:00 +000028static const char *opname(enum fuse_opcode opcode)
29{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000030 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000031 case FUSE_LOOKUP: return "LOOKUP";
32 case FUSE_FORGET: return "FORGET";
33 case FUSE_GETATTR: return "GETATTR";
34 case FUSE_SETATTR: return "SETATTR";
35 case FUSE_READLINK: return "READLINK";
36 case FUSE_SYMLINK: return "SYMLINK";
37 case FUSE_GETDIR: return "GETDIR";
38 case FUSE_MKNOD: return "MKNOD";
39 case FUSE_MKDIR: return "MKDIR";
40 case FUSE_UNLINK: return "UNLINK";
41 case FUSE_RMDIR: return "RMDIR";
42 case FUSE_RENAME: return "RENAME";
43 case FUSE_LINK: return "LINK";
44 case FUSE_OPEN: return "OPEN";
45 case FUSE_READ: return "READ";
46 case FUSE_WRITE: return "WRITE";
47 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000048 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000049 case FUSE_RELEASE: return "RELEASE";
50 case FUSE_FSYNC: return "FSYNC";
51 case FUSE_SETXATTR: return "SETXATTR";
52 case FUSE_GETXATTR: return "GETXATTR";
53 case FUSE_LISTXATTR: return "LISTXATTR";
54 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000055 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000056 }
57}
58
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000059
60static inline void dec_avail(struct fuse *f)
61{
62 pthread_mutex_lock(&f->lock);
63 f->numavail --;
64 pthread_mutex_unlock(&f->lock);
65}
66
Miklos Szeredia13d9002004-11-02 17:32:03 +000067static struct node *__get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000068{
Miklos Szeredia13d9002004-11-02 17:32:03 +000069 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000070 struct node *node;
71
Miklos Szeredia13d9002004-11-02 17:32:03 +000072 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
73 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000074 return node;
75
76 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000077}
78
Miklos Szeredia13d9002004-11-02 17:32:03 +000079static struct node *get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000080{
Miklos Szeredia13d9002004-11-02 17:32:03 +000081 struct node *node = __get_node(f, nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000082 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083 return node;
84
Miklos Szeredia13d9002004-11-02 17:32:03 +000085 fprintf(stderr, "fuse internal error: inode %lu not found\n", nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000087}
88
Miklos Szeredia13d9002004-11-02 17:32:03 +000089static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000090{
Miklos Szeredia13d9002004-11-02 17:32:03 +000091 size_t hash = node->nodeid % f->id_table_size;
92 node->id_next = f->id_table[hash];
93 f->id_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094}
95
Miklos Szeredia13d9002004-11-02 17:32:03 +000096static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097{
Miklos Szeredia13d9002004-11-02 17:32:03 +000098 size_t hash = node->nodeid % f->id_table_size;
99 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000100
Miklos Szeredia13d9002004-11-02 17:32:03 +0000101 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000102 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000103 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000104 return;
105 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106}
107
Miklos Szeredia13d9002004-11-02 17:32:03 +0000108static nodeid_t next_id(struct fuse *f)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000109{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000110 do {
111 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000112 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000113 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000114 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000115 return f->ctr;
116}
117
118static void free_node(struct node *node)
119{
120 free(node->name);
121 free(node);
122}
123
Miklos Szeredia13d9002004-11-02 17:32:03 +0000124static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000125{
126 unsigned int hash = *name;
127
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000128 if (hash)
129 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000130 hash = (hash << 5) - hash + *name;
131
132 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000133}
134
Miklos Szeredia13d9002004-11-02 17:32:03 +0000135static struct node *__lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000136 const char *name)
137{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000138 size_t hash = name_hash(f, parent, name);
139 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000140
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000141 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
142 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000143 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000145 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000146}
147
Miklos Szeredia13d9002004-11-02 17:32:03 +0000148static struct node *lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000149 const char *name)
150{
151 struct node *node;
152
153 pthread_mutex_lock(&f->lock);
154 node = __lookup_node(f, parent, name);
155 pthread_mutex_unlock(&f->lock);
156 if (node != NULL)
157 return node;
158
159 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
160 name);
161 abort();
162}
163
Miklos Szeredia13d9002004-11-02 17:32:03 +0000164static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000165 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000166{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000167 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000168 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000170 if (node->name == NULL)
171 return -1;
172
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000173 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000174 f->name_table[hash] = node;
175 return 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000176}
177
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000178static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000179{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000180 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181 size_t hash = name_hash(f, node->parent, node->name);
182 struct node **nodep = &f->name_table[hash];
183
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000184 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
185 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000186 *nodep = node->name_next;
187 node->name_next = NULL;
188 free(node->name);
189 node->name = NULL;
190 node->parent = 0;
191 return;
192 }
193 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000194 node->nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000195 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000196 }
197}
198
Miklos Szeredia13d9002004-11-02 17:32:03 +0000199static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000200 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000201{
202 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000203 int mode = attr->mode & S_IFMT;
204 int rdev = 0;
205
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000206 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000207 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000208
Miklos Szeredia181e612001-11-06 12:03:23 +0000209 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000210 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 if (node != NULL) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000212 if (node->mode == mode && node->rdev == rdev &&
213 (!(f->flags & FUSE_USE_INO) || node->ino == attr->ino)) {
214 if (!(f->flags & FUSE_USE_INO))
215 attr->ino = node->nodeid;
216
Miklos Szeredia181e612001-11-06 12:03:23 +0000217 goto out;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000218 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000219
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000220 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000221 }
222
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000224 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000225 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000226
Miklos Szeredia13d9002004-11-02 17:32:03 +0000227 node->nodeid = next_id(f);
228 if (!(f->flags & FUSE_USE_INO))
229 attr->ino = node->nodeid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000230 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000231 node->rdev = rdev;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000232 node->ino = attr->ino;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000233 node->open_count = 0;
234 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000235 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000236 if (hash_name(f, node, parent, name) == -1) {
237 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000238 node = NULL;
239 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000240 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000241 hash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000242
Miklos Szeredic2309912004-09-21 13:40:38 +0000243 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000244 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000245 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000246 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000247 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000248}
249
Miklos Szeredia13d9002004-11-02 17:32:03 +0000250static int path_lookup(struct fuse *f, const char *path, nodeid_t *nodeidp,
251 unsigned long *inop)
Miklos Szeredi891b8742004-07-29 09:27:49 +0000252{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000253 nodeid_t nodeid;
254 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000255 int err;
256 char *s;
257 char *name;
258 char *tmp = strdup(path);
259 if (!tmp)
260 return -ENOMEM;
261
262 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000263 nodeid = FUSE_ROOT_ID;
264 ino = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000265 err = 0;
266 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
267 if (name[0]) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000268 struct node *node = __lookup_node(f, nodeid, name);
Miklos Szeredi891b8742004-07-29 09:27:49 +0000269 if (node == NULL) {
270 err = -ENOENT;
271 break;
272 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000273 nodeid = node->nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000274 ino = node->ino;
275 }
276 }
277 pthread_mutex_unlock(&f->lock);
278 free(tmp);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000279 if (!err) {
280 *nodeidp = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000281 *inop = ino;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282 }
Miklos Szeredi891b8742004-07-29 09:27:49 +0000283
284 return err;
285}
286
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000287static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000288{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000289 size_t len = strlen(name);
290 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000291 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
293 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000294 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 strncpy(s, name, len);
296 s--;
297 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000298
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000299 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000300}
301
Miklos Szeredia13d9002004-11-02 17:32:03 +0000302static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000303{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000304 char buf[FUSE_MAX_PATH];
305 char *s = buf + FUSE_MAX_PATH - 1;
306 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000307
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000308 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000309
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000310 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000313 return NULL;
314 }
315
316 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000317 for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000318 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000319 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000320 s = NULL;
321 break;
322 }
323
324 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000326 break;
327 }
328 pthread_mutex_unlock(&f->lock);
329
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000331 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000333 return strdup("/");
334 else
335 return strdup(s);
336}
Miklos Szeredia181e612001-11-06 12:03:23 +0000337
Miklos Szeredia13d9002004-11-02 17:32:03 +0000338static char *get_path(struct fuse *f, nodeid_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000339{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000340 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000341}
342
Miklos Szeredia13d9002004-11-02 17:32:03 +0000343static void destroy_node(struct fuse *f, nodeid_t nodeid, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000344{
Miklos Szeredia181e612001-11-06 12:03:23 +0000345 struct node *node;
346
347 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000348 node = __get_node(f, nodeid);
349 if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000350 unhash_name(f, node);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000351 unhash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000352 free_node(node);
353 }
354 pthread_mutex_unlock(&f->lock);
355
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000356}
357
Miklos Szeredia13d9002004-11-02 17:32:03 +0000358static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000359{
Miklos Szeredia181e612001-11-06 12:03:23 +0000360 struct node *node;
361
362 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000363 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000365 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
366 dir, name);
367 abort();
368 }
369 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000370 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000371}
372
Miklos Szeredia13d9002004-11-02 17:32:03 +0000373static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
374 nodeid_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000375{
Miklos Szeredia181e612001-11-06 12:03:23 +0000376 struct node *node;
377 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000378 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000379
380 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000381 node = __lookup_node(f, olddir, oldname);
382 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000383 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000384 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
385 olddir, oldname);
386 abort();
387 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000389 if (newnode != NULL) {
390 if (hide) {
391 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000392 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000393 goto out;
394 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000395 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000396 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000397
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000398 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000399 if (hash_name(f, node, newdir, newname) == -1) {
400 err = -ENOMEM;
401 goto out;
402 }
403
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000404 if (hide)
405 node->is_hidden = 1;
406
407 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000408 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000409 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000410}
411
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000412static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
413{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000414 attr->ino = stbuf->st_ino;
Miklos Szeredib5958612004-02-20 14:10:49 +0000415 attr->mode = stbuf->st_mode;
416 attr->nlink = stbuf->st_nlink;
417 attr->uid = stbuf->st_uid;
418 attr->gid = stbuf->st_gid;
419 attr->rdev = stbuf->st_rdev;
420 attr->size = stbuf->st_size;
421 attr->blocks = stbuf->st_blocks;
422 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000423 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000424 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000425#ifdef HAVE_STRUCT_STAT_ST_ATIM
426 attr->atimensec = stbuf->st_atim.tv_nsec;
427 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000428 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000429#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430}
431
Miklos Szeredia181e612001-11-06 12:03:23 +0000432static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433{
434 struct fuse_dirent dirent;
435 size_t reclen;
436 size_t res;
437
Miklos Szeredi43696432001-11-18 19:15:05 +0000438 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439 dirent.namelen = strlen(name);
440 strncpy(dirent.name, name, sizeof(dirent.name));
441 dirent.type = type;
442 reclen = FUSE_DIRENT_SIZE(&dirent);
443 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000444 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000445 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000446 return -EIO;
447 }
448 return 0;
449}
450
Miklos Szeredi73798f92004-07-12 15:55:11 +0000451static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
452 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000453{
454 int res;
455
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000456 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000457 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
458 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
459 out->error, strerror(-out->error), outsize);
460 fflush(stdout);
461 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000462
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000463 /* This needs to be done before the reply, otherwise the scheduler
464 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000465 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000466 if (!locked)
467 pthread_mutex_lock(&f->lock);
468 f->numavail ++;
469 if (!locked)
470 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000471
Miklos Szeredi43696432001-11-18 19:15:05 +0000472 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000473 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000474 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000475 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000476 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000477 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000478 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000479 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000480}
481
Miklos Szeredi73798f92004-07-12 15:55:11 +0000482static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
483 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000484{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000485 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000486 char *outbuf;
487 size_t outsize;
488 struct fuse_out_header *out;
489
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000490 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000491 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000492 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000493 }
494
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000495 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000496 argsize = 0;
497
498 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000499 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000500 if (outbuf == NULL) {
501 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
502 res = -ENOMEM;
503 } else {
504 out = (struct fuse_out_header *) outbuf;
505 memset(out, 0, sizeof(struct fuse_out_header));
506 out->unique = in->unique;
507 out->error = error;
508 if (argsize != 0)
509 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
510
511 res = send_reply_raw(f, outbuf, outsize, locked);
512 free(outbuf);
513 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000514
515 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000516}
517
Miklos Szeredi73798f92004-07-12 15:55:11 +0000518static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
519 void *arg, size_t argsize)
520{
521 return __send_reply(f, in, error, arg, argsize, 0);
522}
523
Miklos Szeredia13d9002004-11-02 17:32:03 +0000524static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000525{
526 struct node *node;
527 int isopen = 0;
528 pthread_mutex_lock(&f->lock);
529 node = __lookup_node(f, dir, name);
530 if (node && node->open_count > 0)
531 isopen = 1;
532 pthread_mutex_unlock(&f->lock);
533 return isopen;
534}
535
Miklos Szeredia13d9002004-11-02 17:32:03 +0000536static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000537 char *newname, size_t bufsize)
538{
539 struct stat buf;
540 struct node *node;
541 struct node *newnode;
542 char *newpath;
543 int res;
544 int failctr = 10;
545
546 if (!f->op.getattr)
547 return NULL;
548
549 do {
550 node = lookup_node(f, dir, oldname);
551 pthread_mutex_lock(&f->lock);
552 do {
553 f->hidectr ++;
554 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000555 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000556 newnode = __lookup_node(f, dir, newname);
557 } while(newnode);
558 pthread_mutex_unlock(&f->lock);
559
560 newpath = get_path_name(f, dir, newname);
561 if (!newpath)
562 break;
563
564 res = f->op.getattr(newpath, &buf);
565 if (res != 0)
566 break;
567 free(newpath);
568 newpath = NULL;
569 } while(--failctr);
570
571 return newpath;
572}
573
Miklos Szeredia13d9002004-11-02 17:32:03 +0000574static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000575 const char *oldname)
576{
577 char newname[64];
578 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000579 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000580
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000581 if (f->op.rename && f->op.unlink) {
582 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
583 if (newpath) {
584 int res = f->op.rename(oldpath, newpath);
585 if (res == 0)
586 err = rename_node(f, dir, oldname, dir, newname, 1);
587 free(newpath);
588 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000589 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000590 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000591}
592
Miklos Szeredia13d9002004-11-02 17:32:03 +0000593static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000594 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000595{
596 int res;
597 struct stat buf;
598
599 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000600 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000601 struct node *node;
602
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000603 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000604 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000605 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000606 if (node == NULL)
607 res = -ENOMEM;
608 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000609 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000610 arg->generation = node->generation;
611 arg->entry_valid = ENTRY_REVALIDATE_TIME;
612 arg->entry_valid_nsec = 0;
613 arg->attr_valid = ATTR_REVALIDATE_TIME;
614 arg->attr_valid_nsec = 0;
615 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000616 printf(" NODEID: %li\n", arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000617 fflush(stdout);
618 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000619 }
620 }
621 return res;
622}
623
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000624static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
625{
626 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000627 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000628 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000629 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000630
Miklos Szeredi5e183482001-10-31 14:52:35 +0000631 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000632 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000633 if (path != NULL) {
634 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000635 printf("LOOKUP %s\n", path);
636 fflush(stdout);
637 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000638 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000639 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000640 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000641 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000643 res2 = send_reply(f, in, res, &arg, sizeof(arg));
644 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000645 destroy_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000646}
647
Miklos Szeredia181e612001-11-06 12:03:23 +0000648static void do_forget(struct fuse *f, struct fuse_in_header *in,
649 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000650{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000651 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000652 printf("FORGET %li/%i\n", in->nodeid, arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000653 fflush(stdout);
654 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000655 destroy_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000656}
657
658static void do_getattr(struct fuse *f, struct fuse_in_header *in)
659{
660 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000661 char *path;
662 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000663 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000664
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000666 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000667 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000669 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000670 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000671 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000673
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000674 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000675 memset(&arg, 0, sizeof(struct fuse_attr_out));
676 arg.attr_valid = ATTR_REVALIDATE_TIME;
677 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000678 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000679 if (!(f->flags & FUSE_USE_INO))
680 arg.attr.ino = in->nodeid;
681 else {
682 struct node *node = get_node(f, in->nodeid);
683 node->ino = arg.attr.ino;
684 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000685 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000686
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000687 send_reply(f, in, res, &arg, sizeof(arg));
688}
689
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000690static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000691{
692 int res;
693
694 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000695 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000696 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000697
698 return res;
699}
700
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000701static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000702 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000703{
704 int res;
705 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
706 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
707
708 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000709 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000710 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000711
712 return res;
713}
714
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000715static int do_truncate(struct fuse *f, const char *path,
716 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000717{
718 int res;
719
720 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000721 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000722 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000723
724 return res;
725}
726
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000727static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000728{
729 int res;
730 struct utimbuf buf;
731 buf.actime = attr->atime;
732 buf.modtime = attr->mtime;
733 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000734 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000735 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000736
737 return res;
738}
739
Miklos Szeredi5e183482001-10-31 14:52:35 +0000740static void do_setattr(struct fuse *f, struct fuse_in_header *in,
741 struct fuse_setattr_in *arg)
742{
743 int res;
744 char *path;
745 int valid = arg->valid;
746 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000747 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000748
749 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000750 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000751 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000752 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000753 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000754 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000755 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000756 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000757 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000758 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000760 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000762 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000763 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000764 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000765 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000766 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000768 memset(&outarg, 0, sizeof(struct fuse_attr_out));
769 outarg.attr_valid = ATTR_REVALIDATE_TIME;
770 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000771 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000772 if (!(f->flags & FUSE_USE_INO))
773 outarg.attr.ino = in->nodeid;
774 else {
775 struct node *node = get_node(f, in->nodeid);
776 node->ino = outarg.attr.ino;
777 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000778 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000779 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000780 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000781 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000783 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000784}
785
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786static void do_readlink(struct fuse *f, struct fuse_in_header *in)
787{
788 int res;
789 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000790 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000791
Miklos Szeredi5e183482001-10-31 14:52:35 +0000792 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000793 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000794 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000795 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000796 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000797 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000798 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000800 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000801 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000802}
803
804static void do_getdir(struct fuse *f, struct fuse_in_header *in)
805{
806 int res;
807 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000808 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000809 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000810
Miklos Szeredib483c932001-10-29 14:57:57 +0000811 dh.fuse = f;
812 dh.fp = tmpfile();
Miklos Szeredia13d9002004-11-02 17:32:03 +0000813 dh.dir = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000814
Miklos Szeredi65afea12004-09-14 07:13:45 +0000815 res = -EIO;
816 if (dh.fp == NULL)
817 perror("fuse: failed to create temporary file");
818 else {
819 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000820 path = get_path(f, in->nodeid);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000821 if (path != NULL) {
822 res = -ENOSYS;
823 if (f->op.getdir)
824 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
825 free(path);
826 }
827 fflush(dh.fp);
828 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000829 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000830 if (res == 0)
831 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000832 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000833 if (dh.fp != NULL)
834 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000835}
836
Miklos Szeredib483c932001-10-29 14:57:57 +0000837static void do_mknod(struct fuse *f, struct fuse_in_header *in,
838 struct fuse_mknod_in *inarg)
839{
840 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000841 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000842 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000843 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000844 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000845
Miklos Szeredi5e183482001-10-31 14:52:35 +0000846 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000847 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 if (path != NULL) {
849 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000850 printf("MKNOD %s\n", path);
851 fflush(stdout);
852 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000855 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000857 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000858 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000859 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000860 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000861 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
862 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000863 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000864}
865
866static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
867 struct fuse_mkdir_in *inarg)
868{
869 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000870 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000871 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000872 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000873 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000874
Miklos Szeredi5e183482001-10-31 14:52:35 +0000875 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000876 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877 if (path != NULL) {
878 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000879 printf("MKDIR %s\n", path);
880 fflush(stdout);
881 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000882 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000883 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000884 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000886 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000887 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000888 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000890 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
891 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000892 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000893}
894
Miklos Szeredib5958612004-02-20 14:10:49 +0000895static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000896{
897 int res;
898 char *path;
899
Miklos Szeredi5e183482001-10-31 14:52:35 +0000900 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000901 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000903 if (f->flags & FUSE_DEBUG) {
904 printf("UNLINK %s\n", path);
905 fflush(stdout);
906 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000907 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000909 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
910 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000911 else {
912 res = f->op.unlink(path);
913 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000914 remove_node(f, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000915 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000916 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000917 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000918 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000919 send_reply(f, in, res, NULL, 0);
920}
921
922static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
923{
924 int res;
925 char *path;
926
927 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000928 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000929 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000930 if (f->flags & FUSE_DEBUG) {
931 printf("RMDIR %s\n", path);
932 fflush(stdout);
933 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000934 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000935 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000936 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000938 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000939 }
940 free(path);
941 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000942 send_reply(f, in, res, NULL, 0);
943}
944
945static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
946 char *link)
947{
948 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000949 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000950 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000951 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000952
Miklos Szeredi5e183482001-10-31 14:52:35 +0000953 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000954 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 if (path != NULL) {
956 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000957 printf("SYMLINK %s\n", path);
958 fflush(stdout);
959 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000960 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000961 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000962 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000964 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000965 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000966 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000967 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000968 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
969 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000970 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000971
Miklos Szeredib483c932001-10-29 14:57:57 +0000972}
973
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000974static void do_rename(struct fuse *f, struct fuse_in_header *in,
975 struct fuse_rename_in *inarg)
976{
977 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000978 nodeid_t olddir = in->nodeid;
979 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000980 char *oldname = PARAM(inarg);
981 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000982 char *oldpath;
983 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000984
Miklos Szeredi5e183482001-10-31 14:52:35 +0000985 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000986 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000987 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000988 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000989 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000990 if (f->flags & FUSE_DEBUG) {
991 printf("RENAME %s -> %s\n", oldpath, newpath);
992 fflush(stdout);
993 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000994 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000995 if (f->op.rename) {
996 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +0000997 if (!(f->flags & FUSE_HARD_REMOVE) &&
998 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000999 res = hide_node(f, newpath, newdir, newname);
1000 if (res == 0) {
1001 res = f->op.rename(oldpath, newpath);
1002 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001003 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001004 }
1005 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001006 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001007 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001008 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001009 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001010 send_reply(f, in, res, NULL, 0);
1011}
1012
1013static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001014 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001015{
1016 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001017 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001018 char *oldpath;
1019 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001020 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001021 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001022
Miklos Szeredi5e183482001-10-31 14:52:35 +00001023 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001024 oldpath = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001025 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001026 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001027 if (newpath != NULL) {
1028 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001029 printf("LINK %s\n", newpath);
1030 fflush(stdout);
1031 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001032 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001033 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001034 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001035 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001036 res = lookup_path(f, arg->newdir, in->unique, name,
1037 newpath, &outarg);
1038 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001039 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001040 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001041 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001042 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001043 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1044 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001045 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001046}
1047
Miklos Szeredi5e183482001-10-31 14:52:35 +00001048static void do_open(struct fuse *f, struct fuse_in_header *in,
1049 struct fuse_open_in *arg)
1050{
1051 int res;
1052 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001053 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001054
1055 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001056 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001057 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001058 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001059 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001060 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001061 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001062 if (res == 0) {
1063 int res2;
1064
1065 /* If the request is interrupted the lock must be held until
1066 the cancellation is finished. Otherwise there could be
1067 races with rename/unlink, against which the kernel can't
1068 protect */
1069 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001070 f->fh_ctr ++;
1071 outarg.fh = f->fh_ctr;
1072 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001073 printf("OPEN[%lu] flags: 0x%x\n", outarg.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001074 fflush(stdout);
1075 }
1076
1077 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001078 if(res2 == -ENOENT) {
1079 /* The open syscall was interrupted, so it must be cancelled */
1080 if(f->op.release)
1081 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001082 } else
Miklos Szeredia13d9002004-11-02 17:32:03 +00001083 get_node(f, in->nodeid)->open_count ++;
Miklos Szeredi73798f92004-07-12 15:55:11 +00001084 pthread_mutex_unlock(&f->lock);
1085
1086 } else
1087 send_reply(f, in, res, NULL, 0);
1088
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001089 if (path)
1090 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001091}
1092
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001093static void do_flush(struct fuse *f, struct fuse_in_header *in,
1094 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001095{
1096 char *path;
1097 int res;
1098
1099 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001100 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001101 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001102 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001103 printf("FLUSH[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001104 fflush(stdout);
1105 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001106 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001107 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001108 res = f->op.flush(path);
1109 free(path);
1110 }
1111 send_reply(f, in, res, NULL, 0);
1112}
1113
Miklos Szeredi9478e862002-12-11 09:50:26 +00001114static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001115 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001116{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001117 struct node *node;
1118 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001119
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001120 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001121 node = get_node(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001122 --node->open_count;
1123 pthread_mutex_unlock(&f->lock);
1124
Miklos Szeredia13d9002004-11-02 17:32:03 +00001125 path = get_path(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001126 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001127 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001128 printf("RELEASE[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001129 fflush(stdout);
1130 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001131 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001132 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001133
1134 if(node->is_hidden && node->open_count == 0)
1135 /* can now clean up this hidden file */
1136 f->op.unlink(path);
1137
1138 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001139 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001140 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001141}
1142
Miklos Szeredi5e183482001-10-31 14:52:35 +00001143static void do_read(struct fuse *f, struct fuse_in_header *in,
1144 struct fuse_read_in *arg)
1145{
1146 int res;
1147 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001148 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001149 if (outbuf == NULL)
1150 send_reply(f, in, -ENOMEM, NULL, 0);
1151 else {
1152 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1153 char *buf = outbuf + sizeof(struct fuse_out_header);
1154 size_t size;
1155 size_t outsize;
1156
1157 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001158 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001159 if (path != NULL) {
1160 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001161 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001162 arg->offset);
1163 fflush(stdout);
1164 }
1165
1166 res = -ENOSYS;
1167 if (f->op.read)
1168 res = f->op.read(path, buf, arg->size, arg->offset);
1169 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001170 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001171
1172 size = 0;
1173 if (res >= 0) {
1174 size = res;
1175 res = 0;
1176 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001177 printf(" READ[%lu] %u bytes\n", arg->fh, size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001178 fflush(stdout);
1179 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001180 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001181 memset(out, 0, sizeof(struct fuse_out_header));
1182 out->unique = in->unique;
1183 out->error = res;
1184 outsize = sizeof(struct fuse_out_header) + size;
1185
1186 send_reply_raw(f, outbuf, outsize, 0);
1187 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001188 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001189}
Miklos Szeredib483c932001-10-29 14:57:57 +00001190
Miklos Szeredia181e612001-11-06 12:03:23 +00001191static void do_write(struct fuse *f, struct fuse_in_header *in,
1192 struct fuse_write_in *arg)
1193{
1194 int res;
1195 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001196 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001197
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001198 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001199 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001200 if (path != NULL) {
1201 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001202 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001203 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1204 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001205 fflush(stdout);
1206 }
1207
Miklos Szeredia181e612001-11-06 12:03:23 +00001208 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001209 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001210 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001211 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001212 }
1213
Miklos Szerediad051c32004-07-02 09:22:50 +00001214 if (res >= 0) {
1215 outarg.size = res;
1216 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001217 }
1218
Miklos Szerediad051c32004-07-02 09:22:50 +00001219 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001220}
1221
Miklos Szeredi77f39942004-03-25 11:17:52 +00001222static int default_statfs(struct statfs *buf)
1223{
1224 buf->f_namelen = 255;
1225 buf->f_bsize = 512;
1226 return 0;
1227}
1228
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001229static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1230{
1231 kstatfs->bsize = statfs->f_bsize;
1232 kstatfs->blocks = statfs->f_blocks;
1233 kstatfs->bfree = statfs->f_bfree;
1234 kstatfs->bavail = statfs->f_bavail;
1235 kstatfs->files = statfs->f_files;
1236 kstatfs->ffree = statfs->f_ffree;
1237 kstatfs->namelen = statfs->f_namelen;
1238}
1239
Mark Glinesd84b39a2002-01-07 16:32:02 +00001240static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1241{
1242 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001243 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001244 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001245
Miklos Szeredi77f39942004-03-25 11:17:52 +00001246 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001247 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001248 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001249 else
1250 res = default_statfs(&buf);
1251
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001252 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001253 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001254
Mark Glinesd84b39a2002-01-07 16:32:02 +00001255 send_reply(f, in, res, &arg, sizeof(arg));
1256}
1257
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001258static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1259 struct fuse_fsync_in *inarg)
1260{
1261 int res;
1262 char *path;
1263
1264 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001265 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001266 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001267 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001268 printf("FSYNC[%lu]\n", inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001269 fflush(stdout);
1270 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001271 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001272 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001273 res = f->op.fsync(path, inarg->datasync);
1274 free(path);
1275 }
1276 send_reply(f, in, res, NULL, 0);
1277}
1278
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001279static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1280 struct fuse_setxattr_in *arg)
1281{
1282 int res;
1283 char *path;
1284 char *name = PARAM(arg);
1285 unsigned char *value = name + strlen(name) + 1;
1286
1287 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001288 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001289 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001290 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001291 if (f->op.setxattr)
1292 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1293 free(path);
1294 }
1295 send_reply(f, in, res, NULL, 0);
1296}
1297
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001298static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1299 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001300{
1301 int res;
1302 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001303
1304 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001305 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001306 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001307 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001308 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001309 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001310 free(path);
1311 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001312 return res;
1313}
1314
1315static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1316 const char *name, size_t size)
1317{
1318 int res;
1319 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001320 if (outbuf == NULL)
1321 send_reply(f, in, -ENOMEM, NULL, 0);
1322 else {
1323 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1324 char *value = outbuf + sizeof(struct fuse_out_header);
1325
1326 res = common_getxattr(f, in, name, value, size);
1327 size = 0;
1328 if (res > 0) {
1329 size = res;
1330 res = 0;
1331 }
1332 memset(out, 0, sizeof(struct fuse_out_header));
1333 out->unique = in->unique;
1334 out->error = res;
1335
1336 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1337 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001338 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001339}
1340
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001341static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1342 const char *name)
1343{
1344 int res;
1345 struct fuse_getxattr_out arg;
1346
1347 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001348 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001349 arg.size = res;
1350 res = 0;
1351 }
1352 send_reply(f, in, res, &arg, sizeof(arg));
1353}
1354
1355static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1356 struct fuse_getxattr_in *arg)
1357{
1358 char *name = PARAM(arg);
1359
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001360 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001361 do_getxattr_read(f, in, name, arg->size);
1362 else
1363 do_getxattr_size(f, in, name);
1364}
1365
1366static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1367 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001368{
1369 int res;
1370 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001371
1372 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001373 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001374 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001375 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001376 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001377 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001378 free(path);
1379 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001380 return res;
1381}
1382
1383static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1384 size_t size)
1385{
1386 int res;
1387 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001388 if (outbuf == NULL)
1389 send_reply(f, in, -ENOMEM, NULL, 0);
1390 else {
1391 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1392 char *list = outbuf + sizeof(struct fuse_out_header);
1393
1394 res = common_listxattr(f, in, list, size);
1395 size = 0;
1396 if (res > 0) {
1397 size = res;
1398 res = 0;
1399 }
1400 memset(out, 0, sizeof(struct fuse_out_header));
1401 out->unique = in->unique;
1402 out->error = res;
1403
1404 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1405 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001406 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001407}
1408
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001409static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1410{
1411 int res;
1412 struct fuse_getxattr_out arg;
1413
1414 res = common_listxattr(f, in, NULL, 0);
1415 if (res >= 0) {
1416 arg.size = res;
1417 res = 0;
1418 }
1419 send_reply(f, in, res, &arg, sizeof(arg));
1420}
1421
1422static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1423 struct fuse_getxattr_in *arg)
1424{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001425 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001426 do_listxattr_read(f, in, arg->size);
1427 else
1428 do_listxattr_size(f, in);
1429}
1430
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001431static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1432 char *name)
1433{
1434 int res;
1435 char *path;
1436
1437 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001438 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001439 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001440 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001441 if (f->op.removexattr)
1442 res = f->op.removexattr(path, name);
1443 free(path);
1444 }
1445 send_reply(f, in, res, NULL, 0);
1446}
1447
1448
Miklos Szeredi43696432001-11-18 19:15:05 +00001449static void free_cmd(struct fuse_cmd *cmd)
1450{
1451 free(cmd->buf);
1452 free(cmd);
1453}
1454
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001455void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001456{
Miklos Szeredia181e612001-11-06 12:03:23 +00001457 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1458 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1459 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001460 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001461
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001462 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001463
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001464 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001465 printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
1466 in->unique, opname(in->opcode), in->opcode, in->nodeid,
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001467 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001468 fflush(stdout);
1469 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001470
Miklos Szeredid169f312004-09-22 08:48:26 +00001471 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001472 ctx->uid = in->uid;
1473 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001474 ctx->pid = in->pid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001475
1476 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1477
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001478 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001479 case FUSE_LOOKUP:
1480 do_lookup(f, in, (char *) inarg);
1481 break;
1482
Miklos Szeredia181e612001-11-06 12:03:23 +00001483 case FUSE_GETATTR:
1484 do_getattr(f, in);
1485 break;
1486
1487 case FUSE_SETATTR:
1488 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1489 break;
1490
1491 case FUSE_READLINK:
1492 do_readlink(f, in);
1493 break;
1494
1495 case FUSE_GETDIR:
1496 do_getdir(f, in);
1497 break;
1498
1499 case FUSE_MKNOD:
1500 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1501 break;
1502
1503 case FUSE_MKDIR:
1504 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1505 break;
1506
1507 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001508 do_unlink(f, in, (char *) inarg);
1509 break;
1510
Miklos Szeredia181e612001-11-06 12:03:23 +00001511 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001512 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001513 break;
1514
1515 case FUSE_SYMLINK:
1516 do_symlink(f, in, (char *) inarg,
1517 ((char *) inarg) + strlen((char *) inarg) + 1);
1518 break;
1519
1520 case FUSE_RENAME:
1521 do_rename(f, in, (struct fuse_rename_in *) inarg);
1522 break;
1523
1524 case FUSE_LINK:
1525 do_link(f, in, (struct fuse_link_in *) inarg);
1526 break;
1527
1528 case FUSE_OPEN:
1529 do_open(f, in, (struct fuse_open_in *) inarg);
1530 break;
1531
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001532 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001533 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001534 break;
1535
Miklos Szeredi9478e862002-12-11 09:50:26 +00001536 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001537 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001538 break;
1539
Miklos Szeredia181e612001-11-06 12:03:23 +00001540 case FUSE_READ:
1541 do_read(f, in, (struct fuse_read_in *) inarg);
1542 break;
1543
1544 case FUSE_WRITE:
1545 do_write(f, in, (struct fuse_write_in *) inarg);
1546 break;
1547
Mark Glinesd84b39a2002-01-07 16:32:02 +00001548 case FUSE_STATFS:
1549 do_statfs(f, in);
1550 break;
1551
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001552 case FUSE_FSYNC:
1553 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1554 break;
1555
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001556 case FUSE_SETXATTR:
1557 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1558 break;
1559
1560 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001561 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001562 break;
1563
1564 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001565 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001566 break;
1567
1568 case FUSE_REMOVEXATTR:
1569 do_removexattr(f, in, (char *) inarg);
1570 break;
1571
Miklos Szeredia181e612001-11-06 12:03:23 +00001572 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001573 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001574 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001575
1576 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001577}
1578
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001579int __fuse_exited(struct fuse* f)
1580{
1581 return f->exited;
1582}
1583
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001584struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001585{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001586 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001587 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001588 struct fuse_in_header *in;
1589 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001590
Miklos Szeredi43696432001-11-18 19:15:05 +00001591 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001592 if (cmd == NULL) {
1593 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1594 return NULL;
1595 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001596 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001597 if (cmd->buf == NULL) {
1598 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1599 free(cmd);
1600 return NULL;
1601 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001602 in = (struct fuse_in_header *) cmd->buf;
1603 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001604
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001605 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1606 if (res == -1) {
1607 free_cmd(cmd);
1608 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001609 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001610
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001611 /* ENODEV means we got unmounted, so we silenty return failure */
1612 if (errno != ENODEV) {
1613 /* BAD... This will happen again */
1614 perror("fuse: reading device");
1615 }
1616
1617 fuse_exit(f);
1618 return NULL;
1619 }
1620 if ((size_t) res < sizeof(struct fuse_in_header)) {
1621 free_cmd(cmd);
1622 /* Cannot happen */
1623 fprintf(stderr, "short read on fuse device\n");
1624 fuse_exit(f);
1625 return NULL;
1626 }
1627 cmd->buflen = res;
1628
1629 /* Forget is special, it can be done without messing with threads. */
1630 if (in->opcode == FUSE_FORGET) {
1631 do_forget(f, in, (struct fuse_forget_in *) inarg);
1632 free_cmd(cmd);
1633 return NULL;
1634 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001635
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001636 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001637}
1638
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001639int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001640{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001641 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001642 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001643
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001644 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001645 struct fuse_cmd *cmd;
1646
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001647 if (__fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001648 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001649
1650 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001651 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001652 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001653
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001654 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001655 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001656 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001657 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001658}
1659
Miklos Szeredi891b8742004-07-29 09:27:49 +00001660int fuse_invalidate(struct fuse *f, const char *path)
1661{
1662 int res;
1663 int err;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001664 nodeid_t nodeid;
1665 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001666 struct fuse_user_header h;
1667
Miklos Szeredia13d9002004-11-02 17:32:03 +00001668 err = path_lookup(f, path, &nodeid, &ino);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001669 if (err) {
1670 if (err == -ENOENT)
1671 return 0;
1672 else
1673 return err;
1674 }
1675
1676 memset(&h, 0, sizeof(struct fuse_user_header));
1677 h.opcode = FUSE_INVALIDATE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001678 h.nodeid = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001679 h.ino = ino;
1680
1681 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001682 printf("INVALIDATE nodeid: %li\n", nodeid);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001683 fflush(stdout);
1684 }
1685
1686 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1687 if (res == -1) {
1688 if (errno != ENOENT) {
1689 perror("fuse: writing device");
1690 return -errno;
1691 }
1692 }
1693 return 0;
1694}
1695
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001696void fuse_exit(struct fuse *f)
1697{
1698 f->exited = 1;
1699}
1700
Miklos Szeredid169f312004-09-22 08:48:26 +00001701struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001702{
Miklos Szeredid169f312004-09-22 08:48:26 +00001703 static struct fuse_context context;
1704 if (fuse_getcontext)
1705 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001706 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001707 return &context;
1708}
1709
1710void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1711{
1712 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001713}
1714
Miklos Szeredic40748a2004-02-20 16:38:45 +00001715static int check_version(struct fuse *f)
1716{
1717 int res;
1718 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001719 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001720 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1721 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1722 return -1;
1723 }
1724 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1725 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001726 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001727 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1728 return -1;
1729 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001730 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001731 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1732 FUSE_KERNEL_VERSION);
1733 return -1;
1734 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001735 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001736 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1737 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1738 return -1;
1739 }
1740
1741 return 0;
1742}
1743
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001744
1745int fuse_is_lib_option(const char *opt)
1746{
1747 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001748 strcmp(opt, "hard_remove") == 0 ||
1749 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001750 return 1;
1751 else
1752 return 0;
1753}
1754
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001755static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001756{
1757 if (opts) {
1758 char *xopts = strdup(opts);
1759 char *s = xopts;
1760 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001761
1762 if (xopts == NULL)
1763 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001764
1765 while((opt = strsep(&s, ","))) {
1766 if (strcmp(opt, "debug") == 0)
1767 f->flags |= FUSE_DEBUG;
1768 else if (strcmp(opt, "hard_remove") == 0)
1769 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001770 else if (strcmp(opt, "use_ino") == 0)
1771 f->flags |= FUSE_USE_INO;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001772 else
1773 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1774 }
1775 free(xopts);
1776 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001777 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001778}
1779
1780struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001781{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001782 struct fuse *f;
1783 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001784
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001785 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001786 if (f == NULL)
1787 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001788
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001789 if (check_version(f) == -1)
1790 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001791
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001792 if (parse_lib_opts(f, opts) == -1)
1793 goto out_free;
1794
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001795 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001796 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001797 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001798 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001799 f->name_table_size = 14057;
1800 f->name_table = (struct node **)
1801 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001802 if (f->name_table == NULL)
1803 goto out_free;
1804
Miklos Szeredia13d9002004-11-02 17:32:03 +00001805 f->id_table_size = 14057;
1806 f->id_table = (struct node **)
1807 calloc(1, sizeof(struct node *) * f->id_table_size);
1808 if (f->id_table == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001809 goto out_free_name_table;
1810
Miklos Szeredia181e612001-11-06 12:03:23 +00001811 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001812 f->numworker = 0;
1813 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001814 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001815 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001816
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001817 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001818 if (root == NULL)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001819 goto out_free_id_table;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001820
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001821 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001822 root->rdev = 0;
1823 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001824 if (root->name == NULL)
1825 goto out_free_root;
1826
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001827 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001828 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001829 root->generation = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001830 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001831
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001832 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001833
1834 out_free_root:
1835 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001836 out_free_id_table:
1837 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001838 out_free_name_table:
1839 free(f->name_table);
1840 out_free:
1841 free(f);
1842 out:
1843 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1844 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001845}
1846
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001847void fuse_destroy(struct fuse *f)
1848{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001849 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001850 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001851 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001852
Miklos Szeredia13d9002004-11-02 17:32:03 +00001853 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001854 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001855 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001856 if (path)
1857 f->op.unlink(path);
1858 }
1859 }
1860 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001861 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001862 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001863 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001864
Miklos Szeredia13d9002004-11-02 17:32:03 +00001865 for (node = f->id_table[i]; node != NULL; node = next) {
1866 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001867 free_node(node);
1868 }
1869 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001870 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001871 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001872 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001873 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001874}