blob: 66474fb849c2d73f138e0d56d466b7bf1831179b [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 Szeredia25d4c22004-11-23 22:32:16 +000020#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
21#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
22
Miklos Szeredi97c61e92001-11-07 12:09:43 +000023#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000024#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000025
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000026#define ENTRY_REVALIDATE_TIME 1 /* sec */
27#define ATTR_REVALIDATE_TIME 1 /* sec */
28
Miklos Szeredid169f312004-09-22 08:48:26 +000029static struct fuse_context *(*fuse_getcontext)(void) = NULL;
30
Miklos Szeredic8ba2372002-12-10 12:26:00 +000031static const char *opname(enum fuse_opcode opcode)
32{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000033 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000034 case FUSE_LOOKUP: return "LOOKUP";
35 case FUSE_FORGET: return "FORGET";
36 case FUSE_GETATTR: return "GETATTR";
37 case FUSE_SETATTR: return "SETATTR";
38 case FUSE_READLINK: return "READLINK";
39 case FUSE_SYMLINK: return "SYMLINK";
40 case FUSE_GETDIR: return "GETDIR";
41 case FUSE_MKNOD: return "MKNOD";
42 case FUSE_MKDIR: return "MKDIR";
43 case FUSE_UNLINK: return "UNLINK";
44 case FUSE_RMDIR: return "RMDIR";
45 case FUSE_RENAME: return "RENAME";
46 case FUSE_LINK: return "LINK";
47 case FUSE_OPEN: return "OPEN";
48 case FUSE_READ: return "READ";
49 case FUSE_WRITE: return "WRITE";
50 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000051 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000052 case FUSE_RELEASE: return "RELEASE";
53 case FUSE_FSYNC: return "FSYNC";
54 case FUSE_SETXATTR: return "SETXATTR";
55 case FUSE_GETXATTR: return "GETXATTR";
56 case FUSE_LISTXATTR: return "LISTXATTR";
57 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000058 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000059 }
60}
61
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000062
63static inline void dec_avail(struct fuse *f)
64{
65 pthread_mutex_lock(&f->lock);
66 f->numavail --;
67 pthread_mutex_unlock(&f->lock);
68}
69
Miklos Szeredia13d9002004-11-02 17:32:03 +000070static struct node *__get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000071{
Miklos Szeredia13d9002004-11-02 17:32:03 +000072 size_t hash = nodeid % f->id_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000073 struct node *node;
74
Miklos Szeredia13d9002004-11-02 17:32:03 +000075 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
76 if (node->nodeid == nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000077 return node;
78
79 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000080}
81
Miklos Szeredia13d9002004-11-02 17:32:03 +000082static struct node *get_node(struct fuse *f, nodeid_t nodeid)
Miklos Szeredia181e612001-11-06 12:03:23 +000083{
Miklos Szeredia13d9002004-11-02 17:32:03 +000084 struct node *node = __get_node(f, nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000085 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 return node;
87
Miklos Szeredia13d9002004-11-02 17:32:03 +000088 fprintf(stderr, "fuse internal error: inode %lu not found\n", nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +000089 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000090}
91
Miklos Szeredia13d9002004-11-02 17:32:03 +000092static void hash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredia13d9002004-11-02 17:32:03 +000094 size_t hash = node->nodeid % f->id_table_size;
95 node->id_next = f->id_table[hash];
96 f->id_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097}
98
Miklos Szeredia13d9002004-11-02 17:32:03 +000099static void unhash_id(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000101 size_t hash = node->nodeid % f->id_table_size;
102 struct node **nodep = &f->id_table[hash];
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000103
Miklos Szeredia13d9002004-11-02 17:32:03 +0000104 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000105 if (*nodep == node) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000106 *nodep = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000107 return;
108 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109}
110
Miklos Szeredia13d9002004-11-02 17:32:03 +0000111static nodeid_t next_id(struct fuse *f)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000113 do {
114 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000115 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000116 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000117 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000118 return f->ctr;
119}
120
121static void free_node(struct node *node)
122{
123 free(node->name);
124 free(node);
125}
126
Miklos Szeredia13d9002004-11-02 17:32:03 +0000127static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000128{
129 unsigned int hash = *name;
130
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000131 if (hash)
132 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000133 hash = (hash << 5) - hash + *name;
134
135 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000136}
137
Miklos Szeredia13d9002004-11-02 17:32:03 +0000138static struct node *__lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139 const char *name)
140{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000141 size_t hash = name_hash(f, parent, name);
142 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000143
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000144 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
145 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000146 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000147
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000148 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000149}
150
Miklos Szeredia13d9002004-11-02 17:32:03 +0000151static struct node *lookup_node(struct fuse *f, nodeid_t parent,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000152 const char *name)
153{
154 struct node *node;
155
156 pthread_mutex_lock(&f->lock);
157 node = __lookup_node(f, parent, name);
158 pthread_mutex_unlock(&f->lock);
159 if (node != NULL)
160 return node;
161
162 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
163 name);
164 abort();
165}
166
Miklos Szeredia13d9002004-11-02 17:32:03 +0000167static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000168 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000169{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000171 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000172 node->name = strdup(name);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000173 if (node->name == NULL)
174 return -1;
175
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000176 node->name_next = f->name_table[hash];
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000177 f->name_table[hash] = node;
178 return 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000179}
180
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000181static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000182{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000183 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000184 size_t hash = name_hash(f, node->parent, node->name);
185 struct node **nodep = &f->name_table[hash];
186
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000187 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
188 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000189 *nodep = node->name_next;
190 node->name_next = NULL;
191 free(node->name);
192 node->name = NULL;
193 node->parent = 0;
194 return;
195 }
196 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000197 node->nodeid);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000199 }
200}
201
Miklos Szeredia13d9002004-11-02 17:32:03 +0000202static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000203 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000204{
205 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000206 int mode = attr->mode & S_IFMT;
207 int rdev = 0;
208
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000210 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000211
Miklos Szeredia181e612001-11-06 12:03:23 +0000212 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000213 node = __lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000214 if (node != NULL) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000215 if (node->mode == mode && node->rdev == rdev &&
216 (!(f->flags & FUSE_USE_INO) || node->ino == attr->ino)) {
217 if (!(f->flags & FUSE_USE_INO))
218 attr->ino = node->nodeid;
219
Miklos Szeredia181e612001-11-06 12:03:23 +0000220 goto out;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000221 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000222
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000224 }
225
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000226 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000227 if (node == NULL)
Miklos Szeredic2309912004-09-21 13:40:38 +0000228 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000229
Miklos Szeredia13d9002004-11-02 17:32:03 +0000230 node->nodeid = next_id(f);
231 if (!(f->flags & FUSE_USE_INO))
232 attr->ino = node->nodeid;
Miklos Szeredia181e612001-11-06 12:03:23 +0000233 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000234 node->rdev = rdev;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000235 node->ino = attr->ino;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000236 node->open_count = 0;
237 node->is_hidden = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000238 node->generation = f->generation;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000239 if (hash_name(f, node, parent, name) == -1) {
240 free(node);
Miklos Szeredic2309912004-09-21 13:40:38 +0000241 node = NULL;
242 goto out_err;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000243 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000244 hash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000245
Miklos Szeredic2309912004-09-21 13:40:38 +0000246 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000247 node->version = version;
Miklos Szeredic2309912004-09-21 13:40:38 +0000248 out_err:
Miklos Szeredia181e612001-11-06 12:03:23 +0000249 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000250 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000251}
252
Miklos Szeredia13d9002004-11-02 17:32:03 +0000253static int path_lookup(struct fuse *f, const char *path, nodeid_t *nodeidp,
254 unsigned long *inop)
Miklos Szeredi891b8742004-07-29 09:27:49 +0000255{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000256 nodeid_t nodeid;
257 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000258 int err;
259 char *s;
260 char *name;
261 char *tmp = strdup(path);
262 if (!tmp)
263 return -ENOMEM;
264
265 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000266 nodeid = FUSE_ROOT_ID;
267 ino = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000268 err = 0;
269 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
270 if (name[0]) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000271 struct node *node = __lookup_node(f, nodeid, name);
Miklos Szeredi891b8742004-07-29 09:27:49 +0000272 if (node == NULL) {
273 err = -ENOENT;
274 break;
275 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000276 nodeid = node->nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000277 ino = node->ino;
278 }
279 }
280 pthread_mutex_unlock(&f->lock);
281 free(tmp);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282 if (!err) {
283 *nodeidp = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +0000284 *inop = ino;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000285 }
Miklos Szeredi891b8742004-07-29 09:27:49 +0000286
287 return err;
288}
289
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000290static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000291{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000292 size_t len = strlen(name);
293 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000294 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000295 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
296 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000297 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000298 strncpy(s, name, len);
299 s--;
300 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000301
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000302 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000303}
304
Miklos Szeredia13d9002004-11-02 17:32:03 +0000305static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000306{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000307 char buf[FUSE_MAX_PATH];
308 char *s = buf + FUSE_MAX_PATH - 1;
309 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000310
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000312
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000314 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000315 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000316 return NULL;
317 }
318
319 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000320 for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000321 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000322 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000323 s = NULL;
324 break;
325 }
326
327 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000328 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000329 break;
330 }
331 pthread_mutex_unlock(&f->lock);
332
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000334 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000336 return strdup("/");
337 else
338 return strdup(s);
339}
Miklos Szeredia181e612001-11-06 12:03:23 +0000340
Miklos Szeredia13d9002004-11-02 17:32:03 +0000341static char *get_path(struct fuse *f, nodeid_t nodeid)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000342{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000343 return get_path_name(f, nodeid, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000344}
345
Miklos Szeredia13d9002004-11-02 17:32:03 +0000346static void destroy_node(struct fuse *f, nodeid_t nodeid, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347{
Miklos Szeredia181e612001-11-06 12:03:23 +0000348 struct node *node;
349
350 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000351 node = __get_node(f, nodeid);
352 if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000353 unhash_name(f, node);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000354 unhash_id(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000355 free_node(node);
356 }
357 pthread_mutex_unlock(&f->lock);
358
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000359}
360
Miklos Szeredia13d9002004-11-02 17:32:03 +0000361static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000362{
Miklos Szeredia181e612001-11-06 12:03:23 +0000363 struct node *node;
364
365 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000366 node = __lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000368 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
369 dir, name);
370 abort();
371 }
372 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000373 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000374}
375
Miklos Szeredia13d9002004-11-02 17:32:03 +0000376static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
377 nodeid_t newdir, const char *newname, int hide)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000378{
Miklos Szeredia181e612001-11-06 12:03:23 +0000379 struct node *node;
380 struct node *newnode;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000381 int err = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000382
383 pthread_mutex_lock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000384 node = __lookup_node(f, olddir, oldname);
385 newnode = __lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000386 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000387 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
388 olddir, oldname);
389 abort();
390 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000391
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000392 if (newnode != NULL) {
393 if (hide) {
394 fprintf(stderr, "fuse: hidden file got created during hiding\n");
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000395 err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000396 goto out;
397 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000398 unhash_name(f, newnode);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000399 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000401 unhash_name(f, node);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000402 if (hash_name(f, node, newdir, newname) == -1) {
403 err = -ENOMEM;
404 goto out;
405 }
406
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000407 if (hide)
408 node->is_hidden = 1;
409
410 out:
Miklos Szeredia181e612001-11-06 12:03:23 +0000411 pthread_mutex_unlock(&f->lock);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000412 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000413}
414
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
416{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000417 attr->ino = stbuf->st_ino;
Miklos Szeredib5958612004-02-20 14:10:49 +0000418 attr->mode = stbuf->st_mode;
419 attr->nlink = stbuf->st_nlink;
420 attr->uid = stbuf->st_uid;
421 attr->gid = stbuf->st_gid;
422 attr->rdev = stbuf->st_rdev;
423 attr->size = stbuf->st_size;
424 attr->blocks = stbuf->st_blocks;
425 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000426 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000427 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000428#ifdef HAVE_STRUCT_STAT_ST_ATIM
429 attr->atimensec = stbuf->st_atim.tv_nsec;
430 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000431 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000432#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433}
434
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000435static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
436 ino_t ino)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437{
438 struct fuse_dirent dirent;
439 size_t reclen;
440 size_t res;
441
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000442 if ((dh->fuse->flags & FUSE_USE_INO))
443 dirent.ino = ino;
444 else
445 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000446 dirent.namelen = strlen(name);
447 strncpy(dirent.name, name, sizeof(dirent.name));
448 dirent.type = type;
449 reclen = FUSE_DIRENT_SIZE(&dirent);
450 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000451 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000452 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000453 return -EIO;
454 }
455 return 0;
456}
457
Miklos Szeredi73798f92004-07-12 15:55:11 +0000458static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
459 int locked)
Miklos Szeredi43696432001-11-18 19:15:05 +0000460{
461 int res;
462
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000464 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
465 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
466 out->error, strerror(-out->error), outsize);
467 fflush(stdout);
468 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000469
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000470 /* This needs to be done before the reply, otherwise the scheduler
471 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000472 long after the operation is done */
Miklos Szeredi73798f92004-07-12 15:55:11 +0000473 if (!locked)
474 pthread_mutex_lock(&f->lock);
475 f->numavail ++;
476 if (!locked)
477 pthread_mutex_unlock(&f->lock);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000478
Miklos Szeredi43696432001-11-18 19:15:05 +0000479 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000480 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000481 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000482 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000483 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000484 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000485 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000486 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000487}
488
Miklos Szeredi73798f92004-07-12 15:55:11 +0000489static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
490 void *arg, size_t argsize, int locked)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000491{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000492 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000493 char *outbuf;
494 size_t outsize;
495 struct fuse_out_header *out;
496
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000497 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000498 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000499 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500 }
501
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000502 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000503 argsize = 0;
504
505 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000506 outbuf = (char *) malloc(outsize);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000507 if (outbuf == NULL) {
508 fprintf(stderr, "fuse: failed to allocate reply buffer\n");
509 res = -ENOMEM;
510 } else {
511 out = (struct fuse_out_header *) outbuf;
512 memset(out, 0, sizeof(struct fuse_out_header));
513 out->unique = in->unique;
514 out->error = error;
515 if (argsize != 0)
516 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
517
518 res = send_reply_raw(f, outbuf, outsize, locked);
519 free(outbuf);
520 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000521
522 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000523}
524
Miklos Szeredi73798f92004-07-12 15:55:11 +0000525static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
526 void *arg, size_t argsize)
527{
528 return __send_reply(f, in, error, arg, argsize, 0);
529}
530
Miklos Szeredia13d9002004-11-02 17:32:03 +0000531static int is_open(struct fuse *f, nodeid_t dir, const char *name)
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000532{
533 struct node *node;
534 int isopen = 0;
535 pthread_mutex_lock(&f->lock);
536 node = __lookup_node(f, dir, name);
537 if (node && node->open_count > 0)
538 isopen = 1;
539 pthread_mutex_unlock(&f->lock);
540 return isopen;
541}
542
Miklos Szeredia13d9002004-11-02 17:32:03 +0000543static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000544 char *newname, size_t bufsize)
545{
546 struct stat buf;
547 struct node *node;
548 struct node *newnode;
549 char *newpath;
550 int res;
551 int failctr = 10;
552
553 if (!f->op.getattr)
554 return NULL;
555
556 do {
557 node = lookup_node(f, dir, oldname);
558 pthread_mutex_lock(&f->lock);
559 do {
560 f->hidectr ++;
561 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
Miklos Szeredia13d9002004-11-02 17:32:03 +0000562 (unsigned int) node->nodeid, f->hidectr);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000563 newnode = __lookup_node(f, dir, newname);
564 } while(newnode);
565 pthread_mutex_unlock(&f->lock);
566
567 newpath = get_path_name(f, dir, newname);
568 if (!newpath)
569 break;
570
571 res = f->op.getattr(newpath, &buf);
572 if (res != 0)
573 break;
574 free(newpath);
575 newpath = NULL;
576 } while(--failctr);
577
578 return newpath;
579}
580
Miklos Szeredia13d9002004-11-02 17:32:03 +0000581static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000582 const char *oldname)
583{
584 char newname[64];
585 char *newpath;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000586 int err = -EBUSY;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000587
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000588 if (f->op.rename && f->op.unlink) {
589 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
590 if (newpath) {
591 int res = f->op.rename(oldpath, newpath);
592 if (res == 0)
593 err = rename_node(f, dir, oldname, dir, newname, 1);
594 free(newpath);
595 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000596 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000597 return err;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000598}
599
Miklos Szeredia13d9002004-11-02 17:32:03 +0000600static int lookup_path(struct fuse *f, nodeid_t nodeid, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000601 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000602{
603 int res;
604 struct stat buf;
605
606 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000607 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000608 struct node *node;
609
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000610 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000611 convert_stat(&buf, &arg->attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000612 node = find_node(f, nodeid, name, &arg->attr, version);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000613 if (node == NULL)
614 res = -ENOMEM;
615 else {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000616 arg->nodeid = node->nodeid;
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000617 arg->generation = node->generation;
618 arg->entry_valid = ENTRY_REVALIDATE_TIME;
619 arg->entry_valid_nsec = 0;
620 arg->attr_valid = ATTR_REVALIDATE_TIME;
621 arg->attr_valid_nsec = 0;
622 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000623 printf(" NODEID: %li\n", arg->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000624 fflush(stdout);
625 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000626 }
627 }
628 return res;
629}
630
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
632{
633 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000634 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000635 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000636 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637
Miklos Szeredi5e183482001-10-31 14:52:35 +0000638 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000639 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000640 if (path != NULL) {
641 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000642 printf("LOOKUP %s\n", path);
643 fflush(stdout);
644 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000645 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000646 if (f->op.getattr)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000647 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000648 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000650 res2 = send_reply(f, in, res, &arg, sizeof(arg));
651 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000652 destroy_node(f, arg.nodeid, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000653}
654
Miklos Szeredia181e612001-11-06 12:03:23 +0000655static void do_forget(struct fuse *f, struct fuse_in_header *in,
656 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000657{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000658 if (f->flags & FUSE_DEBUG) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000659 printf("FORGET %li/%i\n", in->nodeid, arg->version);
Miklos Szeredi43696432001-11-18 19:15:05 +0000660 fflush(stdout);
661 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000662 destroy_node(f, in->nodeid, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000663}
664
665static void do_getattr(struct fuse *f, struct fuse_in_header *in)
666{
667 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000668 char *path;
669 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000670 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000671
Miklos Szeredi5e183482001-10-31 14:52:35 +0000672 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000673 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000674 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000676 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000677 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000678 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000679 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000680
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000681 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000682 memset(&arg, 0, sizeof(struct fuse_attr_out));
683 arg.attr_valid = ATTR_REVALIDATE_TIME;
684 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000685 convert_stat(&buf, &arg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000686 if (!(f->flags & FUSE_USE_INO))
687 arg.attr.ino = in->nodeid;
688 else {
689 struct node *node = get_node(f, in->nodeid);
690 node->ino = arg.attr.ino;
691 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000692 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000693
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000694 send_reply(f, in, res, &arg, sizeof(arg));
695}
696
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000697static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000698{
699 int res;
700
701 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000702 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000703 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000704
705 return res;
706}
707
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000708static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000709 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000710{
711 int res;
712 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
713 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
714
715 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000716 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000717 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000718
719 return res;
720}
721
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000722static int do_truncate(struct fuse *f, const char *path,
723 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000724{
725 int res;
726
727 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000728 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000729 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000730
731 return res;
732}
733
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000734static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000735{
736 int res;
737 struct utimbuf buf;
738 buf.actime = attr->atime;
739 buf.modtime = attr->mtime;
740 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000741 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000742 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000743
744 return res;
745}
746
Miklos Szeredi5e183482001-10-31 14:52:35 +0000747static void do_setattr(struct fuse *f, struct fuse_in_header *in,
748 struct fuse_setattr_in *arg)
749{
750 int res;
751 char *path;
752 int valid = arg->valid;
753 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000754 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000755
756 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000757 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000758 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000759 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000760 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000761 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000762 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000763 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000764 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000765 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000766 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000767 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000768 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000769 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000770 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000771 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000772 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000773 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000774 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000775 memset(&outarg, 0, sizeof(struct fuse_attr_out));
776 outarg.attr_valid = ATTR_REVALIDATE_TIME;
777 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000778 convert_stat(&buf, &outarg.attr);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000779 if (!(f->flags & FUSE_USE_INO))
780 outarg.attr.ino = in->nodeid;
781 else {
782 struct node *node = get_node(f, in->nodeid);
783 node->ino = outarg.attr.ino;
784 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000785 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000786 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000788 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000789 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000790 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791}
792
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000793static void do_readlink(struct fuse *f, struct fuse_in_header *in)
794{
795 int res;
796 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000797 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000798
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000800 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000801 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000802 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000803 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000804 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000805 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000806 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000807 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000808 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000809}
810
811static void do_getdir(struct fuse *f, struct fuse_in_header *in)
812{
813 int res;
814 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000815 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000816 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000817
Miklos Szeredib483c932001-10-29 14:57:57 +0000818 dh.fuse = f;
819 dh.fp = tmpfile();
Miklos Szeredia13d9002004-11-02 17:32:03 +0000820 dh.dir = in->nodeid;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000821
Miklos Szeredi65afea12004-09-14 07:13:45 +0000822 res = -EIO;
823 if (dh.fp == NULL)
824 perror("fuse: failed to create temporary file");
825 else {
826 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000827 path = get_path(f, in->nodeid);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000828 if (path != NULL) {
829 res = -ENOSYS;
830 if (f->op.getdir)
Miklos Szeredi8fb48fe2004-11-08 14:48:52 +0000831 res = f->op.getdir(path, &dh, fill_dir);
Miklos Szeredi65afea12004-09-14 07:13:45 +0000832 free(path);
833 }
834 fflush(dh.fp);
835 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000836 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000837 if (res == 0)
838 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000839 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredi65afea12004-09-14 07:13:45 +0000840 if (dh.fp != NULL)
841 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000842}
843
Miklos Szeredib483c932001-10-29 14:57:57 +0000844static void do_mknod(struct fuse *f, struct fuse_in_header *in,
845 struct fuse_mknod_in *inarg)
846{
847 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000848 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000849 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000850 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000851 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000852
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000854 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000855 if (path != NULL) {
856 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000857 printf("MKNOD %s\n", path);
858 fflush(stdout);
859 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000860 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000862 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000863 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000864 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000865 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000866 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000867 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000868 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
869 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000870 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000871}
872
873static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
874 struct fuse_mkdir_in *inarg)
875{
876 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000877 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000878 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000879 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000880 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000881
Miklos Szeredi5e183482001-10-31 14:52:35 +0000882 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000883 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000884 if (path != NULL) {
885 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000886 printf("MKDIR %s\n", path);
887 fflush(stdout);
888 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000890 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000891 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000893 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000894 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000895 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000896 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000897 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
898 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000899 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000900}
901
Miklos Szeredib5958612004-02-20 14:10:49 +0000902static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000903{
904 int res;
905 char *path;
906
Miklos Szeredi5e183482001-10-31 14:52:35 +0000907 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000908 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000909 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000910 if (f->flags & FUSE_DEBUG) {
911 printf("UNLINK %s\n", path);
912 fflush(stdout);
913 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000914 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 if (f->op.unlink) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000916 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
917 res = hide_node(f, path, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000918 else {
919 res = f->op.unlink(path);
920 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000921 remove_node(f, in->nodeid, name);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000922 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000923 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000924 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000925 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000926 send_reply(f, in, res, NULL, 0);
927}
928
929static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
930{
931 int res;
932 char *path;
933
934 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000935 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000937 if (f->flags & FUSE_DEBUG) {
938 printf("RMDIR %s\n", path);
939 fflush(stdout);
940 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000941 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000943 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000944 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000945 remove_node(f, in->nodeid, name);
Miklos Szeredib5958612004-02-20 14:10:49 +0000946 }
947 free(path);
948 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000949 send_reply(f, in, res, NULL, 0);
950}
951
952static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
953 char *link)
954{
955 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000956 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000957 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000958 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000959
Miklos Szeredi5e183482001-10-31 14:52:35 +0000960 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000961 path = get_path_name(f, in->nodeid, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 if (path != NULL) {
963 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000964 printf("SYMLINK %s\n", path);
965 fflush(stdout);
966 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000967 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000968 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000969 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000970 if (res == 0)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000971 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000972 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000973 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000974 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000975 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
976 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000977 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000978
Miklos Szeredib483c932001-10-29 14:57:57 +0000979}
980
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000981static void do_rename(struct fuse *f, struct fuse_in_header *in,
982 struct fuse_rename_in *inarg)
983{
984 int res;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000985 nodeid_t olddir = in->nodeid;
986 nodeid_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000987 char *oldname = PARAM(inarg);
988 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000989 char *oldpath;
990 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000991
Miklos Szeredi5e183482001-10-31 14:52:35 +0000992 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000993 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000995 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 if (newpath != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000997 if (f->flags & FUSE_DEBUG) {
998 printf("RENAME %s -> %s\n", oldpath, newpath);
999 fflush(stdout);
1000 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001001 res = -ENOSYS;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001002 if (f->op.rename) {
1003 res = 0;
Miklos Szeredi2529ca22004-07-13 15:36:52 +00001004 if (!(f->flags & FUSE_HARD_REMOVE) &&
1005 is_open(f, newdir, newname))
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001006 res = hide_node(f, newpath, newdir, newname);
1007 if (res == 0) {
1008 res = f->op.rename(oldpath, newpath);
1009 if (res == 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001010 res = rename_node(f, olddir, oldname, newdir, newname, 0);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001011 }
1012 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001013 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001014 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001015 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001016 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001017 send_reply(f, in, res, NULL, 0);
1018}
1019
1020static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +00001021 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001022{
1023 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001024 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001025 char *oldpath;
1026 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001027 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001028 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001029
Miklos Szeredi5e183482001-10-31 14:52:35 +00001030 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001031 oldpath = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001032 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001033 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034 if (newpath != NULL) {
1035 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +00001036 printf("LINK %s\n", newpath);
1037 fflush(stdout);
1038 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001039 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001040 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +00001041 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001042 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +00001043 res = lookup_path(f, arg->newdir, in->unique, name,
1044 newpath, &outarg);
1045 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001046 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001047 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001048 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001049 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +00001050 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
1051 if (res == 0 && res2 == -ENOENT)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001052 destroy_node(f, outarg.nodeid, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001053}
1054
Miklos Szeredi5e183482001-10-31 14:52:35 +00001055static void do_open(struct fuse *f, struct fuse_in_header *in,
1056 struct fuse_open_in *arg)
1057{
1058 int res;
1059 char *path;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001060 struct fuse_open_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001061 struct fuse_file_info fi;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001062
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001063 memset(&fi, 0, sizeof(fi));
1064 fi.flags = arg->flags;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001065 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001066 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001067 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +00001068 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001069 if (f->op.open)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001070 res = f->op.open(path, &fi);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +00001071 }
Miklos Szeredi73798f92004-07-12 15:55:11 +00001072 if (res == 0) {
1073 int res2;
1074
1075 /* If the request is interrupted the lock must be held until
1076 the cancellation is finished. Otherwise there could be
1077 races with rename/unlink, against which the kernel can't
1078 protect */
1079 pthread_mutex_lock(&f->lock);
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001080 outarg.fh = fi.fh;
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001081 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001082 printf("OPEN[%lu] flags: 0x%x\n", outarg.fh, arg->flags);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001083 fflush(stdout);
1084 }
1085
1086 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001087 if(res2 == -ENOENT) {
1088 /* The open syscall was interrupted, so it must be cancelled */
1089 if(f->op.release)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001090 f->op.release(path, &fi);
Miklos Szeredi73798f92004-07-12 15:55:11 +00001091 } else
Miklos Szeredia13d9002004-11-02 17:32:03 +00001092 get_node(f, in->nodeid)->open_count ++;
Miklos Szeredi73798f92004-07-12 15:55:11 +00001093 pthread_mutex_unlock(&f->lock);
1094
1095 } else
1096 send_reply(f, in, res, NULL, 0);
1097
Miklos Szeredi9a31cca2004-06-26 21:11:25 +00001098 if (path)
1099 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001100}
1101
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001102static void do_flush(struct fuse *f, struct fuse_in_header *in,
1103 struct fuse_flush_in *arg)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001104{
1105 char *path;
1106 int res;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001107 struct fuse_file_info fi;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001108
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001109 memset(&fi, 0, sizeof(fi));
1110 fi.fh = arg->fh;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001111 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001112 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001113 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001114 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001115 printf("FLUSH[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001116 fflush(stdout);
1117 }
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001118 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001119 if (f->op.flush)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001120 res = f->op.flush(path, &fi);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001121 free(path);
1122 }
1123 send_reply(f, in, res, NULL, 0);
1124}
1125
Miklos Szeredi9478e862002-12-11 09:50:26 +00001126static void do_release(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001127 struct fuse_release_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001128{
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001129 struct node *node;
1130 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001131 struct fuse_file_info fi;
1132
1133 memset(&fi, 0, sizeof(fi));
1134 fi.flags = arg->flags;
1135 fi.fh = arg->fh;
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001136
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001137 pthread_mutex_lock(&f->lock);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001138 node = get_node(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001139 --node->open_count;
1140 pthread_mutex_unlock(&f->lock);
1141
Miklos Szeredia13d9002004-11-02 17:32:03 +00001142 path = get_path(f, in->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001143 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001144 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001145 printf("RELEASE[%lu]\n", arg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001146 fflush(stdout);
1147 }
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001148 if (f->op.release)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001149 f->op.release(path, &fi);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001150
1151 if(node->is_hidden && node->open_count == 0)
1152 /* can now clean up this hidden file */
1153 f->op.unlink(path);
1154
1155 free(path);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001156 }
Miklos Szeredi556d03d2004-06-30 11:13:41 +00001157 send_reply(f, in, 0, NULL, 0);
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001158}
1159
Miklos Szeredi5e183482001-10-31 14:52:35 +00001160static void do_read(struct fuse *f, struct fuse_in_header *in,
1161 struct fuse_read_in *arg)
1162{
1163 int res;
1164 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +00001165 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001166 if (outbuf == NULL)
1167 send_reply(f, in, -ENOMEM, NULL, 0);
1168 else {
1169 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1170 char *buf = outbuf + sizeof(struct fuse_out_header);
1171 size_t size;
1172 size_t outsize;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001173 struct fuse_file_info fi;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001174
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001175 memset(&fi, 0, sizeof(fi));
1176 fi.fh = arg->fh;
1177
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001178 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001179 path = get_path(f, in->nodeid);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001180 if (path != NULL) {
1181 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001182 printf("READ[%lu] %u bytes from %llu\n", arg->fh, arg->size,
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001183 arg->offset);
1184 fflush(stdout);
1185 }
1186
1187 res = -ENOSYS;
1188 if (f->op.read)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001189 res = f->op.read(path, buf, arg->size, arg->offset, &fi);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001190 free(path);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001191 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001192
1193 size = 0;
1194 if (res >= 0) {
1195 size = res;
1196 res = 0;
1197 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001198 printf(" READ[%lu] %u bytes\n", arg->fh, size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001199 fflush(stdout);
1200 }
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001201 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001202 memset(out, 0, sizeof(struct fuse_out_header));
1203 out->unique = in->unique;
1204 out->error = res;
1205 outsize = sizeof(struct fuse_out_header) + size;
1206
1207 send_reply_raw(f, outbuf, outsize, 0);
1208 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +00001209 }
Miklos Szeredi5e183482001-10-31 14:52:35 +00001210}
Miklos Szeredib483c932001-10-29 14:57:57 +00001211
Miklos Szeredia181e612001-11-06 12:03:23 +00001212static void do_write(struct fuse *f, struct fuse_in_header *in,
1213 struct fuse_write_in *arg)
1214{
1215 int res;
1216 char *path;
Miklos Szerediad051c32004-07-02 09:22:50 +00001217 struct fuse_write_out outarg;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001218 struct fuse_file_info fi;
1219
1220 memset(&fi, 0, sizeof(fi));
1221 fi.fh = arg->fh;
Miklos Szeredia181e612001-11-06 12:03:23 +00001222
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001223 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001224 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001225 if (path != NULL) {
1226 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001227 printf("WRITE%s[%lu] %u bytes to %llu\n",
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001228 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1229 arg->offset);
Miklos Szeredi6ebe2342002-01-06 21:44:16 +00001230 fflush(stdout);
1231 }
1232
Miklos Szeredia181e612001-11-06 12:03:23 +00001233 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001234 if (f->op.write)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001235 res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001236 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +00001237 }
1238
Miklos Szerediad051c32004-07-02 09:22:50 +00001239 if (res >= 0) {
1240 outarg.size = res;
1241 res = 0;
Miklos Szeredia181e612001-11-06 12:03:23 +00001242 }
1243
Miklos Szerediad051c32004-07-02 09:22:50 +00001244 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredia181e612001-11-06 12:03:23 +00001245}
1246
Miklos Szeredi77f39942004-03-25 11:17:52 +00001247static int default_statfs(struct statfs *buf)
1248{
1249 buf->f_namelen = 255;
1250 buf->f_bsize = 512;
1251 return 0;
1252}
1253
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001254static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1255{
1256 kstatfs->bsize = statfs->f_bsize;
1257 kstatfs->blocks = statfs->f_blocks;
1258 kstatfs->bfree = statfs->f_bfree;
1259 kstatfs->bavail = statfs->f_bavail;
1260 kstatfs->files = statfs->f_files;
1261 kstatfs->ffree = statfs->f_ffree;
1262 kstatfs->namelen = statfs->f_namelen;
1263}
1264
Mark Glinesd84b39a2002-01-07 16:32:02 +00001265static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1266{
1267 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001268 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001269 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +00001270
Miklos Szeredi77f39942004-03-25 11:17:52 +00001271 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001272 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +00001273 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +00001274 else
1275 res = default_statfs(&buf);
1276
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001277 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +00001278 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +00001279
Mark Glinesd84b39a2002-01-07 16:32:02 +00001280 send_reply(f, in, res, &arg, sizeof(arg));
1281}
1282
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001283static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1284 struct fuse_fsync_in *inarg)
1285{
1286 int res;
1287 char *path;
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001288 struct fuse_file_info fi;
1289
1290 memset(&fi, 0, sizeof(fi));
1291 fi.fh = inarg->fh;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001292
1293 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001294 path = get_path(f, in->nodeid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001295 if (path != NULL) {
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001296 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi1eea0322004-09-27 18:50:11 +00001297 printf("FSYNC[%lu]\n", inarg->fh);
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001298 fflush(stdout);
1299 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001300 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001301 if (f->op.fsync)
Miklos Szeredifb28c5e2004-11-26 12:15:06 +00001302 res = f->op.fsync(path, inarg->datasync, &fi);
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001303 free(path);
1304 }
1305 send_reply(f, in, res, NULL, 0);
1306}
1307
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001308static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1309 struct fuse_setxattr_in *arg)
1310{
1311 int res;
1312 char *path;
1313 char *name = PARAM(arg);
1314 unsigned char *value = name + strlen(name) + 1;
1315
1316 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001317 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001318 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001319 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001320 if (f->op.setxattr)
1321 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1322 free(path);
1323 }
1324 send_reply(f, in, res, NULL, 0);
1325}
1326
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001327static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1328 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001329{
1330 int res;
1331 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001332
1333 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001334 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001335 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001336 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001337 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001338 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001339 free(path);
1340 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001341 return res;
1342}
1343
1344static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1345 const char *name, size_t size)
1346{
1347 int res;
1348 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001349 if (outbuf == NULL)
1350 send_reply(f, in, -ENOMEM, NULL, 0);
1351 else {
1352 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1353 char *value = outbuf + sizeof(struct fuse_out_header);
1354
1355 res = common_getxattr(f, in, name, value, size);
1356 size = 0;
1357 if (res > 0) {
1358 size = res;
1359 res = 0;
1360 }
1361 memset(out, 0, sizeof(struct fuse_out_header));
1362 out->unique = in->unique;
1363 out->error = res;
1364
1365 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1366 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001367 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001368}
1369
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001370static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1371 const char *name)
1372{
1373 int res;
1374 struct fuse_getxattr_out arg;
1375
1376 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001377 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001378 arg.size = res;
1379 res = 0;
1380 }
1381 send_reply(f, in, res, &arg, sizeof(arg));
1382}
1383
1384static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1385 struct fuse_getxattr_in *arg)
1386{
1387 char *name = PARAM(arg);
1388
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001389 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001390 do_getxattr_read(f, in, name, arg->size);
1391 else
1392 do_getxattr_size(f, in, name);
1393}
1394
1395static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1396 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001397{
1398 int res;
1399 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001400
1401 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001402 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001403 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001404 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001405 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001406 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001407 free(path);
1408 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001409 return res;
1410}
1411
1412static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1413 size_t size)
1414{
1415 int res;
1416 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001417 if (outbuf == NULL)
1418 send_reply(f, in, -ENOMEM, NULL, 0);
1419 else {
1420 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1421 char *list = outbuf + sizeof(struct fuse_out_header);
1422
1423 res = common_listxattr(f, in, list, size);
1424 size = 0;
1425 if (res > 0) {
1426 size = res;
1427 res = 0;
1428 }
1429 memset(out, 0, sizeof(struct fuse_out_header));
1430 out->unique = in->unique;
1431 out->error = res;
1432
1433 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1434 free(outbuf);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001435 }
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001436}
1437
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001438static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1439{
1440 int res;
1441 struct fuse_getxattr_out arg;
1442
1443 res = common_listxattr(f, in, NULL, 0);
1444 if (res >= 0) {
1445 arg.size = res;
1446 res = 0;
1447 }
1448 send_reply(f, in, res, &arg, sizeof(arg));
1449}
1450
1451static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1452 struct fuse_getxattr_in *arg)
1453{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001454 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001455 do_listxattr_read(f, in, arg->size);
1456 else
1457 do_listxattr_size(f, in);
1458}
1459
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001460static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1461 char *name)
1462{
1463 int res;
1464 char *path;
1465
1466 res = -ENOENT;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001467 path = get_path(f, in->nodeid);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001468 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001469 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001470 if (f->op.removexattr)
1471 res = f->op.removexattr(path, name);
1472 free(path);
1473 }
1474 send_reply(f, in, res, NULL, 0);
1475}
1476
1477
Miklos Szeredi43696432001-11-18 19:15:05 +00001478static void free_cmd(struct fuse_cmd *cmd)
1479{
1480 free(cmd->buf);
1481 free(cmd);
1482}
1483
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001484void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001485{
Miklos Szeredia181e612001-11-06 12:03:23 +00001486 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1487 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1488 size_t argsize;
Miklos Szeredid169f312004-09-22 08:48:26 +00001489 struct fuse_context *ctx = fuse_get_context();
Miklos Szeredia181e612001-11-06 12:03:23 +00001490
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001491 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001492
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001493 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001494 printf("unique: %i, opcode: %s (%i), nodeid: %li, insize: %i\n",
1495 in->unique, opname(in->opcode), in->opcode, in->nodeid,
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001496 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001497 fflush(stdout);
1498 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001499
Miklos Szeredid169f312004-09-22 08:48:26 +00001500 ctx->fuse = f;
Miklos Szeredife25def2001-12-20 15:38:05 +00001501 ctx->uid = in->uid;
1502 ctx->gid = in->gid;
Miklos Szeredi1f18db52004-09-27 06:54:49 +00001503 ctx->pid = in->pid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001504
1505 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1506
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001507 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001508 case FUSE_LOOKUP:
1509 do_lookup(f, in, (char *) inarg);
1510 break;
1511
Miklos Szeredia181e612001-11-06 12:03:23 +00001512 case FUSE_GETATTR:
1513 do_getattr(f, in);
1514 break;
1515
1516 case FUSE_SETATTR:
1517 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1518 break;
1519
1520 case FUSE_READLINK:
1521 do_readlink(f, in);
1522 break;
1523
1524 case FUSE_GETDIR:
1525 do_getdir(f, in);
1526 break;
1527
1528 case FUSE_MKNOD:
1529 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1530 break;
1531
1532 case FUSE_MKDIR:
1533 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1534 break;
1535
1536 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001537 do_unlink(f, in, (char *) inarg);
1538 break;
1539
Miklos Szeredia181e612001-11-06 12:03:23 +00001540 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001541 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001542 break;
1543
1544 case FUSE_SYMLINK:
1545 do_symlink(f, in, (char *) inarg,
1546 ((char *) inarg) + strlen((char *) inarg) + 1);
1547 break;
1548
1549 case FUSE_RENAME:
1550 do_rename(f, in, (struct fuse_rename_in *) inarg);
1551 break;
1552
1553 case FUSE_LINK:
1554 do_link(f, in, (struct fuse_link_in *) inarg);
1555 break;
1556
1557 case FUSE_OPEN:
1558 do_open(f, in, (struct fuse_open_in *) inarg);
1559 break;
1560
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001561 case FUSE_FLUSH:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001562 do_flush(f, in, (struct fuse_flush_in *) inarg);
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001563 break;
1564
Miklos Szeredi9478e862002-12-11 09:50:26 +00001565 case FUSE_RELEASE:
Miklos Szeredi209f5d02004-07-24 19:56:16 +00001566 do_release(f, in, (struct fuse_release_in *) inarg);
Miklos Szeredi9478e862002-12-11 09:50:26 +00001567 break;
1568
Miklos Szeredia181e612001-11-06 12:03:23 +00001569 case FUSE_READ:
1570 do_read(f, in, (struct fuse_read_in *) inarg);
1571 break;
1572
1573 case FUSE_WRITE:
1574 do_write(f, in, (struct fuse_write_in *) inarg);
1575 break;
1576
Mark Glinesd84b39a2002-01-07 16:32:02 +00001577 case FUSE_STATFS:
1578 do_statfs(f, in);
1579 break;
1580
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001581 case FUSE_FSYNC:
1582 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1583 break;
1584
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001585 case FUSE_SETXATTR:
1586 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1587 break;
1588
1589 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001590 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001591 break;
1592
1593 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001594 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001595 break;
1596
1597 case FUSE_REMOVEXATTR:
1598 do_removexattr(f, in, (char *) inarg);
1599 break;
1600
Miklos Szeredia181e612001-11-06 12:03:23 +00001601 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001602 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001603 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001604
1605 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001606}
1607
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001608int __fuse_exited(struct fuse* f)
1609{
1610 return f->exited;
1611}
1612
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001613struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001614{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001615 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001616 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001617 struct fuse_in_header *in;
1618 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001619
Miklos Szeredi43696432001-11-18 19:15:05 +00001620 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001621 if (cmd == NULL) {
1622 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1623 return NULL;
1624 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001625 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001626 if (cmd->buf == NULL) {
1627 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1628 free(cmd);
1629 return NULL;
1630 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001631 in = (struct fuse_in_header *) cmd->buf;
1632 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001633
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001634 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1635 if (res == -1) {
1636 free_cmd(cmd);
1637 if (__fuse_exited(f) || errno == EINTR)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001638 return NULL;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001639
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001640 /* ENODEV means we got unmounted, so we silenty return failure */
1641 if (errno != ENODEV) {
1642 /* BAD... This will happen again */
1643 perror("fuse: reading device");
1644 }
1645
1646 fuse_exit(f);
1647 return NULL;
1648 }
1649 if ((size_t) res < sizeof(struct fuse_in_header)) {
1650 free_cmd(cmd);
1651 /* Cannot happen */
1652 fprintf(stderr, "short read on fuse device\n");
1653 fuse_exit(f);
1654 return NULL;
1655 }
1656 cmd->buflen = res;
1657
1658 /* Forget is special, it can be done without messing with threads. */
1659 if (in->opcode == FUSE_FORGET) {
1660 do_forget(f, in, (struct fuse_forget_in *) inarg);
1661 free_cmd(cmd);
1662 return NULL;
1663 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001664
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001665 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001666}
1667
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001668int fuse_loop(struct fuse *f)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001669{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001670 if (f == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001671 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001672
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001673 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001674 struct fuse_cmd *cmd;
1675
Miklos Szeredi65cf7c72004-06-30 11:34:56 +00001676 if (__fuse_exited(f))
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001677 break;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001678
1679 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001680 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001681 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001682
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001683 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001684 }
Miklos Szeredi874e3c12004-11-01 23:15:20 +00001685 f->exited = 0;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001686 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001687}
1688
Miklos Szeredi891b8742004-07-29 09:27:49 +00001689int fuse_invalidate(struct fuse *f, const char *path)
1690{
1691 int res;
1692 int err;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001693 nodeid_t nodeid;
1694 unsigned long ino;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001695 struct fuse_user_header h;
1696
Miklos Szeredia13d9002004-11-02 17:32:03 +00001697 err = path_lookup(f, path, &nodeid, &ino);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001698 if (err) {
1699 if (err == -ENOENT)
1700 return 0;
1701 else
1702 return err;
1703 }
1704
1705 memset(&h, 0, sizeof(struct fuse_user_header));
1706 h.opcode = FUSE_INVALIDATE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001707 h.nodeid = nodeid;
Miklos Szeredi891b8742004-07-29 09:27:49 +00001708 h.ino = ino;
1709
1710 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001711 printf("INVALIDATE nodeid: %li\n", nodeid);
Miklos Szeredi891b8742004-07-29 09:27:49 +00001712 fflush(stdout);
1713 }
1714
1715 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1716 if (res == -1) {
1717 if (errno != ENOENT) {
1718 perror("fuse: writing device");
1719 return -errno;
1720 }
1721 }
1722 return 0;
1723}
1724
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001725void fuse_exit(struct fuse *f)
1726{
1727 f->exited = 1;
1728}
1729
Miklos Szeredid169f312004-09-22 08:48:26 +00001730struct fuse_context *fuse_get_context()
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001731{
Miklos Szeredid169f312004-09-22 08:48:26 +00001732 static struct fuse_context context;
1733 if (fuse_getcontext)
1734 return fuse_getcontext();
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001735 else
Miklos Szeredid169f312004-09-22 08:48:26 +00001736 return &context;
1737}
1738
1739void __fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1740{
1741 fuse_getcontext = func;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001742}
1743
Miklos Szeredic40748a2004-02-20 16:38:45 +00001744static int check_version(struct fuse *f)
1745{
1746 int res;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001747 const char *version_file = FUSE_VERSION_FILE;
1748 FILE *vf = fopen(version_file, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001749 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001750 version_file = FUSE_VERSION_FILE_OLD;
Miklos Szeredif3845c42004-11-20 11:18:34 +00001751 vf = fopen(version_file, "r");
1752 if (vf == NULL) {
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001753 struct stat tmp;
1754 if (stat(FUSE_DEV_OLD, &tmp) != -1) {
1755 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1756 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1757 return -1;
1758 } else {
1759 fprintf(stderr, "fuse: warning: version of kernel interface unknown\n");
1760 return 0;
1761 }
Miklos Szeredif3845c42004-11-20 11:18:34 +00001762 }
Miklos Szeredic40748a2004-02-20 16:38:45 +00001763 }
1764 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1765 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001766 if (res != 2) {
Miklos Szeredif3845c42004-11-20 11:18:34 +00001767 fprintf(stderr, "fuse: error reading %s\n", version_file);
Miklos Szeredic40748a2004-02-20 16:38:45 +00001768 return -1;
1769 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001770 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001771 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1772 FUSE_KERNEL_VERSION);
1773 return -1;
1774 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001775 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredi256739a2004-11-20 12:22:37 +00001776 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n",
Miklos Szeredic40748a2004-02-20 16:38:45 +00001777 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1778 return -1;
1779 }
1780
1781 return 0;
1782}
1783
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001784
1785int fuse_is_lib_option(const char *opt)
1786{
1787 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredia13d9002004-11-02 17:32:03 +00001788 strcmp(opt, "hard_remove") == 0 ||
1789 strcmp(opt, "use_ino") == 0)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001790 return 1;
1791 else
1792 return 0;
1793}
1794
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001795static int parse_lib_opts(struct fuse *f, const char *opts)
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001796{
1797 if (opts) {
1798 char *xopts = strdup(opts);
1799 char *s = xopts;
1800 char *opt;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001801
1802 if (xopts == NULL)
1803 return -1;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001804
1805 while((opt = strsep(&s, ","))) {
1806 if (strcmp(opt, "debug") == 0)
1807 f->flags |= FUSE_DEBUG;
1808 else if (strcmp(opt, "hard_remove") == 0)
1809 f->flags |= FUSE_HARD_REMOVE;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001810 else if (strcmp(opt, "use_ino") == 0)
1811 f->flags |= FUSE_USE_INO;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001812 else
1813 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1814 }
1815 free(xopts);
1816 }
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001817 return 0;
Miklos Szeredibd7661b2004-07-23 17:16:29 +00001818}
1819
1820struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001821{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001822 struct fuse *f;
1823 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001824
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001825 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001826 if (f == NULL)
1827 goto out;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001828
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001829 if (check_version(f) == -1)
1830 goto out_free;
Miklos Szeredic40748a2004-02-20 16:38:45 +00001831
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001832 if (parse_lib_opts(f, opts) == -1)
1833 goto out_free;
1834
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001835 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001836 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001837 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001838 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001839 f->name_table_size = 14057;
1840 f->name_table = (struct node **)
1841 calloc(1, sizeof(struct node *) * f->name_table_size);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001842 if (f->name_table == NULL)
1843 goto out_free;
1844
Miklos Szeredia13d9002004-11-02 17:32:03 +00001845 f->id_table_size = 14057;
1846 f->id_table = (struct node **)
1847 calloc(1, sizeof(struct node *) * f->id_table_size);
1848 if (f->id_table == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001849 goto out_free_name_table;
1850
Miklos Szeredia25d4c22004-11-23 22:32:16 +00001851#ifndef USE_UCLIBC
1852 pthread_mutex_init(&f->lock, NULL);
1853#else
1854 {
1855 pthread_mutexattr_t attr;
1856 pthread_mutexattr_init(&attr);
1857 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
1858 pthread_mutex_init(&f->lock, &attr);
1859 pthread_mutexattr_destroy(&attr);
1860 }
1861#endif
Miklos Szeredi33232032001-11-19 17:55:51 +00001862 f->numworker = 0;
1863 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001864 f->op = *op;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001865 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001866
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001867 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001868 if (root == NULL)
Miklos Szeredia13d9002004-11-02 17:32:03 +00001869 goto out_free_id_table;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001870
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001871 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001872 root->rdev = 0;
1873 root->name = strdup("/");
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001874 if (root->name == NULL)
1875 goto out_free_root;
1876
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001877 root->parent = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001878 root->nodeid = FUSE_ROOT_ID;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001879 root->generation = 0;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001880 hash_id(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001881
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001882 return f;
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001883
1884 out_free_root:
1885 free(root);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001886 out_free_id_table:
1887 free(f->id_table);
Miklos Szeredib2cf9562004-09-16 08:42:40 +00001888 out_free_name_table:
1889 free(f->name_table);
1890 out_free:
1891 free(f);
1892 out:
1893 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1894 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001895}
1896
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001897void fuse_destroy(struct fuse *f)
1898{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001899 size_t i;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001900 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001901 struct node *node;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001902
Miklos Szeredia13d9002004-11-02 17:32:03 +00001903 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001904 if (node->is_hidden) {
Miklos Szeredia13d9002004-11-02 17:32:03 +00001905 char *path = get_path(f, node->nodeid);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001906 if (path)
1907 f->op.unlink(path);
1908 }
1909 }
1910 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001911 for (i = 0; i < f->id_table_size; i++) {
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001912 struct node *node;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001913 struct node *next;
Miklos Szeredi1ea9c962004-06-24 21:00:00 +00001914
Miklos Szeredia13d9002004-11-02 17:32:03 +00001915 for (node = f->id_table[i]; node != NULL; node = next) {
1916 next = node->id_next;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001917 free_node(node);
1918 }
1919 }
Miklos Szeredia13d9002004-11-02 17:32:03 +00001920 free(f->id_table);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001921 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001922 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001923 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001924}