blob: 00094562c6812facb97a96a71ffdff030667a3d8 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
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 Szeredic8ba2372002-12-10 12:26:00 +000026static const char *opname(enum fuse_opcode opcode)
27{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000028 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000029 case FUSE_LOOKUP: return "LOOKUP";
30 case FUSE_FORGET: return "FORGET";
31 case FUSE_GETATTR: return "GETATTR";
32 case FUSE_SETATTR: return "SETATTR";
33 case FUSE_READLINK: return "READLINK";
34 case FUSE_SYMLINK: return "SYMLINK";
35 case FUSE_GETDIR: return "GETDIR";
36 case FUSE_MKNOD: return "MKNOD";
37 case FUSE_MKDIR: return "MKDIR";
38 case FUSE_UNLINK: return "UNLINK";
39 case FUSE_RMDIR: return "RMDIR";
40 case FUSE_RENAME: return "RENAME";
41 case FUSE_LINK: return "LINK";
42 case FUSE_OPEN: return "OPEN";
43 case FUSE_READ: return "READ";
44 case FUSE_WRITE: return "WRITE";
45 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000046 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000047 case FUSE_RELEASE: return "RELEASE";
48 case FUSE_FSYNC: return "FSYNC";
49 case FUSE_SETXATTR: return "SETXATTR";
50 case FUSE_GETXATTR: return "GETXATTR";
51 case FUSE_LISTXATTR: return "LISTXATTR";
52 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000053 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000054 }
55}
56
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000057static inline void inc_avail(struct fuse *f)
58{
59 pthread_mutex_lock(&f->lock);
60 f->numavail ++;
61 pthread_mutex_unlock(&f->lock);
62}
63
64static inline void dec_avail(struct fuse *f)
65{
66 pthread_mutex_lock(&f->lock);
67 f->numavail --;
68 pthread_mutex_unlock(&f->lock);
69}
70
Miklos Szeredi97c61e92001-11-07 12:09:43 +000071static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000072{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000073 size_t hash = ino % f->ino_table_size;
74 struct node *node;
75
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000076 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
77 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000078 return node;
79
80 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000081}
82
Miklos Szeredi97c61e92001-11-07 12:09:43 +000083static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000084{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000085 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000086 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000087 return node;
88
89 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
90 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000091}
92
Miklos Szeredi76f65782004-02-19 16:55:40 +000093static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094{
Miklos Szeredi76f65782004-02-19 16:55:40 +000095 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000096 node->ino_next = f->ino_table[hash];
97 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000098}
99
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000100static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000101{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000102 size_t hash = node->ino % f->ino_table_size;
103 struct node **nodep = &f->ino_table[hash];
104
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000105 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
106 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000107 *nodep = node->ino_next;
108 return;
109 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000110}
111
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000112static fino_t next_ino(struct fuse *f)
113{
Miklos Szeredi76f65782004-02-19 16:55:40 +0000114 do {
115 f->ctr++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000116 if (!f->ctr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000117 f->generation ++;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000118 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000119 return f->ctr;
120}
121
122static void free_node(struct node *node)
123{
124 free(node->name);
125 free(node);
126}
127
128static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
129{
130 unsigned int hash = *name;
131
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000132 if (hash)
133 for (name += 1; *name != '\0'; name++)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000134 hash = (hash << 5) - hash + *name;
135
136 return (hash + parent) % f->name_table_size;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000137}
138
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139static struct node *lookup_node(struct fuse *f, fino_t parent,
140 const char *name)
141{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000142 size_t hash = name_hash(f, parent, name);
143 struct node *node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000144
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000145 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
146 if (node->parent == parent && strcmp(node->name, name) == 0)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000147 return node;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000148
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000149 return NULL;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000150}
151
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000152static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000153 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000154{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000155 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000156 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000157 node->name = strdup(name);
158 node->name_next = f->name_table[hash];
159 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000160}
161
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000162static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000163{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000164 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000165 size_t hash = name_hash(f, node->parent, node->name);
166 struct node **nodep = &f->name_table[hash];
167
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000168 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
169 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000170 *nodep = node->name_next;
171 node->name_next = NULL;
172 free(node->name);
173 node->name = NULL;
174 node->parent = 0;
175 return;
176 }
177 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
178 node->ino);
179 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000180 }
181}
182
Miklos Szeredi76f65782004-02-19 16:55:40 +0000183static struct node *find_node(struct fuse *f, fino_t parent, char *name,
184 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000185{
186 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000187 int mode = attr->mode & S_IFMT;
188 int rdev = 0;
189
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000190 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000191 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000192
Miklos Szeredia181e612001-11-06 12:03:23 +0000193 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000194 node = lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000195 if (node != NULL) {
196 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000197 goto out;
198
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000199 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000200 }
201
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000202 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000203 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000204 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000205 node->ino = next_ino(f);
206 node->generation = f->generation;
207 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000208 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000209
210 out:
211 node->version = version;
212 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000213 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000214}
215
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000216static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000218 size_t len = strlen(name);
219 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000220 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000221 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
222 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000224 strncpy(s, name, len);
225 s--;
226 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000227
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000228 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000229}
230
Miklos Szeredia181e612001-11-06 12:03:23 +0000231static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000232{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000233 char buf[FUSE_MAX_PATH];
234 char *s = buf + FUSE_MAX_PATH - 1;
235 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000236
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000237 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000238
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000239 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000240 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000241 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000242 return NULL;
243 }
244
245 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000246 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000247 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000248 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000249 s = NULL;
250 break;
251 }
252
253 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000254 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000255 break;
256 }
257 pthread_mutex_unlock(&f->lock);
258
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000260 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000261 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000262 return strdup("/");
263 else
264 return strdup(s);
265}
Miklos Szeredia181e612001-11-06 12:03:23 +0000266
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000267static char *get_path(struct fuse *f, fino_t ino)
268{
269 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000270}
271
Miklos Szeredia181e612001-11-06 12:03:23 +0000272static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000273{
Miklos Szeredia181e612001-11-06 12:03:23 +0000274 struct node *node;
275
276 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000277 node = get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000278 if (node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000279 unhash_name(f, node);
280 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000281 free_node(node);
282 }
283 pthread_mutex_unlock(&f->lock);
284
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000285}
286
Miklos Szeredi5e183482001-10-31 14:52:35 +0000287static void remove_node(struct fuse *f, fino_t dir, const char *name)
288{
Miklos Szeredia181e612001-11-06 12:03:23 +0000289 struct node *node;
290
291 pthread_mutex_lock(&f->lock);
292 node = lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000293 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000294 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
295 dir, name);
296 abort();
297 }
298 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000299 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000300}
301
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000302static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
303 fino_t newdir, const char *newname)
304{
Miklos Szeredia181e612001-11-06 12:03:23 +0000305 struct node *node;
306 struct node *newnode;
307
308 pthread_mutex_lock(&f->lock);
309 node = lookup_node(f, olddir, oldname);
310 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000311 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000312 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
313 olddir, oldname);
314 abort();
315 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000316
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000317 if (newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000318 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000319
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000320 unhash_name(f, node);
321 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000322 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000323}
324
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000325static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
326{
Miklos Szeredib5958612004-02-20 14:10:49 +0000327 attr->mode = stbuf->st_mode;
328 attr->nlink = stbuf->st_nlink;
329 attr->uid = stbuf->st_uid;
330 attr->gid = stbuf->st_gid;
331 attr->rdev = stbuf->st_rdev;
332 attr->size = stbuf->st_size;
333 attr->blocks = stbuf->st_blocks;
334 attr->atime = stbuf->st_atime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000335 attr->mtime = stbuf->st_mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +0000336 attr->ctime = stbuf->st_ctime;
Miklos Szeredicb264512004-06-23 18:52:50 +0000337#ifdef HAVE_STRUCT_STAT_ST_ATIM
338 attr->atimensec = stbuf->st_atim.tv_nsec;
339 attr->mtimensec = stbuf->st_mtim.tv_nsec;
Miklos Szeredib5958612004-02-20 14:10:49 +0000340 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredicb264512004-06-23 18:52:50 +0000341#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342}
343
Miklos Szeredia181e612001-11-06 12:03:23 +0000344static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000345{
346 struct fuse_dirent dirent;
347 size_t reclen;
348 size_t res;
349
Miklos Szeredi43696432001-11-18 19:15:05 +0000350 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000351 dirent.namelen = strlen(name);
352 strncpy(dirent.name, name, sizeof(dirent.name));
353 dirent.type = type;
354 reclen = FUSE_DIRENT_SIZE(&dirent);
355 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000356 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000357 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000358 return -EIO;
359 }
360 return 0;
361}
362
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000363static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000364{
365 int res;
366
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000368 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
369 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
370 out->error, strerror(-out->error), outsize);
371 fflush(stdout);
372 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000373
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000374 /* This needs to be done before the reply, otherwise the scheduler
375 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000376 long after the operation is done */
377 inc_avail(f);
378
Miklos Szeredi43696432001-11-18 19:15:05 +0000379 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000381 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000383 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000384 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000385 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000386 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000387}
388
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000389static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
390 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000391{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000392 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000393 char *outbuf;
394 size_t outsize;
395 struct fuse_out_header *out;
396
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000397 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000398 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000399 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 }
401
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000402 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000403 argsize = 0;
404
405 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000406 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000407 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000408 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000410 out->error = error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000411 if (argsize != 0)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000412 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
413
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000414 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000415 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000416
417 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000418}
419
Miklos Szeredi76f65782004-02-19 16:55:40 +0000420static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000421 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000422{
423 int res;
424 struct stat buf;
425
426 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000427 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000428 struct node *node;
429
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000430 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000431 convert_stat(&buf, &arg->attr);
432 node = find_node(f, ino, name, &arg->attr, version);
433 arg->ino = node->ino;
434 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000435 arg->entry_valid = ENTRY_REVALIDATE_TIME;
436 arg->entry_valid_nsec = 0;
437 arg->attr_valid = ATTR_REVALIDATE_TIME;
438 arg->attr_valid_nsec = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000439 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000440 printf(" INO: %li\n", arg->ino);
441 fflush(stdout);
442 }
443 }
444 return res;
445}
446
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000447static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
448{
449 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000450 int res2;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000451 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000452 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000453
Miklos Szeredi5e183482001-10-31 14:52:35 +0000454 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000455 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000456 if (path != NULL) {
457 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000458 printf("LOOKUP %s\n", path);
459 fflush(stdout);
460 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000461 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000462 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000463 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000464 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000465 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000466 res2 = send_reply(f, in, res, &arg, sizeof(arg));
467 if (res == 0 && res2 == -ENOENT)
468 destroy_node(f, arg.ino, in->unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000469}
470
Miklos Szeredia181e612001-11-06 12:03:23 +0000471static void do_forget(struct fuse *f, struct fuse_in_header *in,
472 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000473{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000474 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000475 printf("FORGET %li/%i\n", in->ino, arg->version);
476 fflush(stdout);
477 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000478 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000479}
480
481static void do_getattr(struct fuse *f, struct fuse_in_header *in)
482{
483 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000484 char *path;
485 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000486 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000487
Miklos Szeredi5e183482001-10-31 14:52:35 +0000488 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000489 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000490 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000491 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000492 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000493 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000494 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000495 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000496
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000497 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000498 memset(&arg, 0, sizeof(struct fuse_attr_out));
499 arg.attr_valid = ATTR_REVALIDATE_TIME;
500 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000501 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000502 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000503
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000504 send_reply(f, in, res, &arg, sizeof(arg));
505}
506
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000507static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508{
509 int res;
510
511 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000512 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000513 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514
515 return res;
516}
517
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000518static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000519 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000520{
521 int res;
522 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
523 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
524
525 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000526 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000527 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000528
529 return res;
530}
531
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000532static int do_truncate(struct fuse *f, const char *path,
533 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000534{
535 int res;
536
537 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000538 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000539 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000540
541 return res;
542}
543
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000544static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000545{
546 int res;
547 struct utimbuf buf;
548 buf.actime = attr->atime;
549 buf.modtime = attr->mtime;
550 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000551 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000552 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000553
554 return res;
555}
556
Miklos Szeredi5e183482001-10-31 14:52:35 +0000557static void do_setattr(struct fuse *f, struct fuse_in_header *in,
558 struct fuse_setattr_in *arg)
559{
560 int res;
561 char *path;
562 int valid = arg->valid;
563 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000564 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000565
566 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000567 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000568 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000569 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000570 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000571 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000572 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000573 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000574 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000575 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000576 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000577 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000578 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000579 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000580 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000581 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000582 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000583 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000584 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000585 memset(&outarg, 0, sizeof(struct fuse_attr_out));
586 outarg.attr_valid = ATTR_REVALIDATE_TIME;
587 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000588 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000589 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000590 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000591 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000592 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000594 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000595}
596
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000597static void do_readlink(struct fuse *f, struct fuse_in_header *in)
598{
599 int res;
600 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000601 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000602
Miklos Szeredi5e183482001-10-31 14:52:35 +0000603 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000604 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000605 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000606 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000607 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000608 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000609 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000610 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000611 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000612 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000613}
614
615static void do_getdir(struct fuse *f, struct fuse_in_header *in)
616{
617 int res;
618 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000619 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000620 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000621
Miklos Szeredib483c932001-10-29 14:57:57 +0000622 dh.fuse = f;
623 dh.fp = tmpfile();
624 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000625 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000626 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000627 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000628 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000629 if (f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000630 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000631 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000632 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000633 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000634
635 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000636 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000638 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000639}
640
Miklos Szeredib483c932001-10-29 14:57:57 +0000641static void do_mknod(struct fuse *f, struct fuse_in_header *in,
642 struct fuse_mknod_in *inarg)
643{
644 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000645 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000646 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000647 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000648 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000649
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000651 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000652 if (path != NULL) {
653 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000654 printf("MKNOD %s\n", path);
655 fflush(stdout);
656 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000657 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000658 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000659 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000660 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000661 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000662 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000663 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000664 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000665 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
666 if (res == 0 && res2 == -ENOENT)
667 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000668}
669
670static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
671 struct fuse_mkdir_in *inarg)
672{
673 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000674 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000675 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000676 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000677 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000678
Miklos Szeredi5e183482001-10-31 14:52:35 +0000679 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000680 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000681 if (path != NULL) {
682 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000683 printf("MKDIR %s\n", path);
684 fflush(stdout);
685 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000686 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000687 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000688 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000689 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000690 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
691 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000692 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000693 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000694 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
695 if (res == 0 && res2 == -ENOENT)
696 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredib483c932001-10-29 14:57:57 +0000697}
698
Miklos Szeredib5958612004-02-20 14:10:49 +0000699static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000700{
701 int res;
702 char *path;
703
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000705 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000706 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000707 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000708 if (f->op.unlink) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000709 res = f->op.unlink(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000710 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000711 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000712 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000713 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000714 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000715 send_reply(f, in, res, NULL, 0);
716}
717
718static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
719{
720 int res;
721 char *path;
722
723 res = -ENOENT;
724 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000725 if (path != NULL) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000726 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000727 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000728 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000729 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000730 remove_node(f, in->ino, name);
731 }
732 free(path);
733 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000734 send_reply(f, in, res, NULL, 0);
735}
736
737static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
738 char *link)
739{
740 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000741 int res2;
Miklos Szeredib483c932001-10-29 14:57:57 +0000742 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000743 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000744
Miklos Szeredi5e183482001-10-31 14:52:35 +0000745 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000746 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000747 if (path != NULL) {
748 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000749 printf("SYMLINK %s\n", path);
750 fflush(stdout);
751 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000752 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000753 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000754 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000755 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000756 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
757 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000758 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000759 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000760 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
761 if (res == 0 && res2 == -ENOENT)
762 destroy_node(f, outarg.ino, in->unique);
763
Miklos Szeredib483c932001-10-29 14:57:57 +0000764}
765
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000766static void do_rename(struct fuse *f, struct fuse_in_header *in,
767 struct fuse_rename_in *inarg)
768{
769 int res;
770 fino_t olddir = in->ino;
771 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000772 char *oldname = PARAM(inarg);
773 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000774 char *oldpath;
775 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000776
Miklos Szeredi5e183482001-10-31 14:52:35 +0000777 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000778 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000779 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000780 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000781 if (newpath != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000783 if (f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000784 res = f->op.rename(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000785 if (res == 0)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000786 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000787 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000788 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000789 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000790 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000791 send_reply(f, in, res, NULL, 0);
792}
793
794static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000795 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000796{
797 int res;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000798 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 char *oldpath;
800 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000801 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000802 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000803
Miklos Szeredi5e183482001-10-31 14:52:35 +0000804 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000805 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000806 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000807 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000808 if (newpath != NULL) {
809 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000810 printf("LINK %s\n", newpath);
811 fflush(stdout);
812 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000813 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000814 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000815 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000816 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000817 res = lookup_path(f, arg->newdir, in->unique, name,
818 newpath, &outarg);
819 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000820 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000821 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000822 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000823 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000824 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
825 if (res == 0 && res2 == -ENOENT)
826 destroy_node(f, outarg.ino, in->unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000827}
828
Miklos Szeredi5e183482001-10-31 14:52:35 +0000829static void do_open(struct fuse *f, struct fuse_in_header *in,
830 struct fuse_open_in *arg)
831{
832 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000833 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000834 char *path;
835
836 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000837 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000838 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000839 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000840 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000841 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000842 }
843 res2 = send_reply(f, in, res, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000844 if (path != NULL) {
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000845 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000846 if (res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000847 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000848 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000849 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000850}
851
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000852static void do_flush(struct fuse *f, struct fuse_in_header *in)
853{
854 char *path;
855 int res;
856
857 res = -ENOENT;
858 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000859 if (path != NULL) {
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000860 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000862 res = f->op.flush(path);
863 free(path);
864 }
865 send_reply(f, in, res, NULL, 0);
866}
867
Miklos Szeredi9478e862002-12-11 09:50:26 +0000868static void do_release(struct fuse *f, struct fuse_in_header *in,
869 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000870{
Miklos Szeredib3210582004-06-23 13:54:33 +0000871 if (f->op.release) {
872 char *path;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000873
Miklos Szeredib3210582004-06-23 13:54:33 +0000874 path = get_path(f, in->ino);
875 if (path != NULL) {
876 f->op.release(path, arg->flags);
877 free(path);
878 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000879 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000880}
881
Miklos Szeredi5e183482001-10-31 14:52:35 +0000882static void do_read(struct fuse *f, struct fuse_in_header *in,
883 struct fuse_read_in *arg)
884{
885 int res;
886 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000887 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
888 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
889 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000890 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000891 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000892
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000893 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000894 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 if (path != NULL) {
896 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000897 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
898 fflush(stdout);
899 }
900
Miklos Szeredi5e183482001-10-31 14:52:35 +0000901 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000903 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000904 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000905 }
906
907 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (res > 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000909 size = res;
910 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000911 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000912 printf(" READ %u bytes\n", size);
913 fflush(stdout);
914 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000915 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000916 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000917 out->unique = in->unique;
918 out->error = res;
919 outsize = sizeof(struct fuse_out_header) + size;
920
921 send_reply_raw(f, outbuf, outsize);
922 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000923}
Miklos Szeredib483c932001-10-29 14:57:57 +0000924
Miklos Szeredia181e612001-11-06 12:03:23 +0000925static void do_write(struct fuse *f, struct fuse_in_header *in,
926 struct fuse_write_in *arg)
927{
928 int res;
929 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000930
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000931 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000932 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000933 if (path != NULL) {
934 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000935 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
936 fflush(stdout);
937 }
938
Miklos Szeredia181e612001-11-06 12:03:23 +0000939 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000940 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000941 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000942 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000943 }
944
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 if (res > 0) {
946 if ((size_t) res != arg->size) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000947 fprintf(stderr, "short write: %u (should be %u)\n", res,
948 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000949 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000950 }
951 else
952 res = 0;
953 }
954
955 send_reply(f, in, res, NULL, 0);
956}
957
Miklos Szeredi77f39942004-03-25 11:17:52 +0000958static int default_statfs(struct statfs *buf)
959{
960 buf->f_namelen = 255;
961 buf->f_bsize = 512;
962 return 0;
963}
964
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000965static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
966{
967 kstatfs->bsize = statfs->f_bsize;
968 kstatfs->blocks = statfs->f_blocks;
969 kstatfs->bfree = statfs->f_bfree;
970 kstatfs->bavail = statfs->f_bavail;
971 kstatfs->files = statfs->f_files;
972 kstatfs->ffree = statfs->f_ffree;
973 kstatfs->namelen = statfs->f_namelen;
974}
975
Mark Glinesd84b39a2002-01-07 16:32:02 +0000976static void do_statfs(struct fuse *f, struct fuse_in_header *in)
977{
978 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000979 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000980 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000981
Miklos Szeredi77f39942004-03-25 11:17:52 +0000982 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000983 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000984 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000985 else
986 res = default_statfs(&buf);
987
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +0000989 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000990
Mark Glinesd84b39a2002-01-07 16:32:02 +0000991 send_reply(f, in, res, &arg, sizeof(arg));
992}
993
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000994static void do_fsync(struct fuse *f, struct fuse_in_header *in,
995 struct fuse_fsync_in *inarg)
996{
997 int res;
998 char *path;
999
1000 res = -ENOENT;
1001 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001002 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001003 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001005 res = f->op.fsync(path, inarg->datasync);
1006 free(path);
1007 }
1008 send_reply(f, in, res, NULL, 0);
1009}
1010
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001011static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1012 struct fuse_setxattr_in *arg)
1013{
1014 int res;
1015 char *path;
1016 char *name = PARAM(arg);
1017 unsigned char *value = name + strlen(name) + 1;
1018
1019 res = -ENOENT;
1020 path = get_path(f, in->ino);
1021 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001022 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001023 if (f->op.setxattr)
1024 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1025 free(path);
1026 }
1027 send_reply(f, in, res, NULL, 0);
1028}
1029
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001030static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1031 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001032{
1033 int res;
1034 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001035
1036 res = -ENOENT;
1037 path = get_path(f, in->ino);
1038 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001039 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001040 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001041 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 free(path);
1043 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001044 return res;
1045}
1046
1047static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1048 const char *name, size_t size)
1049{
1050 int res;
1051 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1052 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1053 char *value = outbuf + sizeof(struct fuse_out_header);
1054
1055 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001056 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001057 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001058 size = res;
1059 res = 0;
1060 }
1061 memset(out, 0, sizeof(struct fuse_out_header));
1062 out->unique = in->unique;
1063 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001064
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001065 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001066 free(outbuf);
1067}
1068
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001069static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1070 const char *name)
1071{
1072 int res;
1073 struct fuse_getxattr_out arg;
1074
1075 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001077 arg.size = res;
1078 res = 0;
1079 }
1080 send_reply(f, in, res, &arg, sizeof(arg));
1081}
1082
1083static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1084 struct fuse_getxattr_in *arg)
1085{
1086 char *name = PARAM(arg);
1087
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001088 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001089 do_getxattr_read(f, in, name, arg->size);
1090 else
1091 do_getxattr_size(f, in, name);
1092}
1093
1094static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1095 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001096{
1097 int res;
1098 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001099
1100 res = -ENOENT;
1101 path = get_path(f, in->ino);
1102 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001103 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001104 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001105 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001106 free(path);
1107 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001108 return res;
1109}
1110
1111static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1112 size_t size)
1113{
1114 int res;
1115 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1116 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1117 char *list = outbuf + sizeof(struct fuse_out_header);
1118
1119 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001120 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001121 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001122 size = res;
1123 res = 0;
1124 }
1125 memset(out, 0, sizeof(struct fuse_out_header));
1126 out->unique = in->unique;
1127 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001128
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001129 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001130 free(outbuf);
1131}
1132
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001133static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1134{
1135 int res;
1136 struct fuse_getxattr_out arg;
1137
1138 res = common_listxattr(f, in, NULL, 0);
1139 if (res >= 0) {
1140 arg.size = res;
1141 res = 0;
1142 }
1143 send_reply(f, in, res, &arg, sizeof(arg));
1144}
1145
1146static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1147 struct fuse_getxattr_in *arg)
1148{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001149 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001150 do_listxattr_read(f, in, arg->size);
1151 else
1152 do_listxattr_size(f, in);
1153}
1154
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001155static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1156 char *name)
1157{
1158 int res;
1159 char *path;
1160
1161 res = -ENOENT;
1162 path = get_path(f, in->ino);
1163 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001164 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001165 if (f->op.removexattr)
1166 res = f->op.removexattr(path, name);
1167 free(path);
1168 }
1169 send_reply(f, in, res, NULL, 0);
1170}
1171
1172
Miklos Szeredi43696432001-11-18 19:15:05 +00001173static void free_cmd(struct fuse_cmd *cmd)
1174{
1175 free(cmd->buf);
1176 free(cmd);
1177}
1178
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001179void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001180{
Miklos Szeredia181e612001-11-06 12:03:23 +00001181 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1182 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1183 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001184 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001185
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001186 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001187
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001188 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001189 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1190 in->unique, opname(in->opcode), in->opcode, in->ino,
1191 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001192 fflush(stdout);
1193 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001194
1195 ctx->uid = in->uid;
1196 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001197
1198 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1199
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001200 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001201 case FUSE_LOOKUP:
1202 do_lookup(f, in, (char *) inarg);
1203 break;
1204
Miklos Szeredia181e612001-11-06 12:03:23 +00001205 case FUSE_GETATTR:
1206 do_getattr(f, in);
1207 break;
1208
1209 case FUSE_SETATTR:
1210 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1211 break;
1212
1213 case FUSE_READLINK:
1214 do_readlink(f, in);
1215 break;
1216
1217 case FUSE_GETDIR:
1218 do_getdir(f, in);
1219 break;
1220
1221 case FUSE_MKNOD:
1222 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1223 break;
1224
1225 case FUSE_MKDIR:
1226 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1227 break;
1228
1229 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001230 do_unlink(f, in, (char *) inarg);
1231 break;
1232
Miklos Szeredia181e612001-11-06 12:03:23 +00001233 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001234 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001235 break;
1236
1237 case FUSE_SYMLINK:
1238 do_symlink(f, in, (char *) inarg,
1239 ((char *) inarg) + strlen((char *) inarg) + 1);
1240 break;
1241
1242 case FUSE_RENAME:
1243 do_rename(f, in, (struct fuse_rename_in *) inarg);
1244 break;
1245
1246 case FUSE_LINK:
1247 do_link(f, in, (struct fuse_link_in *) inarg);
1248 break;
1249
1250 case FUSE_OPEN:
1251 do_open(f, in, (struct fuse_open_in *) inarg);
1252 break;
1253
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001254 case FUSE_FLUSH:
1255 do_flush(f, in);
1256 break;
1257
Miklos Szeredi9478e862002-12-11 09:50:26 +00001258 case FUSE_RELEASE:
1259 do_release(f, in, (struct fuse_open_in *) inarg);
1260 break;
1261
Miklos Szeredia181e612001-11-06 12:03:23 +00001262 case FUSE_READ:
1263 do_read(f, in, (struct fuse_read_in *) inarg);
1264 break;
1265
1266 case FUSE_WRITE:
1267 do_write(f, in, (struct fuse_write_in *) inarg);
1268 break;
1269
Mark Glinesd84b39a2002-01-07 16:32:02 +00001270 case FUSE_STATFS:
1271 do_statfs(f, in);
1272 break;
1273
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001274 case FUSE_FSYNC:
1275 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1276 break;
1277
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001278 case FUSE_SETXATTR:
1279 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1280 break;
1281
1282 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001283 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001284 break;
1285
1286 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001287 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001288 break;
1289
1290 case FUSE_REMOVEXATTR:
1291 do_removexattr(f, in, (char *) inarg);
1292 break;
1293
Miklos Szeredia181e612001-11-06 12:03:23 +00001294 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001295 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001296 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001297
1298 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001299}
1300
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001301struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001302{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001303 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001304 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001305 struct fuse_in_header *in;
1306 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001307
Miklos Szeredi43696432001-11-18 19:15:05 +00001308 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1309 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001310 in = (struct fuse_in_header *) cmd->buf;
1311 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001312
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001313 do {
1314 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001315 if (res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001316 free_cmd(cmd);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001317 if (f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001318 return NULL;
1319
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001320 /* ENODEV means we got unmounted, so we silenty return failure */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001321 if (errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001322 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001323 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001324 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001325
1326 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001327 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001328 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001329 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001330 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001331 /* Cannot happen */
1332 fprintf(stderr, "short read on fuse device\n");
1333 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001334 return NULL;
1335 }
1336 cmd->buflen = res;
1337
1338 /* Forget is special, it can be done without messing with threads. */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001339 if (in->opcode == FUSE_FORGET)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001340 do_forget(f, in, (struct fuse_forget_in *) inarg);
1341
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001342 } while (in->opcode == FUSE_FORGET);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001343
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001344 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001345}
1346
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001347void fuse_loop(struct fuse *f)
1348{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001349 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001350 return;
1351
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001352 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001353 struct fuse_cmd *cmd;
1354
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001355 if (f->exited)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001356 return;
1357
1358 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001359 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001360 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001361
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001362 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001363 }
1364}
1365
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001366void fuse_exit(struct fuse *f)
1367{
1368 f->exited = 1;
1369}
1370
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001371struct fuse_context *fuse_get_context(struct fuse *f)
1372{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001373 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001374 return f->getcontext(f);
1375 else
1376 return &f->context;
1377}
1378
Miklos Szeredic40748a2004-02-20 16:38:45 +00001379static int check_version(struct fuse *f)
1380{
1381 int res;
1382 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001383 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001384 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1385 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1386 return -1;
1387 }
1388 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1389 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001390 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001391 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1392 return -1;
1393 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001394 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001395 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1396 FUSE_KERNEL_VERSION);
1397 return -1;
1398 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001399 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001400 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1401 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1402 return -1;
1403 }
1404
1405 return 0;
1406}
1407
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001408struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001409{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001410 struct fuse *f;
1411 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001412
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001413 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001414
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001415 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001416 free(f);
1417 return NULL;
1418 }
1419
Miklos Szeredia181e612001-11-06 12:03:23 +00001420 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001421 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001422 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001423 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001424 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001425 f->name_table_size = 14057;
1426 f->name_table = (struct node **)
1427 calloc(1, sizeof(struct node *) * f->name_table_size);
1428 f->ino_table_size = 14057;
1429 f->ino_table = (struct node **)
1430 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001431 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001432 f->numworker = 0;
1433 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001434 f->op = *op;
1435 f->getcontext = NULL;
1436 f->context.uid = 0;
1437 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001438 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001439
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001440 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001441 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001442 root->rdev = 0;
1443 root->name = strdup("/");
1444 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001445 root->ino = FUSE_ROOT_INO;
1446 root->generation = 0;
1447 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001448
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001449 return f;
1450}
1451
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001452void fuse_destroy(struct fuse *f)
1453{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001454 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001455 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001456 struct node *node;
1457 struct node *next;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001458 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001459 next = node->ino_next;
1460 free_node(node);
1461 }
1462 }
1463 free(f->ino_table);
1464 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001465 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001466 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001467}