blob: b29db9d2f7d326736092bee358e476d3f8ddfb70 [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 Szeredi8fb48fe2004-11-08 14:48:52 +0000432static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
433 ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434{
435 struct fuse_dirent dirent;
436 size_t reclen;
437 size_t res;
438
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000439 if ((dh->fuse->flags & FUSE_USE_INO))
440 dirent.ino = ino;
441 else
442 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000443 dirent.namelen = strlen(name);
444 strncpy(dirent.name, name, sizeof(dirent.name));
445 dirent.type = type;
446 reclen = FUSE_DIRENT_SIZE(&dirent);
447 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000448 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000449 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450 return -EIO;
451 }
452 return 0;
453}
454
Miklos Szeredi73798f92004-07-12 15:55:11 +0000455static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
456 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000457{
458 int res;
459
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000460 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000461 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
462 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
463 out->error, strerror(-out->error), outsize);
464 fflush(stdout);
465 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000466
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000467 /* This needs to be done before the reply, otherwise the scheduler
468 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000469 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000470 if (!locked)
471 pthread_mutex_lock(&f->lock);
472 f->numavail ++;
473 if (!locked)
474 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000475
Miklos Szeredi43696432001-11-18 19:15:05 +0000476 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000477 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000478 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000479 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000480 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000481 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000482 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000483 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000484}
485
Miklos Szeredi73798f92004-07-12 15:55:11 +0000486static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
487 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000488{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000489 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000490 char *outbuf;
491 size_t outsize;
492 struct fuse_out_header *out;
493
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000494 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000495 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000496 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000497 }
498
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000499 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500 argsize = 0;
501
502 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000503 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000504 if (outbuf == NULL) {
505 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
506 res = -ENOMEM;
507 } else {
508 out = (struct fuse_out_header *) outbuf;
509 memset(out, 0, sizeof(struct fuse_out_header));
510 out->unique = in->unique;
511 out->error = error;
512 if (argsize != 0)
513 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
514
515 res = send_reply_raw(f, outbuf, outsize, locked);
516 free(outbuf);
517 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000518
519 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000520}
521
Miklos Szeredi73798f92004-07-12 15:55:11 +0000522static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
523 void *arg, size_t argsize)
524{
525 return __send_reply(f, in, error, arg, argsize, 0);
526}
527
Miklos Szeredia13d9002004-11-02 17:32:03 +0000528static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000529{
530 struct node *node;
531 int isopen = 0;
532 pthread_mutex_lock(&f->lock);
533 node = __lookup_node(f, dir, name);
534 if (node && node->open_count > 0)
535 isopen = 1;
536 pthread_mutex_unlock(&f->lock);
537 return isopen;
538}
539
Miklos Szeredia13d9002004-11-02 17:32:03 +0000540static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000541 char *newname, size_t bufsize)
542{
543 struct stat buf;
544 struct node *node;
545 struct node *newnode;
546 char *newpath;
547 int res;
548 int failctr = 10;
549
550 if (!f->op.getattr)
551 return NULL;
552
553 do {
554 node = lookup_node(f, dir, oldname);
555 pthread_mutex_lock(&f->lock);
556 do {
557 f->hidectr ++;
558 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000559 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000560 newnode = __lookup_node(f, dir, newname);
561 } while(newnode);
562 pthread_mutex_unlock(&f->lock);
563
564 newpath = get_path_name(f, dir, newname);
565 if (!newpath)
566 break;
567
568 res = f->op.getattr(newpath, &buf);
569 if (res != 0)
570 break;
571 free(newpath);
572 newpath = NULL;
573 } while(--failctr);
574
575 return newpath;
576}
577
Miklos Szeredia13d9002004-11-02 17:32:03 +0000578static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000579 const char *oldname)
580{
581 char newname[64];
582 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000583 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000584
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000585 if (f->op.rename && f->op.unlink) {
586 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
587 if (newpath) {
588 int res = f->op.rename(oldpath, newpath);
589 if (res == 0)
590 err = rename_node(f, dir, oldname, dir, newname, 1);
591 free(newpath);
592 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000593 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000594 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000595}
596
Miklos Szeredia13d9002004-11-02 17:32:03 +0000597static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000598 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000599{
600 int res;
601 struct stat buf;
602
603 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000604 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000605 struct node *node;
606
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000607 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000608 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000609 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000610 if (node == NULL)
611 res = -ENOMEM;
612 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000613 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000614 arg->generation = node->generation;
615 arg->entry_valid = ENTRY_REVALIDATE_TIME;
616 arg->entry_valid_nsec = 0;
617 arg->attr_valid = ATTR_REVALIDATE_TIME;
618 arg->attr_valid_nsec = 0;
619 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000620 printf(" NODEID: %li\n", arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000621 fflush(stdout);
622 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000623 }
624 }
625 return res;
626}
627
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000628static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
629{
630 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000631 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000632 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000633 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000634
Miklos Szeredi5e183482001-10-31 14:52:35 +0000635 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000636 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000637 if (path != NULL) {
638 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000639 printf("LOOKUP %s\n", path);
640 fflush(stdout);
641 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000642 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000643 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000644 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000645 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000646 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000647 res2 = send_reply(f, in, res, &arg, sizeof(arg));
648 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000649 destroy_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000650}
651
Miklos Szeredia181e612001-11-06 12:03:23 +0000652static void do_forget(struct fuse *f, struct fuse_in_header *in,
653 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000654{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000655 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000656 printf("FORGET %li/%i\n", in->nodeid, arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000657 fflush(stdout);
658 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000659 destroy_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000660}
661
662static void do_getattr(struct fuse *f, struct fuse_in_header *in)
663{
664 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000665 char *path;
666 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000667 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000668
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000670 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000671 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000673 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000674 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000675 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000677
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000678 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000679 memset(&arg, 0, sizeof(struct fuse_attr_out));
680 arg.attr_valid = ATTR_REVALIDATE_TIME;
681 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000682 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000683 if (!(f->flags & FUSE_USE_INO))
684 arg.attr.ino = in->nodeid;
685 else {
686 struct node *node = get_node(f, in->nodeid);
687 node->ino = arg.attr.ino;
688 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000689 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000690
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000691 send_reply(f, in, res, &arg, sizeof(arg));
692}
693
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000694static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000695{
696 int res;
697
698 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000699 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000700 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000701
702 return res;
703}
704
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000705static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000706 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000707{
708 int res;
709 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
710 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
711
712 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000713 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000714 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000715
716 return res;
717}
718
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000719static int do_truncate(struct fuse *f, const char *path,
720 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000721{
722 int res;
723
724 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000725 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000726 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000727
728 return res;
729}
730
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000731static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000732{
733 int res;
734 struct utimbuf buf;
735 buf.actime = attr->atime;
736 buf.modtime = attr->mtime;
737 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000738 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000739 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000740
741 return res;
742}
743
Miklos Szeredi5e183482001-10-31 14:52:35 +0000744static void do_setattr(struct fuse *f, struct fuse_in_header *in,
745 struct fuse_setattr_in *arg)
746{
747 int res;
748 char *path;
749 int valid = arg->valid;
750 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000751 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000752
753 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000754 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000755 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000756 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000757 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000758 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000760 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000762 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000764 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000766 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000767 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000768 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000769 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000770 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000771 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000772 memset(&outarg, 0, sizeof(struct fuse_attr_out));
773 outarg.attr_valid = ATTR_REVALIDATE_TIME;
774 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000775 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000776 if (!(f->flags & FUSE_USE_INO))
777 outarg.attr.ino = in->nodeid;
778 else {
779 struct node *node = get_node(f, in->nodeid);
780 node->ino = outarg.attr.ino;
781 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000782 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000783 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000784 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000785 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000786 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000787 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788}
789
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000790static void do_readlink(struct fuse *f, struct fuse_in_header *in)
791{
792 int res;
793 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000794 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000795
Miklos Szeredi5e183482001-10-31 14:52:35 +0000796 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000797 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000798 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000800 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000801 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000802 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000803 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000804 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000805 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000806}
807
808static void do_getdir(struct fuse *f, struct fuse_in_header *in)
809{
810 int res;
811 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000812 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000813 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000814
Miklos Szeredib483c932001-10-29 14:57:57 +0000815 dh.fuse = f;
816 dh.fp = tmpfile();
Miklos Szeredia13d9002004-11-02 17:32:03 +0000817 dh.dir = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000818
Miklos Szeredi65afea12004-09-14 07:13:45 +0000819 res = -EIO;
820 if (dh.fp == NULL)
821 perror("fuse: failed to create temporary file");
822 else {
823 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000824 path = get_path(f, in->nodeid);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000825 if (path != NULL) {
826 res = -ENOSYS;
827 if (f->op.getdir)
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000828 res = f->op.getdir(path, &dh, fill_dir);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000829 free(path);
830 }
831 fflush(dh.fp);
832 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000833 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000834 if (res == 0)
835 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000836 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000837 if (dh.fp != NULL)
838 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000839}
840
Miklos Szeredib483c932001-10-29 14:57:57 +0000841static void do_mknod(struct fuse *f, struct fuse_in_header *in,
842 struct fuse_mknod_in *inarg)
843{
844 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000845 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000846 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000847 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000848 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000849
Miklos Szeredi5e183482001-10-31 14:52:35 +0000850 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000851 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000852 if (path != NULL) {
853 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000854 printf("MKNOD %s\n", path);
855 fflush(stdout);
856 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000857 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000858 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000859 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000860 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000861 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000862 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000863 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000864 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000865 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
866 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000867 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000868}
869
870static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
871 struct fuse_mkdir_in *inarg)
872{
873 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000874 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000875 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000876 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000877 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000878
Miklos Szeredi5e183482001-10-31 14:52:35 +0000879 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000880 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 if (path != NULL) {
882 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000883 printf("MKDIR %s\n", path);
884 fflush(stdout);
885 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000886 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000887 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000888 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000889 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000890 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000891 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000892 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000893 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000894 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
895 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000896 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000897}
898
Miklos Szeredib5958612004-02-20 14:10:49 +0000899static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000900{
901 int res;
902 char *path;
903
Miklos Szeredi5e183482001-10-31 14:52:35 +0000904 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000905 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000906 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000907 if (f->flags & FUSE_DEBUG) {
908 printf("UNLINK %s\n", path);
909 fflush(stdout);
910 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000911 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000912 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000913 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
914 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000915 else {
916 res = f->op.unlink(path);
917 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000918 remove_node(f, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000919 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000920 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000921 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000922 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000923 send_reply(f, in, res, NULL, 0);
924}
925
926static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
927{
928 int res;
929 char *path;
930
931 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000932 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000933 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000934 if (f->flags & FUSE_DEBUG) {
935 printf("RMDIR %s\n", path);
936 fflush(stdout);
937 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000938 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000939 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000940 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000941 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000942 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000943 }
944 free(path);
945 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000946 send_reply(f, in, res, NULL, 0);
947}
948
949static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
950 char *link)
951{
952 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000953 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000954 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000955 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000956
Miklos Szeredi5e183482001-10-31 14:52:35 +0000957 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000958 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000959 if (path != NULL) {
960 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000961 printf("SYMLINK %s\n", path);
962 fflush(stdout);
963 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000964 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000965 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000966 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000967 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000968 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000969 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000970 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000971 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000972 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
973 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000974 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000975
Miklos Szeredib483c932001-10-29 14:57:57 +0000976}
977
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000978static void do_rename(struct fuse *f, struct fuse_in_header *in,
979 struct fuse_rename_in *inarg)
980{
981 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000982 nodeid_t olddir = in->nodeid;
983 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000984 char *oldname = PARAM(inarg);
985 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000986 char *oldpath;
987 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000988
Miklos Szeredi5e183482001-10-31 14:52:35 +0000989 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000990 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000991 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000992 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000993 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000994 if (f->flags & FUSE_DEBUG) {
995 printf("RENAME %s -> %s\n", oldpath, newpath);
996 fflush(stdout);
997 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000998 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000999 if (f->op.rename) {
1000 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001001 if (!(f->flags & FUSE_HARD_REMOVE) &&
1002 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001003 res = hide_node(f, newpath, newdir, newname);
1004 if (res == 0) {
1005 res = f->op.rename(oldpath, newpath);
1006 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001007 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001008 }
1009 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001010 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001011 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001012 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001013 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001014 send_reply(f, in, res, NULL, 0);
1015}
1016
1017static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001018 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001019{
1020 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001021 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001022 char *oldpath;
1023 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001024 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001025 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001026
Miklos Szeredi5e183482001-10-31 14:52:35 +00001027 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001028 oldpath = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001029 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001030 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001031 if (newpath != NULL) {
1032 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001033 printf("LINK %s\n", newpath);
1034 fflush(stdout);
1035 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001036 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001037 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001038 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001039 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001040 res = lookup_path(f, arg->newdir, in->unique, name,
1041 newpath, &outarg);
1042 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001043 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001044 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001045 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001046 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001047 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1048 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001049 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001050}
1051
Miklos Szeredi5e183482001-10-31 14:52:35 +00001052static void do_open(struct fuse *f, struct fuse_in_header *in,
1053 struct fuse_open_in *arg)
1054{
1055 int res;
1056 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001057 struct fuse_open_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001058
1059 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001060 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001061 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001062 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001063 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001064 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001065 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001066 if (res == 0) {
1067 int res2;
1068
1069 /* If the request is interrupted the lock must be held until
1070 the cancellation is finished. Otherwise there could be
1071 races with rename/unlink, against which the kernel can't
1072 protect */
1073 pthread_mutex_lock(&f->lock);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001074 f->fh_ctr ++;
1075 outarg.fh = f->fh_ctr;
1076 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001077 printf("OPEN[%lu] flags: 0x%x\n", outarg.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001078 fflush(stdout);
1079 }
1080
1081 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001082 if(res2 == -ENOENT) {
1083 /* The open syscall was interrupted, so it must be cancelled */
1084 if(f->op.release)
1085 f->op.release(path, arg->flags);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001086 } else
Miklos Szeredia13d9002004-11-02 17:32:03 +00001087 get_node(f, in->nodeid)->open_count ++;
Miklos Szeredi73798f92004-07-12 15:55:11 +00001088 pthread_mutex_unlock(&f->lock);
1089
1090 } else
1091 send_reply(f, in, res, NULL, 0);
1092
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001093 if (path)
1094 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001095}
1096
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001097static void do_flush(struct fuse *f, struct fuse_in_header *in,
1098 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001099{
1100 char *path;
1101 int res;
1102
1103 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001104 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001105 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001106 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001107 printf("FLUSH[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001108 fflush(stdout);
1109 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001110 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001111 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001112 res = f->op.flush(path);
1113 free(path);
1114 }
1115 send_reply(f, in, res, NULL, 0);
1116}
1117
Miklos Szeredi9478e862002-12-11 09:50:26 +00001118static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001119 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001120{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001121 struct node *node;
1122 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001123
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001124 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001125 node = get_node(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001126 --node->open_count;
1127 pthread_mutex_unlock(&f->lock);
1128
Miklos Szeredia13d9002004-11-02 17:32:03 +00001129 path = get_path(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001130 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001131 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001132 printf("RELEASE[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001133 fflush(stdout);
1134 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001135 if (f->op.release)
Miklos Szeredib3210582004-06-23 13:54:33 +00001136 f->op.release(path, arg->flags);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001137
1138 if(node->is_hidden && node->open_count == 0)
1139 /* can now clean up this hidden file */
1140 f->op.unlink(path);
1141
1142 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001143 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001144 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001145}
1146
Miklos Szeredi5e183482001-10-31 14:52:35 +00001147static void do_read(struct fuse *f, struct fuse_in_header *in,
1148 struct fuse_read_in *arg)
1149{
1150 int res;
1151 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001152 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001153 if (outbuf == NULL)
1154 send_reply(f, in, -ENOMEM, NULL, 0);
1155 else {
1156 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1157 char *buf = outbuf + sizeof(struct fuse_out_header);
1158 size_t size;
1159 size_t outsize;
1160
1161 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001162 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001163 if (path != NULL) {
1164 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001165 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001166 arg->offset);
1167 fflush(stdout);
1168 }
1169
1170 res = -ENOSYS;
1171 if (f->op.read)
1172 res = f->op.read(path, buf, arg->size, arg->offset);
1173 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001174 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001175
1176 size = 0;
1177 if (res >= 0) {
1178 size = res;
1179 res = 0;
1180 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001181 printf(" READ[%lu] %u bytes\n", arg->fh, size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001182 fflush(stdout);
1183 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001184 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001185 memset(out, 0, sizeof(struct fuse_out_header));
1186 out->unique = in->unique;
1187 out->error = res;
1188 outsize = sizeof(struct fuse_out_header) + size;
1189
1190 send_reply_raw(f, outbuf, outsize, 0);
1191 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001192 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001193}
Miklos Szeredib483c932001-10-29 14:57:57 +00001194
Miklos Szeredia181e612001-11-06 12:03:23 +00001195static void do_write(struct fuse *f, struct fuse_in_header *in,
1196 struct fuse_write_in *arg)
1197{
1198 int res;
1199 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001200 struct fuse_write_out outarg;
Miklos Szeredia181e612001-11-06 12:03:23 +00001201
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001202 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001203 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001204 if (path != NULL) {
1205 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001206 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001207 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1208 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001209 fflush(stdout);
1210 }
1211
Miklos Szeredia181e612001-11-06 12:03:23 +00001212 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001213 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +00001214 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001215 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001216 }
1217
Miklos Szerediad051c32004-07-02 09:22:50 +00001218 if (res >= 0) {
1219 outarg.size = res;
1220 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001221 }
1222
Miklos Szerediad051c32004-07-02 09:22:50 +00001223 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001224}
1225
Miklos Szeredi77f39942004-03-25 11:17:52 +00001226static int default_statfs(struct statfs *buf)
1227{
1228 buf->f_namelen = 255;
1229 buf->f_bsize = 512;
1230 return 0;
1231}
1232
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001233static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1234{
1235 kstatfs->bsize = statfs->f_bsize;
1236 kstatfs->blocks = statfs->f_blocks;
1237 kstatfs->bfree = statfs->f_bfree;
1238 kstatfs->bavail = statfs->f_bavail;
1239 kstatfs->files = statfs->f_files;
1240 kstatfs->ffree = statfs->f_ffree;
1241 kstatfs->namelen = statfs->f_namelen;
1242}
1243
Mark Glinesd84b39a2002-01-07 16:32:02 +00001244static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1245{
1246 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001247 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001248 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001249
Miklos Szeredi77f39942004-03-25 11:17:52 +00001250 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001251 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001252 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001253 else
1254 res = default_statfs(&buf);
1255
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001256 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001257 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001258
Mark Glinesd84b39a2002-01-07 16:32:02 +00001259 send_reply(f, in, res, &arg, sizeof(arg));
1260}
1261
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001262static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1263 struct fuse_fsync_in *inarg)
1264{
1265 int res;
1266 char *path;
1267
1268 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001269 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001270 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001271 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001272 printf("FSYNC[%lu]\n", inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001273 fflush(stdout);
1274 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001275 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001276 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001277 res = f->op.fsync(path, inarg->datasync);
1278 free(path);
1279 }
1280 send_reply(f, in, res, NULL, 0);
1281}
1282
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001283static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1284 struct fuse_setxattr_in *arg)
1285{
1286 int res;
1287 char *path;
1288 char *name = PARAM(arg);
1289 unsigned char *value = name + strlen(name) + 1;
1290
1291 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001292 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001293 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001294 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001295 if (f->op.setxattr)
1296 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1297 free(path);
1298 }
1299 send_reply(f, in, res, NULL, 0);
1300}
1301
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001302static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1303 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001304{
1305 int res;
1306 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001307
1308 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001309 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001310 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001311 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001312 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001313 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001314 free(path);
1315 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001316 return res;
1317}
1318
1319static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1320 const char *name, size_t size)
1321{
1322 int res;
1323 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001324 if (outbuf == NULL)
1325 send_reply(f, in, -ENOMEM, NULL, 0);
1326 else {
1327 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1328 char *value = outbuf + sizeof(struct fuse_out_header);
1329
1330 res = common_getxattr(f, in, name, value, size);
1331 size = 0;
1332 if (res > 0) {
1333 size = res;
1334 res = 0;
1335 }
1336 memset(out, 0, sizeof(struct fuse_out_header));
1337 out->unique = in->unique;
1338 out->error = res;
1339
1340 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1341 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001342 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001343}
1344
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001345static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1346 const char *name)
1347{
1348 int res;
1349 struct fuse_getxattr_out arg;
1350
1351 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001352 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001353 arg.size = res;
1354 res = 0;
1355 }
1356 send_reply(f, in, res, &arg, sizeof(arg));
1357}
1358
1359static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1360 struct fuse_getxattr_in *arg)
1361{
1362 char *name = PARAM(arg);
1363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001364 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001365 do_getxattr_read(f, in, name, arg->size);
1366 else
1367 do_getxattr_size(f, in, name);
1368}
1369
1370static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1371 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001372{
1373 int res;
1374 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001375
1376 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001377 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001378 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001379 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001380 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001381 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001382 free(path);
1383 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001384 return res;
1385}
1386
1387static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1388 size_t size)
1389{
1390 int res;
1391 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001392 if (outbuf == NULL)
1393 send_reply(f, in, -ENOMEM, NULL, 0);
1394 else {
1395 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1396 char *list = outbuf + sizeof(struct fuse_out_header);
1397
1398 res = common_listxattr(f, in, list, size);
1399 size = 0;
1400 if (res > 0) {
1401 size = res;
1402 res = 0;
1403 }
1404 memset(out, 0, sizeof(struct fuse_out_header));
1405 out->unique = in->unique;
1406 out->error = res;
1407
1408 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1409 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001410 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001411}
1412
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001413static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1414{
1415 int res;
1416 struct fuse_getxattr_out arg;
1417
1418 res = common_listxattr(f, in, NULL, 0);
1419 if (res >= 0) {
1420 arg.size = res;
1421 res = 0;
1422 }
1423 send_reply(f, in, res, &arg, sizeof(arg));
1424}
1425
1426static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1427 struct fuse_getxattr_in *arg)
1428{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001429 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001430 do_listxattr_read(f, in, arg->size);
1431 else
1432 do_listxattr_size(f, in);
1433}
1434
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001435static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1436 char *name)
1437{
1438 int res;
1439 char *path;
1440
1441 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001442 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001443 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001444 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001445 if (f->op.removexattr)
1446 res = f->op.removexattr(path, name);
1447 free(path);
1448 }
1449 send_reply(f, in, res, NULL, 0);
1450}
1451
1452
Miklos Szeredi43696432001-11-18 19:15:05 +00001453static void free_cmd(struct fuse_cmd *cmd)
1454{
1455 free(cmd->buf);
1456 free(cmd);
1457}
1458
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001459void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001460{
Miklos Szeredia181e612001-11-06 12:03:23 +00001461 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1462 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1463 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001464 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001465
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001466 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001467
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001468 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001469 printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
1470 in->unique, opname(in->opcode), in->opcode, in->nodeid,
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001471 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001472 fflush(stdout);
1473 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001474
Miklos Szeredid169f312004-09-22 08:48:26 +00001475 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001476 ctx->uid = in->uid;
1477 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001478 ctx->pid = in->pid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001479
1480 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1481
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001482 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001483 case FUSE_LOOKUP:
1484 do_lookup(f, in, (char *) inarg);
1485 break;
1486
Miklos Szeredia181e612001-11-06 12:03:23 +00001487 case FUSE_GETATTR:
1488 do_getattr(f, in);
1489 break;
1490
1491 case FUSE_SETATTR:
1492 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1493 break;
1494
1495 case FUSE_READLINK:
1496 do_readlink(f, in);
1497 break;
1498
1499 case FUSE_GETDIR:
1500 do_getdir(f, in);
1501 break;
1502
1503 case FUSE_MKNOD:
1504 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1505 break;
1506
1507 case FUSE_MKDIR:
1508 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1509 break;
1510
1511 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001512 do_unlink(f, in, (char *) inarg);
1513 break;
1514
Miklos Szeredia181e612001-11-06 12:03:23 +00001515 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001516 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001517 break;
1518
1519 case FUSE_SYMLINK:
1520 do_symlink(f, in, (char *) inarg,
1521 ((char *) inarg) + strlen((char *) inarg) + 1);
1522 break;
1523
1524 case FUSE_RENAME:
1525 do_rename(f, in, (struct fuse_rename_in *) inarg);
1526 break;
1527
1528 case FUSE_LINK:
1529 do_link(f, in, (struct fuse_link_in *) inarg);
1530 break;
1531
1532 case FUSE_OPEN:
1533 do_open(f, in, (struct fuse_open_in *) inarg);
1534 break;
1535
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001536 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001537 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001538 break;
1539
Miklos Szeredi9478e862002-12-11 09:50:26 +00001540 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001541 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001542 break;
1543
Miklos Szeredia181e612001-11-06 12:03:23 +00001544 case FUSE_READ:
1545 do_read(f, in, (struct fuse_read_in *) inarg);
1546 break;
1547
1548 case FUSE_WRITE:
1549 do_write(f, in, (struct fuse_write_in *) inarg);
1550 break;
1551
Mark Glinesd84b39a2002-01-07 16:32:02 +00001552 case FUSE_STATFS:
1553 do_statfs(f, in);
1554 break;
1555
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001556 case FUSE_FSYNC:
1557 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1558 break;
1559
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001560 case FUSE_SETXATTR:
1561 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1562 break;
1563
1564 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001565 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001566 break;
1567
1568 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001569 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001570 break;
1571
1572 case FUSE_REMOVEXATTR:
1573 do_removexattr(f, in, (char *) inarg);
1574 break;
1575
Miklos Szeredia181e612001-11-06 12:03:23 +00001576 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001577 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001578 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001579
1580 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001581}
1582
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001583int __fuse_exited(struct fuse* f)
1584{
1585 return f->exited;
1586}
1587
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001588struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001589{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001590 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001591 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001592 struct fuse_in_header *in;
1593 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001594
Miklos Szeredi43696432001-11-18 19:15:05 +00001595 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001596 if (cmd == NULL) {
1597 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1598 return NULL;
1599 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001600 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001601 if (cmd->buf == NULL) {
1602 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1603 free(cmd);
1604 return NULL;
1605 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001606 in = (struct fuse_in_header *) cmd->buf;
1607 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001608
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001609 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1610 if (res == -1) {
1611 free_cmd(cmd);
1612 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001613 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001614
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001615 /* ENODEV means we got unmounted, so we silenty return failure */
1616 if (errno != ENODEV) {
1617 /* BAD... This will happen again */
1618 perror("fuse: reading device");
1619 }
1620
1621 fuse_exit(f);
1622 return NULL;
1623 }
1624 if ((size_t) res < sizeof(struct fuse_in_header)) {
1625 free_cmd(cmd);
1626 /* Cannot happen */
1627 fprintf(stderr, "short read on fuse device\n");
1628 fuse_exit(f);
1629 return NULL;
1630 }
1631 cmd->buflen = res;
1632
1633 /* Forget is special, it can be done without messing with threads. */
1634 if (in->opcode == FUSE_FORGET) {
1635 do_forget(f, in, (struct fuse_forget_in *) inarg);
1636 free_cmd(cmd);
1637 return NULL;
1638 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001639
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001640 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001641}
1642
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001643int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001644{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001645 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001646 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001647
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001648 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001649 struct fuse_cmd *cmd;
1650
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001651 if (__fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001652 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001653
1654 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001655 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001656 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001657
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001658 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001659 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001660 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001661 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001662}
1663
Miklos Szeredi891b8742004-07-29 09:27:49 +00001664int fuse_invalidate(struct fuse *f, const char *path)
1665{
1666 int res;
1667 int err;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001668 nodeid_t nodeid;
1669 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001670 struct fuse_user_header h;
1671
Miklos Szeredia13d9002004-11-02 17:32:03 +00001672 err = path_lookup(f, path, &nodeid, &ino);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001673 if (err) {
1674 if (err == -ENOENT)
1675 return 0;
1676 else
1677 return err;
1678 }
1679
1680 memset(&h, 0, sizeof(struct fuse_user_header));
1681 h.opcode = FUSE_INVALIDATE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001682 h.nodeid = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001683 h.ino = ino;
1684
1685 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001686 printf("INVALIDATE nodeid: %li\n", nodeid);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001687 fflush(stdout);
1688 }
1689
1690 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1691 if (res == -1) {
1692 if (errno != ENOENT) {
1693 perror("fuse: writing device");
1694 return -errno;
1695 }
1696 }
1697 return 0;
1698}
1699
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001700void fuse_exit(struct fuse *f)
1701{
1702 f->exited = 1;
1703}
1704
Miklos Szeredid169f312004-09-22 08:48:26 +00001705struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001706{
Miklos Szeredid169f312004-09-22 08:48:26 +00001707 static struct fuse_context context;
1708 if (fuse_getcontext)
1709 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001710 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001711 return &context;
1712}
1713
1714void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1715{
1716 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001717}
1718
Miklos Szeredic40748a2004-02-20 16:38:45 +00001719static int check_version(struct fuse *f)
1720{
1721 int res;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001722 const char *version_file = FUSE_VERSION_FILE;
1723 FILE *vf = fopen(version_file, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001724 if (vf == NULL) {
Miklos Szeredif3845c42004-11-20 11:18:34 +00001725 version_file = "/sys/fs/fuse/version";
1726 vf = fopen(version_file, "r");
1727 if (vf == NULL) {
1728 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1729 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1730 return -1;
1731 }
Miklos Szeredic40748a2004-02-20 16:38:45 +00001732 }
1733 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1734 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001735 if (res != 2) {
Miklos Szeredif3845c42004-11-20 11:18:34 +00001736 fprintf(stderr, "fuse: error reading %s\n", version_file);
Miklos Szeredic40748a2004-02-20 16:38:45 +00001737 return -1;
1738 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001739 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001740 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1741 FUSE_KERNEL_VERSION);
1742 return -1;
1743 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001744 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredi256739a2004-11-20 12:22:37 +00001745 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n",
Miklos Szeredic40748a2004-02-20 16:38:45 +00001746 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1747 return -1;
1748 }
1749
1750 return 0;
1751}
1752
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001753
1754int fuse_is_lib_option(const char *opt)
1755{
1756 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001757 strcmp(opt, "hard_remove") == 0 ||
1758 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001759 return 1;
1760 else
1761 return 0;
1762}
1763
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001764static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001765{
1766 if (opts) {
1767 char *xopts = strdup(opts);
1768 char *s = xopts;
1769 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001770
1771 if (xopts == NULL)
1772 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001773
1774 while((opt = strsep(&s, ","))) {
1775 if (strcmp(opt, "debug") == 0)
1776 f->flags |= FUSE_DEBUG;
1777 else if (strcmp(opt, "hard_remove") == 0)
1778 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001779 else if (strcmp(opt, "use_ino") == 0)
1780 f->flags |= FUSE_USE_INO;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001781 else
1782 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1783 }
1784 free(xopts);
1785 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001786 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001787}
1788
1789struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001790{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001791 struct fuse *f;
1792 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001793
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001794 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001795 if (f == NULL)
1796 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001797
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001798 if (check_version(f) == -1)
1799 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001800
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001801 if (parse_lib_opts(f, opts) == -1)
1802 goto out_free;
1803
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001804 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001805 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001806 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001807 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001808 f->name_table_size = 14057;
1809 f->name_table = (struct node **)
1810 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001811 if (f->name_table == NULL)
1812 goto out_free;
1813
Miklos Szeredia13d9002004-11-02 17:32:03 +00001814 f->id_table_size = 14057;
1815 f->id_table = (struct node **)
1816 calloc(1, sizeof(struct node *) * f->id_table_size);
1817 if (f->id_table == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001818 goto out_free_name_table;
1819
Miklos Szeredia181e612001-11-06 12:03:23 +00001820 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001821 f->numworker = 0;
1822 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001823 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001824 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001825
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001826 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001827 if (root == NULL)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001828 goto out_free_id_table;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001829
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001830 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001831 root->rdev = 0;
1832 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001833 if (root->name == NULL)
1834 goto out_free_root;
1835
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001836 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001837 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001838 root->generation = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001839 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001840
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001841 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001842
1843 out_free_root:
1844 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001845 out_free_id_table:
1846 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001847 out_free_name_table:
1848 free(f->name_table);
1849 out_free:
1850 free(f);
1851 out:
1852 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1853 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001854}
1855
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001856void fuse_destroy(struct fuse *f)
1857{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001858 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001859 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001860 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001861
Miklos Szeredia13d9002004-11-02 17:32:03 +00001862 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001863 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001864 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001865 if (path)
1866 f->op.unlink(path);
1867 }
1868 }
1869 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001870 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001871 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001872 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001873
Miklos Szeredia13d9002004-11-02 17:32:03 +00001874 for (node = f->id_table[i]; node != NULL; node = next) {
1875 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001876 free_node(node);
1877 }
1878 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001879 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001880 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001881 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001882 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001883}