blob: 4015d827376ea441f68fe05b3c45b7a2e1aefe0f [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
9#include "fuse_i.h"
10#include <linux/fuse.h>
11
12#include <string.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000013#include <stdlib.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014#include <unistd.h>
Miklos Szeredi97c61e92001-11-07 12:09:43 +000015#include <limits.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000016#include <errno.h>
Miklos Szeredi019b4e92001-12-26 18:08:09 +000017#include <sys/param.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000018
Miklos Szeredi97c61e92001-11-07 12:09:43 +000019#define FUSE_MAX_PATH 4096
Miklos Szeredi6bf8b682002-10-28 08:49:39 +000020#define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000021
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000022#define ENTRY_REVALIDATE_TIME 1 /* sec */
23#define ATTR_REVALIDATE_TIME 1 /* sec */
24
Miklos Szeredic8ba2372002-12-10 12:26:00 +000025static const char *opname(enum fuse_opcode opcode)
26{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000027 switch (opcode) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +000028 case FUSE_LOOKUP: return "LOOKUP";
29 case FUSE_FORGET: return "FORGET";
30 case FUSE_GETATTR: return "GETATTR";
31 case FUSE_SETATTR: return "SETATTR";
32 case FUSE_READLINK: return "READLINK";
33 case FUSE_SYMLINK: return "SYMLINK";
34 case FUSE_GETDIR: return "GETDIR";
35 case FUSE_MKNOD: return "MKNOD";
36 case FUSE_MKDIR: return "MKDIR";
37 case FUSE_UNLINK: return "UNLINK";
38 case FUSE_RMDIR: return "RMDIR";
39 case FUSE_RENAME: return "RENAME";
40 case FUSE_LINK: return "LINK";
41 case FUSE_OPEN: return "OPEN";
42 case FUSE_READ: return "READ";
43 case FUSE_WRITE: return "WRITE";
44 case FUSE_STATFS: return "STATFS";
Miklos Szeredi99f20742004-05-19 08:01:10 +000045 case FUSE_FLUSH: return "FLUSH";
Miklos Szeredi3ed84232004-03-30 15:17:26 +000046 case FUSE_RELEASE: return "RELEASE";
47 case FUSE_FSYNC: return "FSYNC";
48 case FUSE_SETXATTR: return "SETXATTR";
49 case FUSE_GETXATTR: return "GETXATTR";
50 case FUSE_LISTXATTR: return "LISTXATTR";
51 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
Miklos Szeredi99f20742004-05-19 08:01:10 +000052 default: return "???";
Miklos Szeredic8ba2372002-12-10 12:26:00 +000053 }
54}
55
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +000056static inline void inc_avail(struct fuse *f)
57{
58 pthread_mutex_lock(&f->lock);
59 f->numavail ++;
60 pthread_mutex_unlock(&f->lock);
61}
62
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 Szeredi97c61e92001-11-07 12:09:43 +000070static struct node *__get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000071{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000072 size_t hash = ino % f->ino_table_size;
73 struct node *node;
74
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000075 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
76 if (node->ino == ino)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000077 return node;
78
79 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +000080}
81
Miklos Szeredi97c61e92001-11-07 12:09:43 +000082static struct node *get_node(struct fuse *f, fino_t ino)
Miklos Szeredia181e612001-11-06 12:03:23 +000083{
Miklos Szeredi97c61e92001-11-07 12:09:43 +000084 struct node *node = __get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000085 if (node != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000086 return node;
87
88 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
89 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +000090}
91
Miklos Szeredi76f65782004-02-19 16:55:40 +000092static void hash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000093{
Miklos Szeredi76f65782004-02-19 16:55:40 +000094 size_t hash = node->ino % f->ino_table_size;
Miklos Szeredi97c61e92001-11-07 12:09:43 +000095 node->ino_next = f->ino_table[hash];
96 f->ino_table[hash] = node;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000097}
98
Miklos Szeredi97c61e92001-11-07 12:09:43 +000099static void unhash_ino(struct fuse *f, struct node *node)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000101 size_t hash = node->ino % f->ino_table_size;
102 struct node **nodep = &f->ino_table[hash];
103
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000104 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
105 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000106 *nodep = node->ino_next;
107 return;
108 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109}
110
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000111static fino_t next_ino(struct fuse *f)
112{
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
127static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
128{
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 Szeredi19dff1b2001-10-30 15:06:52 +0000138static struct node *lookup_node(struct fuse *f, fino_t parent,
139 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 Szeredi97c61e92001-11-07 12:09:43 +0000151static void hash_name(struct fuse *f, struct node *node, fino_t parent,
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 const char *name)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000153{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000154 size_t hash = name_hash(f, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000155 node->parent = parent;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000156 node->name = strdup(name);
157 node->name_next = f->name_table[hash];
158 f->name_table[hash] = node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000159}
160
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000161static void unhash_name(struct fuse *f, struct node *node)
Miklos Szeredia181e612001-11-06 12:03:23 +0000162{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000163 if (node->name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000164 size_t hash = name_hash(f, node->parent, node->name);
165 struct node **nodep = &f->name_table[hash];
166
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000167 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
168 if (*nodep == node) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000169 *nodep = node->name_next;
170 node->name_next = NULL;
171 free(node->name);
172 node->name = NULL;
173 node->parent = 0;
174 return;
175 }
176 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
177 node->ino);
178 abort();
Miklos Szeredia181e612001-11-06 12:03:23 +0000179 }
180}
181
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182static struct node *find_node(struct fuse *f, fino_t parent, char *name,
183 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000184{
185 struct node *node;
Miklos Szeredia181e612001-11-06 12:03:23 +0000186 int mode = attr->mode & S_IFMT;
187 int rdev = 0;
188
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000189 if (S_ISCHR(mode) || S_ISBLK(mode))
Miklos Szeredia181e612001-11-06 12:03:23 +0000190 rdev = attr->rdev;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000191
Miklos Szeredia181e612001-11-06 12:03:23 +0000192 pthread_mutex_lock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000193 node = lookup_node(f, parent, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000194 if (node != NULL) {
195 if (node->mode == mode && node->rdev == rdev)
Miklos Szeredia181e612001-11-06 12:03:23 +0000196 goto out;
197
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000198 unhash_name(f, node);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000199 }
200
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000201 node = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredia181e612001-11-06 12:03:23 +0000202 node->mode = mode;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000203 node->rdev = rdev;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000204 node->ino = next_ino(f);
205 node->generation = f->generation;
206 hash_ino(f, node);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000207 hash_name(f, node, parent, name);
Miklos Szeredia181e612001-11-06 12:03:23 +0000208
209 out:
210 node->version = version;
211 pthread_mutex_unlock(&f->lock);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000212 return node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000213}
214
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000215static char *add_name(char *buf, char *s, const char *name)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000217 size_t len = strlen(name);
218 s -= len;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000219 if (s <= buf) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000220 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
221 return NULL;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000223 strncpy(s, name, len);
224 s--;
225 *s = '/';
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000226
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000227 return s;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000228}
229
Miklos Szeredia181e612001-11-06 12:03:23 +0000230static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000231{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000232 char buf[FUSE_MAX_PATH];
233 char *s = buf + FUSE_MAX_PATH - 1;
234 struct node *node;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000235
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000236 *s = '\0';
Miklos Szeredia181e612001-11-06 12:03:23 +0000237
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000238 if (name != NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000239 s = add_name(buf, s, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000240 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000241 return NULL;
242 }
243
244 pthread_mutex_lock(&f->lock);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000245 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000246 node = get_node(f, node->parent)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000247 if (node->name == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000248 s = NULL;
249 break;
250 }
251
252 s = add_name(buf, s, node->name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000253 if (s == NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000254 break;
255 }
256 pthread_mutex_unlock(&f->lock);
257
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 if (s == NULL)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000259 return NULL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000260 else if (*s == '\0')
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000261 return strdup("/");
262 else
263 return strdup(s);
264}
Miklos Szeredia181e612001-11-06 12:03:23 +0000265
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000266static char *get_path(struct fuse *f, fino_t ino)
267{
268 return get_path_name(f, ino, NULL);
Miklos Szeredib483c932001-10-29 14:57:57 +0000269}
270
Miklos Szeredia181e612001-11-06 12:03:23 +0000271static void destroy_node(struct fuse *f, fino_t ino, int version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000272{
Miklos Szeredia181e612001-11-06 12:03:23 +0000273 struct node *node;
274
275 pthread_mutex_lock(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000276 node = get_node(f, ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 if (node->version == version && ino != FUSE_ROOT_INO) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000278 unhash_name(f, node);
279 unhash_ino(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000280 free_node(node);
281 }
282 pthread_mutex_unlock(&f->lock);
283
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000284}
285
Miklos Szeredi5e183482001-10-31 14:52:35 +0000286static void remove_node(struct fuse *f, fino_t dir, const char *name)
287{
Miklos Szeredia181e612001-11-06 12:03:23 +0000288 struct node *node;
289
290 pthread_mutex_lock(&f->lock);
291 node = lookup_node(f, dir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000292 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000293 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
294 dir, name);
295 abort();
296 }
297 unhash_name(f, node);
Miklos Szeredia181e612001-11-06 12:03:23 +0000298 pthread_mutex_unlock(&f->lock);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000299}
300
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000301static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
302 fino_t newdir, const char *newname)
303{
Miklos Szeredia181e612001-11-06 12:03:23 +0000304 struct node *node;
305 struct node *newnode;
306
307 pthread_mutex_lock(&f->lock);
308 node = lookup_node(f, olddir, oldname);
309 newnode = lookup_node(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000310 if (node == NULL) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000311 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
312 olddir, oldname);
313 abort();
314 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000315
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000316 if (newnode != NULL)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000317 unhash_name(f, newnode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000318
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000319 unhash_name(f, node);
320 hash_name(f, node, newdir, newname);
Miklos Szeredia181e612001-11-06 12:03:23 +0000321 pthread_mutex_unlock(&f->lock);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322}
323
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
325{
Miklos Szeredib5958612004-02-20 14:10:49 +0000326 attr->mode = stbuf->st_mode;
327 attr->nlink = stbuf->st_nlink;
328 attr->uid = stbuf->st_uid;
329 attr->gid = stbuf->st_gid;
330 attr->rdev = stbuf->st_rdev;
331 attr->size = stbuf->st_size;
332 attr->blocks = stbuf->st_blocks;
333 attr->atime = stbuf->st_atime;
334 attr->atimensec = stbuf->st_atim.tv_nsec;
335 attr->mtime = stbuf->st_mtime;
336 attr->mtimensec = stbuf->st_mtim.tv_nsec;
337 attr->ctime = stbuf->st_ctime;
338 attr->ctimensec = stbuf->st_ctim.tv_nsec;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000339}
340
Miklos Szeredia181e612001-11-06 12:03:23 +0000341static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342{
343 struct fuse_dirent dirent;
344 size_t reclen;
345 size_t res;
346
Miklos Szeredi43696432001-11-18 19:15:05 +0000347 dirent.ino = (unsigned long) -1;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000348 dirent.namelen = strlen(name);
349 strncpy(dirent.name, name, sizeof(dirent.name));
350 dirent.type = type;
351 reclen = FUSE_DIRENT_SIZE(&dirent);
352 res = fwrite(&dirent, reclen, 1, dh->fp);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000353 if (res == 0) {
Miklos Szeredi96249982001-11-21 12:21:19 +0000354 perror("fuse: writing directory file");
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000355 return -EIO;
356 }
357 return 0;
358}
359
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000360static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
Miklos Szeredi43696432001-11-18 19:15:05 +0000361{
362 int res;
363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000365 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
366 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
367 out->error, strerror(-out->error), outsize);
368 fflush(stdout);
369 }
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000370
Miklos Szeredi4e71c9f2004-02-09 12:05:14 +0000371 /* This needs to be done before the reply, otherwise the scheduler
372 could play tricks with us, and only let the counter be increased
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +0000373 long after the operation is done */
374 inc_avail(f);
375
Miklos Szeredi43696432001-11-18 19:15:05 +0000376 res = write(f->fd, outbuf, outsize);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377 if (res == -1) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 /* ENOENT means the operation was interrupted */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000379 if (!f->exited && errno != ENOENT)
Miklos Szeredi96249982001-11-21 12:21:19 +0000380 perror("fuse: writing device");
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000381 return -errno;
Miklos Szeredi43696432001-11-18 19:15:05 +0000382 }
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000383 return 0;
Miklos Szeredi43696432001-11-18 19:15:05 +0000384}
385
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000386static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
387 void *arg, size_t argsize)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000388{
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000389 int res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390 char *outbuf;
391 size_t outsize;
392 struct fuse_out_header *out;
393
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000394 if (error <= -1000 || error > 0) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000395 fprintf(stderr, "fuse: bad error value: %i\n", error);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000396 error = -ERANGE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000397 }
398
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000399 if (error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400 argsize = 0;
401
402 outsize = sizeof(struct fuse_out_header) + argsize;
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000403 outbuf = (char *) malloc(outsize);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000404 out = (struct fuse_out_header *) outbuf;
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000405 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406 out->unique = in->unique;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000407 out->error = error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000408 if (argsize != 0)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
410
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000411 res = send_reply_raw(f, outbuf, outsize);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000412 free(outbuf);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000413
414 return res;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000415}
416
Miklos Szeredi76f65782004-02-19 16:55:40 +0000417static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000418 const char *path, struct fuse_entry_out *arg)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000419{
420 int res;
421 struct stat buf;
422
423 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 if (res == 0) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000425 struct node *node;
426
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000427 memset(arg, 0, sizeof(struct fuse_entry_out));
Miklos Szeredi76f65782004-02-19 16:55:40 +0000428 convert_stat(&buf, &arg->attr);
429 node = find_node(f, ino, name, &arg->attr, version);
430 arg->ino = node->ino;
431 arg->generation = node->generation;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000432 arg->entry_valid = ENTRY_REVALIDATE_TIME;
433 arg->entry_valid_nsec = 0;
434 arg->attr_valid = ATTR_REVALIDATE_TIME;
435 arg->attr_valid_nsec = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000436 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000437 printf(" INO: %li\n", arg->ino);
438 fflush(stdout);
439 }
440 }
441 return res;
442}
443
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
445{
446 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000447 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000448 struct fuse_entry_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000449
Miklos Szeredi5e183482001-10-31 14:52:35 +0000450 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000451 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000452 if (path != NULL) {
453 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000454 printf("LOOKUP %s\n", path);
455 fflush(stdout);
456 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000457 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000458 if (f->op.getattr)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000459 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000460 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000461 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000462 send_reply(f, in, res, &arg, sizeof(arg));
463}
464
Miklos Szeredia181e612001-11-06 12:03:23 +0000465static void do_forget(struct fuse *f, struct fuse_in_header *in,
466 struct fuse_forget_in *arg)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000468 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi43696432001-11-18 19:15:05 +0000469 printf("FORGET %li/%i\n", in->ino, arg->version);
470 fflush(stdout);
471 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000472 destroy_node(f, in->ino, arg->version);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000473}
474
475static void do_getattr(struct fuse *f, struct fuse_in_header *in)
476{
477 int res;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000478 char *path;
479 struct stat buf;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000480 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000481
Miklos Szeredi5e183482001-10-31 14:52:35 +0000482 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000483 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000484 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000485 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000486 if (f->op.getattr)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000487 res = f->op.getattr(path, &buf);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000488 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000489 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000490
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000491 if (res == 0) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000492 memset(&arg, 0, sizeof(struct fuse_attr_out));
493 arg.attr_valid = ATTR_REVALIDATE_TIME;
494 arg.attr_valid_nsec = 0;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000495 convert_stat(&buf, &arg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000496 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000497
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000498 send_reply(f, in, res, &arg, sizeof(arg));
499}
500
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000501static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000502{
503 int res;
504
505 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000506 if (f->op.chmod)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000507 res = f->op.chmod(path, attr->mode);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000508
509 return res;
510}
511
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000512static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
Miklos Szeredi2e50d432001-12-20 12:17:25 +0000513 int valid)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000514{
515 int res;
516 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
517 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
518
519 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000520 if (f->op.chown)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000521 res = f->op.chown(path, uid, gid);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000522
523 return res;
524}
525
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000526static int do_truncate(struct fuse *f, const char *path,
527 struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000528{
529 int res;
530
531 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000532 if (f->op.truncate)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000533 res = f->op.truncate(path, attr->size);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000534
535 return res;
536}
537
Miklos Szeredi680a69a2001-11-16 13:31:14 +0000538static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000539{
540 int res;
541 struct utimbuf buf;
542 buf.actime = attr->atime;
543 buf.modtime = attr->mtime;
544 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000545 if (f->op.utime)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000546 res = f->op.utime(path, &buf);
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000547
548 return res;
549}
550
Miklos Szeredi5e183482001-10-31 14:52:35 +0000551static void do_setattr(struct fuse *f, struct fuse_in_header *in,
552 struct fuse_setattr_in *arg)
553{
554 int res;
555 char *path;
556 int valid = arg->valid;
557 struct fuse_attr *attr = &arg->attr;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000558 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559
560 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000561 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000562 if (path != NULL) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000563 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000564 if (f->op.getattr) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000565 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000566 if (!res && (valid & FATTR_MODE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000567 res = do_chmod(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000568 if (!res && (valid & (FATTR_UID | FATTR_GID)))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000569 res = do_chown(f, path, attr, valid);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000570 if (!res && (valid & FATTR_SIZE))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000571 res = do_truncate(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000572 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
Miklos Szeredib5958612004-02-20 14:10:49 +0000573 (FATTR_ATIME | FATTR_MTIME))
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000574 res = do_utime(f, path, attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000575 if (!res) {
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000576 struct stat buf;
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000577 res = f->op.getattr(path, &buf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000578 if (!res) {
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000579 memset(&outarg, 0, sizeof(struct fuse_attr_out));
580 outarg.attr_valid = ATTR_REVALIDATE_TIME;
581 outarg.attr_valid_nsec = 0;
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000582 convert_stat(&buf, &outarg.attr);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000583 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000584 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000585 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000586 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000587 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000588 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi5e183482001-10-31 14:52:35 +0000589}
590
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000591static void do_readlink(struct fuse *f, struct fuse_in_header *in)
592{
593 int res;
594 char link[PATH_MAX + 1];
Miklos Szeredib483c932001-10-29 14:57:57 +0000595 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000596
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000598 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000599 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000601 if (f->op.readlink)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000602 res = f->op.readlink(path, link, sizeof(link));
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000603 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000604 }
Miklos Szeredi2df1c042001-11-06 15:07:17 +0000605 link[PATH_MAX] = '\0';
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000606 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000607}
608
609static void do_getdir(struct fuse *f, struct fuse_in_header *in)
610{
611 int res;
612 struct fuse_getdir_out arg;
Miklos Szeredia181e612001-11-06 12:03:23 +0000613 struct fuse_dirhandle dh;
Miklos Szeredib483c932001-10-29 14:57:57 +0000614 char *path;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000615
Miklos Szeredib483c932001-10-29 14:57:57 +0000616 dh.fuse = f;
617 dh.fp = tmpfile();
618 dh.dir = in->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000619 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000620 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000621 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000622 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000623 if (f->op.getdir)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000624 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000625 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000626 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000627 fflush(dh.fp);
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000628
629 memset(&arg, 0, sizeof(struct fuse_getdir_out));
Miklos Szeredib483c932001-10-29 14:57:57 +0000630 arg.fd = fileno(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000631 send_reply(f, in, res, &arg, sizeof(arg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000632 fclose(dh.fp);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000633}
634
Miklos Szeredib483c932001-10-29 14:57:57 +0000635static void do_mknod(struct fuse *f, struct fuse_in_header *in,
636 struct fuse_mknod_in *inarg)
637{
638 int res;
639 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000640 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000641 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000642
Miklos Szeredi5e183482001-10-31 14:52:35 +0000643 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000644 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000645 if (path != NULL) {
646 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000647 printf("MKNOD %s\n", path);
648 fflush(stdout);
649 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000651 if (f->op.mknod && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000652 res = f->op.mknod(path, inarg->mode, inarg->rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000653 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000654 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000656 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000657 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000658 send_reply(f, in, res, &outarg, sizeof(outarg));
659}
660
661static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
662 struct fuse_mkdir_in *inarg)
663{
664 int res;
665 char *path;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000666 char *name = PARAM(inarg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000667 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000668
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 res = -ENOENT;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000670 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000671 if (path != NULL) {
672 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000673 printf("MKDIR %s\n", path);
674 fflush(stdout);
675 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000677 if (f->op.mkdir && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000678 res = f->op.mkdir(path, inarg->mode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000679 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000680 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
681 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000682 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000683 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000684 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000685}
686
Miklos Szeredib5958612004-02-20 14:10:49 +0000687static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
Miklos Szeredib483c932001-10-29 14:57:57 +0000688{
689 int res;
690 char *path;
691
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000693 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000694 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000695 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000696 if (f->op.unlink) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000697 res = f->op.unlink(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000698 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000699 remove_node(f, in->ino, name);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000700 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000701 free(path);
Miklos Szeredib483c932001-10-29 14:57:57 +0000702 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000703 send_reply(f, in, res, NULL, 0);
704}
705
706static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
707{
708 int res;
709 char *path;
710
711 res = -ENOENT;
712 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000713 if (path != NULL) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000714 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 if (f->op.rmdir) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000716 res = f->op.rmdir(path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000717 if (res == 0)
Miklos Szeredib5958612004-02-20 14:10:49 +0000718 remove_node(f, in->ino, name);
719 }
720 free(path);
721 }
Miklos Szeredib483c932001-10-29 14:57:57 +0000722 send_reply(f, in, res, NULL, 0);
723}
724
725static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
726 char *link)
727{
728 int res;
729 char *path;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000730 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000731
Miklos Szeredi5e183482001-10-31 14:52:35 +0000732 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000733 path = get_path_name(f, in->ino, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000734 if (path != NULL) {
735 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000736 printf("SYMLINK %s\n", path);
737 fflush(stdout);
738 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000740 if (f->op.symlink && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000741 res = f->op.symlink(link, path);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000742 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000743 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
744 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000745 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000746 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000747 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredib483c932001-10-29 14:57:57 +0000748}
749
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000750static void do_rename(struct fuse *f, struct fuse_in_header *in,
751 struct fuse_rename_in *inarg)
752{
753 int res;
754 fino_t olddir = in->ino;
755 fino_t newdir = inarg->newdir;
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000756 char *oldname = PARAM(inarg);
757 char *newname = oldname + strlen(oldname) + 1;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758 char *oldpath;
759 char *newpath;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000760
Miklos Szeredi5e183482001-10-31 14:52:35 +0000761 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000762 oldpath = get_path_name(f, olddir, oldname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 if (oldpath != NULL) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000764 newpath = get_path_name(f, newdir, newname);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000765 if (newpath != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000766 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 if (f->op.rename)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000768 res = f->op.rename(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 if (res == 0)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000770 rename_node(f, olddir, oldname, newdir, newname);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000771 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000772 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000773 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000774 }
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000775 send_reply(f, in, res, NULL, 0);
776}
777
778static void do_link(struct fuse *f, struct fuse_in_header *in,
Miklos Szeredi5e183482001-10-31 14:52:35 +0000779 struct fuse_link_in *arg)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000780{
781 int res;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 char *oldpath;
783 char *newpath;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000784 char *name = PARAM(arg);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000785 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000786
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000788 oldpath = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000789 if (oldpath != NULL) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000790 newpath = get_path_name(f, arg->newdir, name);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000791 if (newpath != NULL) {
792 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000793 printf("LINK %s\n", newpath);
794 fflush(stdout);
795 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000796 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000797 if (f->op.link && f->op.getattr) {
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000798 res = f->op.link(oldpath, newpath);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000799 if (res == 0)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000800 res = lookup_path(f, arg->newdir, in->unique, name,
801 newpath, &outarg);
802 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000803 free(newpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000804 }
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000805 free(oldpath);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000806 }
Miklos Szeredi76f65782004-02-19 16:55:40 +0000807 send_reply(f, in, res, &outarg, sizeof(outarg));
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000808}
809
Miklos Szeredi5e183482001-10-31 14:52:35 +0000810static void do_open(struct fuse *f, struct fuse_in_header *in,
811 struct fuse_open_in *arg)
812{
813 int res;
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000814 int res2;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000815 char *path;
816
817 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000818 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000819 if (path != NULL) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000820 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000821 if (f->op.open)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000822 res = f->op.open(path, arg->flags);
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000823 }
824 res2 = send_reply(f, in, res, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000825 if (path != NULL) {
Miklos Szeredi40b9a5a2002-12-10 16:09:02 +0000826 /* The open syscall was interrupted, so it must be cancelled */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000827 if (res == 0 && res2 == -ENOENT && f->op.release)
Miklos Szeredi9478e862002-12-11 09:50:26 +0000828 f->op.release(path, arg->flags);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000829 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000830 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831}
832
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000833static void do_flush(struct fuse *f, struct fuse_in_header *in)
834{
835 char *path;
836 int res;
837
838 res = -ENOENT;
839 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000840 if (path != NULL) {
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000841 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000842 if (f->op.flush)
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000843 res = f->op.flush(path);
844 free(path);
845 }
846 send_reply(f, in, res, NULL, 0);
847}
848
Miklos Szeredi9478e862002-12-11 09:50:26 +0000849static void do_release(struct fuse *f, struct fuse_in_header *in,
850 struct fuse_open_in *arg)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000851{
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000852 char *path;
853
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 if (!f->op.release) {
855 send_reply(f, in, -ENOSYS, NULL, 0);
856 return;
857 }
858
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000859 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000860 if (path != NULL) {
861 f->op.release(path, arg->flags);
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000862 free(path);
863 }
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000864}
865
Miklos Szeredi5e183482001-10-31 14:52:35 +0000866static void do_read(struct fuse *f, struct fuse_in_header *in,
867 struct fuse_read_in *arg)
868{
869 int res;
870 char *path;
Miklos Szeredi43696432001-11-18 19:15:05 +0000871 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
872 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
873 char *buf = outbuf + sizeof(struct fuse_out_header);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000874 size_t size;
Miklos Szeredi43696432001-11-18 19:15:05 +0000875 size_t outsize;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000876
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000877 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000878 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 if (path != NULL) {
880 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000881 printf("READ %u bytes from %llu\n", arg->size, arg->offset);
882 fflush(stdout);
883 }
884
Miklos Szeredi5e183482001-10-31 14:52:35 +0000885 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000886 if (f->op.read)
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000887 res = f->op.read(path, buf, arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000888 free(path);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000889 }
890
891 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 if (res > 0) {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000893 size = res;
894 res = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000896 printf(" READ %u bytes\n", size);
897 fflush(stdout);
898 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000899 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +0000900 memset(out, 0, sizeof(struct fuse_out_header));
Miklos Szeredi43696432001-11-18 19:15:05 +0000901 out->unique = in->unique;
902 out->error = res;
903 outsize = sizeof(struct fuse_out_header) + size;
904
905 send_reply_raw(f, outbuf, outsize);
906 free(outbuf);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000907}
Miklos Szeredib483c932001-10-29 14:57:57 +0000908
Miklos Szeredia181e612001-11-06 12:03:23 +0000909static void do_write(struct fuse *f, struct fuse_in_header *in,
910 struct fuse_write_in *arg)
911{
912 int res;
913 char *path;
Miklos Szeredia181e612001-11-06 12:03:23 +0000914
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000915 res = -ENOENT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000916 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000917 if (path != NULL) {
918 if (f->flags & FUSE_DEBUG) {
Miklos Szeredi6ebe2342002-01-06 21:44:16 +0000919 printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
920 fflush(stdout);
921 }
922
Miklos Szeredia181e612001-11-06 12:03:23 +0000923 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000924 if (f->op.write)
Miklos Szeredi6bf8b682002-10-28 08:49:39 +0000925 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000926 free(path);
Miklos Szeredia181e612001-11-06 12:03:23 +0000927 }
928
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000929 if (res > 0) {
930 if ((size_t) res != arg->size) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000931 fprintf(stderr, "short write: %u (should be %u)\n", res,
932 arg->size);
Miklos Szeredi0e535082003-10-13 10:08:06 +0000933 res = -EINVAL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000934 }
935 else
936 res = 0;
937 }
938
939 send_reply(f, in, res, NULL, 0);
940}
941
Miklos Szeredi77f39942004-03-25 11:17:52 +0000942static int default_statfs(struct statfs *buf)
943{
944 buf->f_namelen = 255;
945 buf->f_bsize = 512;
946 return 0;
947}
948
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000949static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
950{
951 kstatfs->bsize = statfs->f_bsize;
952 kstatfs->blocks = statfs->f_blocks;
953 kstatfs->bfree = statfs->f_bfree;
954 kstatfs->bavail = statfs->f_bavail;
955 kstatfs->files = statfs->f_files;
956 kstatfs->ffree = statfs->f_ffree;
957 kstatfs->namelen = statfs->f_namelen;
958}
959
Mark Glinesd84b39a2002-01-07 16:32:02 +0000960static void do_statfs(struct fuse *f, struct fuse_in_header *in)
961{
962 int res;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000963 struct fuse_statfs_out arg;
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000964 struct statfs buf;
Mark Glinesd84b39a2002-01-07 16:32:02 +0000965
Miklos Szeredi77f39942004-03-25 11:17:52 +0000966 memset(&buf, 0, sizeof(struct statfs));
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000967 if (f->op.statfs)
Miklos Szeredi18e75e42004-02-19 14:23:27 +0000968 res = f->op.statfs("/", &buf);
Miklos Szeredi77f39942004-03-25 11:17:52 +0000969 else
970 res = default_statfs(&buf);
971
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000972 if (res == 0)
Miklos Szeredi77f39942004-03-25 11:17:52 +0000973 convert_statfs(&buf, &arg.st);
Miklos Szeredi4b2bef42002-01-09 12:23:27 +0000974
Mark Glinesd84b39a2002-01-07 16:32:02 +0000975 send_reply(f, in, res, &arg, sizeof(arg));
976}
977
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000978static void do_fsync(struct fuse *f, struct fuse_in_header *in,
979 struct fuse_fsync_in *inarg)
980{
981 int res;
982 char *path;
983
984 res = -ENOENT;
985 path = get_path(f, in->ino);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000986 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000987 res = -ENOSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 if (f->op.fsync)
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000989 res = f->op.fsync(path, inarg->datasync);
990 free(path);
991 }
992 send_reply(f, in, res, NULL, 0);
993}
994
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000995static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
996 struct fuse_setxattr_in *arg)
997{
998 int res;
999 char *path;
1000 char *name = PARAM(arg);
1001 unsigned char *value = name + strlen(name) + 1;
1002
1003 res = -ENOENT;
1004 path = get_path(f, in->ino);
1005 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001006 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001007 if (f->op.setxattr)
1008 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1009 free(path);
1010 }
1011 send_reply(f, in, res, NULL, 0);
1012}
1013
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001014static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1015 const char *name, char *value, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001016{
1017 int res;
1018 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001019
1020 res = -ENOENT;
1021 path = get_path(f, in->ino);
1022 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001023 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001024 if (f->op.getxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001025 res = f->op.getxattr(path, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001026 free(path);
1027 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001028 return res;
1029}
1030
1031static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1032 const char *name, size_t size)
1033{
1034 int res;
1035 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1036 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1037 char *value = outbuf + sizeof(struct fuse_out_header);
1038
1039 res = common_getxattr(f, in, name, value, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001040 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001041 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 size = res;
1043 res = 0;
1044 }
1045 memset(out, 0, sizeof(struct fuse_out_header));
1046 out->unique = in->unique;
1047 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001048
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001049 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001050 free(outbuf);
1051}
1052
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001053static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1054 const char *name)
1055{
1056 int res;
1057 struct fuse_getxattr_out arg;
1058
1059 res = common_getxattr(f, in, name, NULL, 0);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 if (res >= 0) {
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001061 arg.size = res;
1062 res = 0;
1063 }
1064 send_reply(f, in, res, &arg, sizeof(arg));
1065}
1066
1067static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1068 struct fuse_getxattr_in *arg)
1069{
1070 char *name = PARAM(arg);
1071
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001072 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001073 do_getxattr_read(f, in, name, arg->size);
1074 else
1075 do_getxattr_size(f, in, name);
1076}
1077
1078static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1079 char *list, size_t size)
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001080{
1081 int res;
1082 char *path;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001083
1084 res = -ENOENT;
1085 path = get_path(f, in->ino);
1086 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001087 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001088 if (f->op.listxattr)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001089 res = f->op.listxattr(path, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001090 free(path);
1091 }
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001092 return res;
1093}
1094
1095static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1096 size_t size)
1097{
1098 int res;
1099 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1100 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1101 char *list = outbuf + sizeof(struct fuse_out_header);
1102
1103 res = common_listxattr(f, in, list, size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001104 size = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001105 if (res > 0) {
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001106 size = res;
1107 res = 0;
1108 }
1109 memset(out, 0, sizeof(struct fuse_out_header));
1110 out->unique = in->unique;
1111 out->error = res;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001112
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001113 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001114 free(outbuf);
1115}
1116
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001117static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1118{
1119 int res;
1120 struct fuse_getxattr_out arg;
1121
1122 res = common_listxattr(f, in, NULL, 0);
1123 if (res >= 0) {
1124 arg.size = res;
1125 res = 0;
1126 }
1127 send_reply(f, in, res, &arg, sizeof(arg));
1128}
1129
1130static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1131 struct fuse_getxattr_in *arg)
1132{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001133 if (arg->size)
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001134 do_listxattr_read(f, in, arg->size);
1135 else
1136 do_listxattr_size(f, in);
1137}
1138
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001139static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1140 char *name)
1141{
1142 int res;
1143 char *path;
1144
1145 res = -ENOENT;
1146 path = get_path(f, in->ino);
1147 if (path != NULL) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001148 res = -ENOSYS;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001149 if (f->op.removexattr)
1150 res = f->op.removexattr(path, name);
1151 free(path);
1152 }
1153 send_reply(f, in, res, NULL, 0);
1154}
1155
1156
Miklos Szeredi43696432001-11-18 19:15:05 +00001157static void free_cmd(struct fuse_cmd *cmd)
1158{
1159 free(cmd->buf);
1160 free(cmd);
1161}
1162
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001163void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
Miklos Szeredia181e612001-11-06 12:03:23 +00001164{
Miklos Szeredia181e612001-11-06 12:03:23 +00001165 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1166 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1167 size_t argsize;
Miklos Szeredife25def2001-12-20 15:38:05 +00001168 struct fuse_context *ctx = fuse_get_context(f);
Miklos Szeredia181e612001-11-06 12:03:23 +00001169
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001170 dec_avail(f);
Miklos Szeredi33232032001-11-19 17:55:51 +00001171
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001172 if ((f->flags & FUSE_DEBUG)) {
Miklos Szeredic8ba2372002-12-10 12:26:00 +00001173 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1174 in->unique, opname(in->opcode), in->opcode, in->ino,
1175 cmd->buflen);
Miklos Szeredic0938ea2001-11-07 12:35:06 +00001176 fflush(stdout);
1177 }
Miklos Szeredife25def2001-12-20 15:38:05 +00001178
1179 ctx->uid = in->uid;
1180 ctx->gid = in->gid;
Miklos Szeredia181e612001-11-06 12:03:23 +00001181
1182 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1183
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001184 switch (in->opcode) {
Miklos Szeredia181e612001-11-06 12:03:23 +00001185 case FUSE_LOOKUP:
1186 do_lookup(f, in, (char *) inarg);
1187 break;
1188
Miklos Szeredia181e612001-11-06 12:03:23 +00001189 case FUSE_GETATTR:
1190 do_getattr(f, in);
1191 break;
1192
1193 case FUSE_SETATTR:
1194 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1195 break;
1196
1197 case FUSE_READLINK:
1198 do_readlink(f, in);
1199 break;
1200
1201 case FUSE_GETDIR:
1202 do_getdir(f, in);
1203 break;
1204
1205 case FUSE_MKNOD:
1206 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1207 break;
1208
1209 case FUSE_MKDIR:
1210 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1211 break;
1212
1213 case FUSE_UNLINK:
Miklos Szeredib5958612004-02-20 14:10:49 +00001214 do_unlink(f, in, (char *) inarg);
1215 break;
1216
Miklos Szeredia181e612001-11-06 12:03:23 +00001217 case FUSE_RMDIR:
Miklos Szeredib5958612004-02-20 14:10:49 +00001218 do_rmdir(f, in, (char *) inarg);
Miklos Szeredia181e612001-11-06 12:03:23 +00001219 break;
1220
1221 case FUSE_SYMLINK:
1222 do_symlink(f, in, (char *) inarg,
1223 ((char *) inarg) + strlen((char *) inarg) + 1);
1224 break;
1225
1226 case FUSE_RENAME:
1227 do_rename(f, in, (struct fuse_rename_in *) inarg);
1228 break;
1229
1230 case FUSE_LINK:
1231 do_link(f, in, (struct fuse_link_in *) inarg);
1232 break;
1233
1234 case FUSE_OPEN:
1235 do_open(f, in, (struct fuse_open_in *) inarg);
1236 break;
1237
Miklos Szeredie2e4ac22004-05-18 08:45:28 +00001238 case FUSE_FLUSH:
1239 do_flush(f, in);
1240 break;
1241
Miklos Szeredi9478e862002-12-11 09:50:26 +00001242 case FUSE_RELEASE:
1243 do_release(f, in, (struct fuse_open_in *) inarg);
1244 break;
1245
Miklos Szeredia181e612001-11-06 12:03:23 +00001246 case FUSE_READ:
1247 do_read(f, in, (struct fuse_read_in *) inarg);
1248 break;
1249
1250 case FUSE_WRITE:
1251 do_write(f, in, (struct fuse_write_in *) inarg);
1252 break;
1253
Mark Glinesd84b39a2002-01-07 16:32:02 +00001254 case FUSE_STATFS:
1255 do_statfs(f, in);
1256 break;
1257
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +00001258 case FUSE_FSYNC:
1259 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1260 break;
1261
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001262 case FUSE_SETXATTR:
1263 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1264 break;
1265
1266 case FUSE_GETXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001267 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001268 break;
1269
1270 case FUSE_LISTXATTR:
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001271 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001272 break;
1273
1274 case FUSE_REMOVEXATTR:
1275 do_removexattr(f, in, (char *) inarg);
1276 break;
1277
Miklos Szeredia181e612001-11-06 12:03:23 +00001278 default:
Miklos Szeredi43696432001-11-18 19:15:05 +00001279 send_reply(f, in, -ENOSYS, NULL, 0);
Miklos Szeredia181e612001-11-06 12:03:23 +00001280 }
Miklos Szeredi43696432001-11-18 19:15:05 +00001281
1282 free_cmd(cmd);
Miklos Szeredia181e612001-11-06 12:03:23 +00001283}
1284
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001285struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001286{
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001287 ssize_t res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001288 struct fuse_cmd *cmd;
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001289 struct fuse_in_header *in;
1290 void *inarg;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001291
Miklos Szeredi43696432001-11-18 19:15:05 +00001292 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1293 cmd->buf = (char *) malloc(FUSE_MAX_IN);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001294 in = (struct fuse_in_header *) cmd->buf;
1295 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi43696432001-11-18 19:15:05 +00001296
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001297 do {
1298 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001299 if (res == -1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001300 free_cmd(cmd);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001301 if (f->exited || errno == EINTR)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001302 return NULL;
1303
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001304 /* ENODEV means we got unmounted, so we silenty return failure */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001305 if (errno != ENODEV) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001306 /* BAD... This will happen again */
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001307 perror("fuse: reading device");
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001308 }
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001309
1310 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001311 return NULL;
Miklos Szeredi96249982001-11-21 12:21:19 +00001312 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001313 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001314 free_cmd(cmd);
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001315 /* Cannot happen */
1316 fprintf(stderr, "short read on fuse device\n");
1317 fuse_exit(f);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001318 return NULL;
1319 }
1320 cmd->buflen = res;
1321
1322 /* Forget is special, it can be done without messing with threads. */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001323 if (in->opcode == FUSE_FORGET)
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001324 do_forget(f, in, (struct fuse_forget_in *) inarg);
1325
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001326 } while (in->opcode == FUSE_FORGET);
Miklos Szeredi99ddf0e2001-11-25 17:19:59 +00001327
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001328 return cmd;
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001329}
1330
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001331void fuse_loop(struct fuse *f)
1332{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001333 if (f == NULL)
Miklos Szeredic40748a2004-02-20 16:38:45 +00001334 return;
1335
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001336 while (1) {
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001337 struct fuse_cmd *cmd;
1338
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001339 if (f->exited)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001340 return;
1341
1342 cmd = __fuse_read_cmd(f);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001343 if (cmd == NULL)
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001344 continue;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001345
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001346 __fuse_process_cmd(f, cmd);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001347 }
1348}
1349
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001350void fuse_exit(struct fuse *f)
1351{
1352 f->exited = 1;
1353}
1354
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001355struct fuse_context *fuse_get_context(struct fuse *f)
1356{
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001357 if (f->getcontext)
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001358 return f->getcontext(f);
1359 else
1360 return &f->context;
1361}
1362
Miklos Szeredic40748a2004-02-20 16:38:45 +00001363static int check_version(struct fuse *f)
1364{
1365 int res;
1366 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001367 if (vf == NULL) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001368 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1369 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1370 return -1;
1371 }
1372 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1373 fclose(vf);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001374 if (res != 2) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001375 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1376 return -1;
1377 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001378 if (f->majorver != FUSE_KERNEL_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001379 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1380 FUSE_KERNEL_VERSION);
1381 return -1;
1382 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001383 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001384 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1385 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1386 return -1;
1387 }
1388
1389 return 0;
1390}
1391
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001392struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001393{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001394 struct fuse *f;
1395 struct node *root;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001396
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001397 f = (struct fuse *) calloc(1, sizeof(struct fuse));
Miklos Szeredi2df1c042001-11-06 15:07:17 +00001398
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001399 if (check_version(f) == -1) {
Miklos Szeredic40748a2004-02-20 16:38:45 +00001400 free(f);
1401 return NULL;
1402 }
1403
Miklos Szeredia181e612001-11-06 12:03:23 +00001404 f->flags = flags;
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001405 f->fd = fd;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001406 f->ctr = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001407 f->generation = 0;
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001408 /* FIXME: Dynamic hash table */
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001409 f->name_table_size = 14057;
1410 f->name_table = (struct node **)
1411 calloc(1, sizeof(struct node *) * f->name_table_size);
1412 f->ino_table_size = 14057;
1413 f->ino_table = (struct node **)
1414 calloc(1, sizeof(struct node *) * f->ino_table_size);
Miklos Szeredia181e612001-11-06 12:03:23 +00001415 pthread_mutex_init(&f->lock, NULL);
Miklos Szeredi33232032001-11-19 17:55:51 +00001416 f->numworker = 0;
1417 f->numavail = 0;
Miklos Szeredi2e50d432001-12-20 12:17:25 +00001418 f->op = *op;
1419 f->getcontext = NULL;
1420 f->context.uid = 0;
1421 f->context.gid = 0;
Miklos Szeredi0f48a262002-12-05 14:23:01 +00001422 f->exited = 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001423
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001424 root = (struct node *) calloc(1, sizeof(struct node));
Miklos Szeredi8cffdb92001-11-09 14:49:18 +00001425 root->mode = 0;
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001426 root->rdev = 0;
1427 root->name = strdup("/");
1428 root->parent = 0;
Miklos Szeredi76f65782004-02-19 16:55:40 +00001429 root->ino = FUSE_ROOT_INO;
1430 root->generation = 0;
1431 hash_ino(f, root);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001432
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001433 return f;
1434}
1435
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001436void fuse_destroy(struct fuse *f)
1437{
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001438 size_t i;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001439 for (i = 0; i < f->ino_table_size; i++) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001440 struct node *node;
1441 struct node *next;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001442 for (node = f->ino_table[i]; node != NULL; node = next) {
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001443 next = node->ino_next;
1444 free_node(node);
1445 }
1446 }
1447 free(f->ino_table);
1448 free(f->name_table);
Miklos Szeredia181e612001-11-06 12:03:23 +00001449 pthread_mutex_destroy(&f->lock);
Miklos Szeredi97c61e92001-11-07 12:09:43 +00001450 free(f);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001451}