1 /*
2 * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #if defined(__APPLE__)
22 # if ! defined(__DARWIN_64_BIT_INO_T) && ! defined(_DARWIN_USE_64_BIT_INODE)
23 # define __DARWIN_64_BIT_INO_T 0
24 # endif
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <fuse_lowlevel.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <assert.h>
39 #include <syslog.h>
40 #include <inttypes.h>
41 #include <pthread.h>
42
43 #include "stats.h"
44 #include "oplog.h"
45 #include "datapack.h"
46 #include "clocks.h"
47 #include "mastercomm.h"
48 #include "masterproxy.h"
49 #include "getgroups.h"
50 #include "readdata.h"
51 #include "writedata.h"
52 #include "massert.h"
53 #include "strerr.h"
54 #include "MFSCommunication.h"
55
56 #include "sustained_stats.h"
57 #include "dirattrcache.h"
58 #include "symlinkcache.h"
59 #include "negentrycache.h"
60 #include "xattrcache.h"
61 // #include "dircache.h"
62
63 #if MFS_ROOT_ID != FUSE_ROOT_ID
64 #error FUSE_ROOT_ID is not equal to MFS_ROOT_ID
65 #endif
66
67 #if defined(__FreeBSD__)
68 // workaround for bug in FreeBSD Fuse version (kernel part)
69 # define FREEBSD_FALSE_TRUNCATE_WORKAROUND 1
70 # define FREEBSD_EARLY_RELEASE_BUG_WORKAROUND 1
71 # define FREEBSD_EARLY_RELEASE_DELAY 10.0
72 #endif
73
74 #define READDIR_BUFFSIZE 50000
75
76 #define MAX_FILE_SIZE (int64_t)(MFS_MAX_FILE_SIZE)
77
78 #define PKGVERSION ((VERSMAJ)*1000000+(VERSMID)*10000+((VERSMIN)>>1)*100+(RELEASE))
79
80 #define MASTERINFO_WITH_VERSION 1
81 // #define MASTER_NAME ".master"
82 // #define MASTER_INODE 0x7FFFFFFF
83 // 0x01b6 == 0666
84 // static uint8_t masterattr[35]={'f', 0x01,0xB6, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,0};
85
86 #define MASTERINFO_NAME ".masterinfo"
87 #define MASTERINFO_INODE 0x7FFFFFFF
88 // 0x0124 == 0b100100100 == 0444
89 #ifdef MASTERINFO_WITH_VERSION
90 static uint8_t masterinfoattr[35]={'f', 0x01,0x24, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,14};
91 #else
92 static uint8_t masterinfoattr[35]={'f', 0x01,0x24, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,10};
93 #endif
94
95 #define STATS_NAME ".stats"
96 #define STATS_INODE 0x7FFFFFF0
97 // 0x01A4 == 0b110100100 == 0644
98 static uint8_t statsattr[35]={'f', 0x01,0xA4, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,0};
99
100 #define OPLOG_NAME ".oplog"
101 #define OPLOG_INODE 0x7FFFFFF1
102 #define OPHISTORY_NAME ".ophistory"
103 #define OPHISTORY_INODE 0x7FFFFFF2
104 // 0x0100 == 0b100000000 == 0400
105 static uint8_t oplogattr[35]={'f', 0x01,0x00, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,0};
106
107 #define MOOSE_NAME ".mooseart"
108 #define MOOSE_INODE 0x7FFFFFF3
109 // 0x01A4 == 0b110100100 == 0644
110 static uint8_t mooseattr[35]={'f', 0x01,0xA4, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,0};
111
112 /* DIRCACHE
113 #define ATTRCACHE_NAME ".attrcache"
114 #define ATTRCACHE_INODE 0x7FFFFFF3
115 // 0x0180 == 0b110000000 == 0600
116 static uint8_t attrcacheattr[35]={'f', 0x01,0x80, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,0,0,0,0};
117 */
118
119 #define MIN_SPECIAL_INODE 0x7FFFFFF0
120 #define IS_SPECIAL_INODE(ino) ((ino)>=MIN_SPECIAL_INODE)
121 #define IS_SPECIAL_NAME(name) ((name)[0]=='.' && (strcmp(STATS_NAME,(name))==0 || strcmp(MASTERINFO_NAME,(name))==0 || strcmp(OPLOG_NAME,(name))==0 || strcmp(OPHISTORY_NAME,(name))==0 || strcmp(MOOSE_NAME,(name))==0/* || strcmp(ATTRCACHE_NAME,(name))==0*/))
122
123 typedef struct _sinfo {
124 char *buff;
125 uint32_t leng;
126 uint8_t reset;
127 pthread_mutex_t lock;
128 } sinfo;
129
130 typedef struct _dirbuf {
131 int wasread;
132 int dataformat;
133 uid_t uid;
134 gid_t gid;
135 const uint8_t *p;
136 size_t size;
137 void *dcache;
138 pthread_mutex_t lock;
139 } dirbuf;
140
141 enum {IO_NONE,IO_READ,IO_WRITE,IO_READONLY,IO_WRITEONLY};
142
143 typedef struct _finfo {
144 uint8_t mode;
145 void *data;
146 pthread_mutex_t lock;
147 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
148 uint32_t ops_in_progress;
149 double lastuse;
150 struct _finfo *next;
151 #endif
152 } finfo;
153
154 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
155 static finfo *finfo_head = NULL;
156 static pthread_mutex_t finfo_list_lock = PTHREAD_MUTEX_INITIALIZER;
157 #endif
158
159 static int debug_mode = 0;
160 static int usedircache = 1;
161 static int keep_cache = 0;
162 static double direntry_cache_timeout = 0.1;
163 static double entry_cache_timeout = 0.0;
164 static double attr_cache_timeout = 0.1;
165 static int mkdir_copy_sgid = 0;
166 static int sugid_clear_mode = 0;
167 static int xattr_cache_on = 0;
168 static int xattr_acl_support = 0;
169 static int full_permissions = 0;
170
171 //static int local_mode = 0;
172 //static int no_attr_cache = 0;
173
174 enum {
175 OP_STATFS = 0,
176 OP_ACCESS,
177 OP_LOOKUP,
178 OP_ERRLOOKUP,
179 OP_POSLOOKUP,
180 OP_NEGLOOKUP,
181 OP_LOOKUP_INTERNAL,
182 OP_DIRCACHE_LOOKUP,
183 OP_NEGCACHE_LOOKUP,
184 // OP_DIRCACHE_LOOKUP_POSITIVE,
185 // OP_DIRCACHE_LOOKUP_NEGATIVE,
186 // OP_DIRCACHE_LOOKUP_NOATTR,
187 OP_GETATTR,
188 OP_DIRCACHE_GETATTR,
189 OP_SETATTR,
190 OP_MKNOD,
191 OP_UNLINK,
192 OP_MKDIR,
193 OP_RMDIR,
194 OP_SYMLINK,
195 OP_READLINK_MASTER,
196 OP_READLINK_CACHED,
197 OP_RENAME,
198 OP_LINK,
199 OP_OPENDIR,
200 OP_READDIR,
201 OP_RELEASEDIR,
202 OP_CREATE,
203 OP_OPEN,
204 OP_RELEASE,
205 OP_READ,
206 OP_WRITE,
207 OP_FLUSH,
208 OP_FSYNC,
209 OP_SETXATTR,
210 OP_GETXATTR,
211 OP_LISTXATTR,
212 OP_REMOVEXATTR,
213 // OP_GETDIR_CACHED,
214 OP_GETDIR_FULL,
215 OP_GETDIR_SMALL,
216 STATNODES
217 };
218
219 static void *statsptr[STATNODES];
220
mfs_statsptr_init(void)221 void mfs_statsptr_init(void) {
222 void *s;
223 s = stats_get_subnode(NULL,"fuse_ops",0,1);
224 statsptr[OP_SETXATTR] = stats_get_subnode(s,"setxattr",0,1);
225 statsptr[OP_GETXATTR] = stats_get_subnode(s,"getxattr",0,1);
226 statsptr[OP_LISTXATTR] = stats_get_subnode(s,"listxattr",0,1);
227 statsptr[OP_REMOVEXATTR] = stats_get_subnode(s,"removexattr",0,1);
228 statsptr[OP_FSYNC] = stats_get_subnode(s,"fsync",0,1);
229 statsptr[OP_FLUSH] = stats_get_subnode(s,"flush",0,1);
230 statsptr[OP_WRITE] = stats_get_subnode(s,"write",0,1);
231 statsptr[OP_READ] = stats_get_subnode(s,"read",0,1);
232 statsptr[OP_RELEASE] = stats_get_subnode(s,"release",0,1);
233 statsptr[OP_OPEN] = stats_get_subnode(s,"open",0,1);
234 statsptr[OP_CREATE] = stats_get_subnode(s,"create",0,1);
235 statsptr[OP_RELEASEDIR] = stats_get_subnode(s,"releasedir",0,1);
236 statsptr[OP_READDIR] = stats_get_subnode(s,"readdir",0,1);
237 statsptr[OP_OPENDIR] = stats_get_subnode(s,"opendir",0,1);
238 statsptr[OP_LINK] = stats_get_subnode(s,"link",0,1);
239 statsptr[OP_RENAME] = stats_get_subnode(s,"rename",0,1);
240 {
241 void *rl;
242 rl = stats_get_subnode(s,"readlink",0,1);
243 statsptr[OP_READLINK_MASTER] = stats_get_subnode(rl,"master",0,1);
244 statsptr[OP_READLINK_CACHED] = stats_get_subnode(rl,"cached",0,1);
245 }
246 statsptr[OP_SYMLINK] = stats_get_subnode(s,"symlink",0,1);
247 statsptr[OP_RMDIR] = stats_get_subnode(s,"rmdir",0,1);
248 statsptr[OP_MKDIR] = stats_get_subnode(s,"mkdir",0,1);
249 statsptr[OP_UNLINK] = stats_get_subnode(s,"unlink",0,1);
250 statsptr[OP_MKNOD] = stats_get_subnode(s,"mknod",0,1);
251 statsptr[OP_SETATTR] = stats_get_subnode(s,"setattr",0,1);
252 statsptr[OP_GETATTR] = stats_get_subnode(s,"getattr",0,1);
253 statsptr[OP_DIRCACHE_GETATTR] = stats_get_subnode(s,"getattr-cached",0,1);
254 {
255 void *l,*cl,*nl;
256 l = stats_get_subnode(s,"lookup",0,1);
257 cl = stats_get_subnode(l,"cached",0,1);
258 nl = stats_get_subnode(l,"master",0,1);
259 statsptr[OP_LOOKUP_INTERNAL] = stats_get_subnode(l,"internal",0,1);
260 statsptr[OP_POSLOOKUP] = stats_get_subnode(nl,"positive",0,1);
261 statsptr[OP_NEGLOOKUP] = stats_get_subnode(nl,"negative",0,1);
262 statsptr[OP_ERRLOOKUP] = stats_get_subnode(nl,"error",0,1);
263 if (usedircache) {
264 statsptr[OP_DIRCACHE_LOOKUP] = stats_get_subnode(cl,"readdir",0,1);
265 }
266 statsptr[OP_NEGCACHE_LOOKUP] = stats_get_subnode(cl,"negative",0,1);
267 }
268 statsptr[OP_ACCESS] = stats_get_subnode(s,"access",0,1);
269 statsptr[OP_STATFS] = stats_get_subnode(s,"statfs",0,1);
270 {
271 void *rd;
272 rd = stats_get_subnode(s,"readdir",0,1);
273 if (usedircache) {
274 statsptr[OP_GETDIR_FULL] = stats_get_subnode(rd,"with_attrs",0,1);
275 }
276 statsptr[OP_GETDIR_SMALL] = stats_get_subnode(rd,"without_attrs",0,1);
277 }
278 }
279
mfs_stats_inc(uint8_t id)280 void mfs_stats_inc(uint8_t id) {
281 if (id<STATNODES) {
282 stats_counter_inc(statsptr[id]);
283 }
284 }
285
286 static pthread_key_t aclstorage;
287
mfs_aclstorage_free(void * ptr)288 void mfs_aclstorage_free(void *ptr) {
289 if (ptr!=NULL) {
290 free(ptr);
291 }
292 }
293
mfs_aclstorage_init(void)294 void mfs_aclstorage_init(void) {
295 zassert(pthread_key_create(&aclstorage,mfs_aclstorage_free));
296 zassert(pthread_setspecific(aclstorage,NULL));
297 }
298
mfs_aclstorage_get(uint32_t size)299 void* mfs_aclstorage_get(uint32_t size) {
300 uint8_t *buff,*p;
301 const uint8_t *cp;
302 uint32_t s;
303 buff = pthread_getspecific(aclstorage);
304 if (buff!=NULL) {
305 cp = p = buff;
306 s = get32bit(&cp);
307 if (size<=s) {
308 return (buff+4);
309 }
310 free(buff);
311 }
312 buff = malloc(size+4);
313 passert(buff);
314 p = buff;
315 put32bit(&p,size);
316 zassert(pthread_setspecific(aclstorage,buff));
317 return p;
318 }
319
320 #ifndef EDQUOT
321 # define EDQUOT ENOSPC
322 #endif
323 #ifndef ENOATTR
324 # ifdef ENODATA
325 # define ENOATTR ENODATA
326 # else
327 # define ENOATTR ENOENT
328 # endif
329 #endif
330
mfs_errorconv(int status)331 static int mfs_errorconv(int status) {
332 int ret;
333 switch (status) {
334 case STATUS_OK:
335 ret=0;
336 break;
337 case ERROR_EPERM:
338 ret=EPERM;
339 break;
340 case ERROR_ENOTDIR:
341 ret=ENOTDIR;
342 break;
343 case ERROR_ENOENT:
344 ret=ENOENT;
345 break;
346 case ERROR_EACCES:
347 ret=EACCES;
348 break;
349 case ERROR_EEXIST:
350 ret=EEXIST;
351 break;
352 case ERROR_EINVAL:
353 ret=EINVAL;
354 break;
355 case ERROR_ENOTEMPTY:
356 ret=ENOTEMPTY;
357 break;
358 case ERROR_IO:
359 ret=EIO;
360 break;
361 case ERROR_EROFS:
362 ret=EROFS;
363 break;
364 case ERROR_QUOTA:
365 ret=EDQUOT;
366 break;
367 case ERROR_ENOATTR:
368 ret=ENOATTR;
369 break;
370 case ERROR_ENOTSUP:
371 ret=ENOTSUP;
372 break;
373 case ERROR_ERANGE:
374 ret=ERANGE;
375 break;
376 case ERROR_NOSPACE:
377 ret=ENOSPC;
378 break;
379 case ERROR_CHUNKLOST:
380 ret=ENXIO;
381 break;
382 case ERROR_NOCHUNKSERVERS:
383 ret=ENOSPC;
384 break;
385 case ERROR_CSNOTPRESENT:
386 ret=ENXIO;
387 break;
388 default:
389 ret=EINVAL;
390 break;
391 }
392 if (debug_mode && ret!=0) {
393 #ifdef HAVE_STRERROR_R
394 char errorbuff[500];
395 # ifdef STRERROR_R_CHAR_P
396 fprintf(stderr,"status: %s\n",strerror_r(ret,errorbuff,500));
397 # else
398 strerror_r(ret,errorbuff,500);
399 fprintf(stderr,"status: %s\n",errorbuff);
400 # endif
401 #else
402 # ifdef HAVE_PERROR
403 errno=ret;
404 perror("status: ");
405 # else
406 fprintf(stderr,"status: %d\n",ret);
407 # endif
408 #endif
409 }
410 return ret;
411 }
412
fsnodes_type_convert(uint8_t type)413 static inline uint8_t fsnodes_type_convert(uint8_t type) {
414 switch (type) {
415 case DISP_TYPE_FILE:
416 return TYPE_FILE;
417 case DISP_TYPE_DIRECTORY:
418 return TYPE_DIRECTORY;
419 case DISP_TYPE_SYMLINK:
420 return TYPE_SYMLINK;
421 case DISP_TYPE_FIFO:
422 return TYPE_FIFO;
423 case DISP_TYPE_BLOCKDEV:
424 return TYPE_BLOCKDEV;
425 case DISP_TYPE_CHARDEV:
426 return TYPE_CHARDEV;
427 case DISP_TYPE_SOCKET:
428 return TYPE_SOCKET;
429 case DISP_TYPE_TRASH:
430 return TYPE_TRASH;
431 case DISP_TYPE_SUSTAINED:
432 return TYPE_SUSTAINED;
433 }
434 return 0;
435 }
436
mfs_type_to_stat(uint32_t inode,uint8_t type,struct stat * stbuf)437 static void mfs_type_to_stat(uint32_t inode,uint8_t type, struct stat *stbuf) {
438 memset(stbuf,0,sizeof(struct stat));
439 stbuf->st_ino = inode;
440 switch (type&0x7F) {
441 case DISP_TYPE_DIRECTORY:
442 case TYPE_DIRECTORY:
443 stbuf->st_mode = S_IFDIR;
444 break;
445 case DISP_TYPE_SYMLINK:
446 case TYPE_SYMLINK:
447 stbuf->st_mode = S_IFLNK;
448 break;
449 case DISP_TYPE_FILE:
450 case TYPE_FILE:
451 stbuf->st_mode = S_IFREG;
452 break;
453 case DISP_TYPE_FIFO:
454 case TYPE_FIFO:
455 stbuf->st_mode = S_IFIFO;
456 break;
457 case DISP_TYPE_SOCKET:
458 case TYPE_SOCKET:
459 stbuf->st_mode = S_IFSOCK;
460 break;
461 case DISP_TYPE_BLOCKDEV:
462 case TYPE_BLOCKDEV:
463 stbuf->st_mode = S_IFBLK;
464 break;
465 case DISP_TYPE_CHARDEV:
466 case TYPE_CHARDEV:
467 stbuf->st_mode = S_IFCHR;
468 break;
469 default:
470 stbuf->st_mode = 0;
471 }
472 }
473
mfs_attr_get_type(const uint8_t attr[35])474 static inline uint8_t mfs_attr_get_type(const uint8_t attr[35]) {
475 if (attr[0]<64) { // 1.7.29 and up
476 return (attr[1]>>4);
477 } else {
478 return fsnodes_type_convert(attr[0]&0x7F);
479 }
480 }
481
mfs_attr_get_mattr(const uint8_t attr[35])482 static inline uint8_t mfs_attr_get_mattr(const uint8_t attr[35]) {
483 if (attr[0]<64) { // 1.7.29 and up
484 return attr[0];
485 } else {
486 return (attr[1]>>4);
487 }
488 }
489
mfs_attr_modify(uint32_t to_set,uint8_t attr[35],struct stat * stbuf)490 static void mfs_attr_modify(uint32_t to_set,uint8_t attr[35],struct stat *stbuf) {
491 uint8_t mattr;
492 uint16_t attrmode;
493 uint8_t attrtype;
494 uint32_t attruid,attrgid,attratime,attrmtime,attrctime;
495 const uint8_t *ptr;
496 uint8_t *wptr;
497 ptr = attr;
498 if (attr[0]<64) { // 1.7.29 and up
499 mattr = get8bit(&ptr);
500 attrmode = get16bit(&ptr);
501 attrtype = (attrmode>>12);
502 } else {
503 attrtype = get8bit(&ptr);
504 attrtype = fsnodes_type_convert(attrtype&0x7F);
505 attrmode = get16bit(&ptr);
506 mattr = attrmode >> 12;
507 }
508 attrmode &= 0x0FFF;
509 attruid = get32bit(&ptr);
510 attrgid = get32bit(&ptr);
511 attratime = get32bit(&ptr);
512 attrmtime = get32bit(&ptr);
513 attrctime = get32bit(&ptr);
514 if (to_set & FUSE_SET_ATTR_MODE) {
515 attrmode = stbuf->st_mode & 07777;
516 }
517 if (to_set & FUSE_SET_ATTR_UID) {
518 attruid = stbuf->st_uid;
519 }
520 if (to_set & FUSE_SET_ATTR_GID) {
521 attrgid = stbuf->st_gid;
522 }
523 if (to_set & FUSE_SET_ATTR_ATIME) {
524 attratime = stbuf->st_atime;
525 }
526 if (to_set & FUSE_SET_ATTR_MTIME) {
527 attratime = stbuf->st_mtime;
528 }
529 attrctime = time(NULL);
530 wptr = attr;
531 put8bit(&wptr,mattr);
532 attrmode |= ((uint16_t)attrtype)<<12;
533 put16bit(&wptr,attrmode);
534 put32bit(&wptr,attruid);
535 put32bit(&wptr,attrgid);
536 put32bit(&wptr,attratime);
537 put32bit(&wptr,attrmtime);
538 put32bit(&wptr,attrctime);
539 }
540
mfs_attr_to_stat(uint32_t inode,const uint8_t attr[35],struct stat * stbuf)541 static void mfs_attr_to_stat(uint32_t inode,const uint8_t attr[35], struct stat *stbuf) {
542 uint16_t attrmode;
543 uint8_t attrtype;
544 uint32_t attruid,attrgid,attratime,attrmtime,attrctime,attrnlink,attrrdev;
545 uint64_t attrlength;
546 const uint8_t *ptr;
547 ptr = attr;
548 if (attr[0]<64) { // 1.7.29 and up
549 ptr++;
550 attrmode = get16bit(&ptr);
551 attrtype = (attrmode>>12);
552 } else {
553 attrtype = get8bit(&ptr);
554 attrtype = fsnodes_type_convert(attrtype&0x7F);
555 attrmode = get16bit(&ptr);
556 }
557 attrmode &= 0x0FFF;
558 attruid = get32bit(&ptr);
559 attrgid = get32bit(&ptr);
560 attratime = get32bit(&ptr);
561 attrmtime = get32bit(&ptr);
562 attrctime = get32bit(&ptr);
563 attrnlink = get32bit(&ptr);
564 stbuf->st_ino = inode;
565 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
566 stbuf->st_blksize = MFSBLOCKSIZE;
567 #endif
568 switch (attrtype & 0x7F) {
569 case TYPE_DIRECTORY:
570 stbuf->st_mode = S_IFDIR | attrmode;
571 attrlength = get64bit(&ptr);
572 stbuf->st_size = attrlength;
573 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
574 stbuf->st_blocks = (attrlength+511)/512;
575 #endif
576 break;
577 case TYPE_SYMLINK:
578 stbuf->st_mode = S_IFLNK | attrmode;
579 attrlength = get64bit(&ptr);
580 stbuf->st_size = attrlength;
581 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
582 stbuf->st_blocks = (attrlength+511)/512;
583 #endif
584 break;
585 case TYPE_FILE:
586 stbuf->st_mode = S_IFREG | attrmode;
587 attrlength = get64bit(&ptr);
588 stbuf->st_size = attrlength;
589 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
590 stbuf->st_blocks = (attrlength+511)/512;
591 #endif
592 break;
593 case TYPE_FIFO:
594 stbuf->st_mode = S_IFIFO | attrmode;
595 stbuf->st_size = 0;
596 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
597 stbuf->st_blocks = 0;
598 #endif
599 break;
600 case TYPE_SOCKET:
601 stbuf->st_mode = S_IFSOCK | attrmode;
602 stbuf->st_size = 0;
603 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
604 stbuf->st_blocks = 0;
605 #endif
606 break;
607 case TYPE_BLOCKDEV:
608 stbuf->st_mode = S_IFBLK | attrmode;
609 attrrdev = get32bit(&ptr);
610 #ifdef HAVE_STRUCT_STAT_ST_RDEV
611 stbuf->st_rdev = attrrdev;
612 #endif
613 stbuf->st_size = 0;
614 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
615 stbuf->st_blocks = 0;
616 #endif
617 break;
618 case TYPE_CHARDEV:
619 stbuf->st_mode = S_IFCHR | attrmode;
620 attrrdev = get32bit(&ptr);
621 #ifdef HAVE_STRUCT_STAT_ST_RDEV
622 stbuf->st_rdev = attrrdev;
623 #endif
624 stbuf->st_size = 0;
625 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
626 stbuf->st_blocks = 0;
627 #endif
628 break;
629 default:
630 stbuf->st_mode = 0;
631 }
632 stbuf->st_uid = attruid;
633 stbuf->st_gid = attrgid;
634 stbuf->st_atime = attratime;
635 stbuf->st_mtime = attrmtime;
636 stbuf->st_ctime = attrctime;
637 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
638 stbuf->st_birthtime = attrctime; // for future use
639 #endif
640 stbuf->st_nlink = attrnlink;
641 }
642
mfs_makemodestr(char modestr[11],uint16_t mode)643 static inline void mfs_makemodestr(char modestr[11],uint16_t mode) {
644 uint32_t i;
645 strcpy(modestr,"?rwxrwxrwx");
646 switch (mode & S_IFMT) {
647 case S_IFSOCK:
648 modestr[0] = 's';
649 break;
650 case S_IFLNK:
651 modestr[0] = 'l';
652 break;
653 case S_IFREG:
654 modestr[0] = '-';
655 break;
656 case S_IFBLK:
657 modestr[0] = 'b';
658 break;
659 case S_IFDIR:
660 modestr[0] = 'd';
661 break;
662 case S_IFCHR:
663 modestr[0] = 'c';
664 break;
665 case S_IFIFO:
666 modestr[0] = 'f';
667 break;
668 }
669 if (mode & S_ISUID) {
670 modestr[3] = 's';
671 }
672 if (mode & S_ISGID) {
673 modestr[6] = 's';
674 }
675 if (mode & S_ISVTX) {
676 modestr[9] = 't';
677 }
678 for (i=0 ; i<9 ; i++) {
679 if ((mode & (1<<i))==0) {
680 if (modestr[9-i]=='s' || modestr[9-i]=='t') {
681 modestr[9-i]&=0xDF;
682 } else {
683 modestr[9-i]='-';
684 }
685 }
686 }
687 }
688
mfs_makeattrstr(char * buff,uint32_t size,struct stat * stbuf)689 static void mfs_makeattrstr(char *buff,uint32_t size,struct stat *stbuf) {
690 char modestr[11];
691 mfs_makemodestr(modestr,stbuf->st_mode);
692 #ifdef HAVE_STRUCT_STAT_ST_RDEV
693 if (modestr[0]=='b' || modestr[0]=='c') {
694 snprintf(buff,size,"[%s:0%06o,%u,%ld,%ld,%lu,%lu,%lu,%llu,%08lX]",modestr,(unsigned int)(stbuf->st_mode),(unsigned int)(stbuf->st_nlink),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long int)(stbuf->st_ctime),(unsigned long long int)(stbuf->st_size),(unsigned long int)(stbuf->st_rdev));
695 } else {
696 snprintf(buff,size,"[%s:0%06o,%u,%ld,%ld,%lu,%lu,%lu,%llu]",modestr,(unsigned int)(stbuf->st_mode),(unsigned int)(stbuf->st_nlink),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long int)(stbuf->st_ctime),(unsigned long long int)(stbuf->st_size));
697 }
698 #else
699 snprintf(buff,size,"[%s:0%06o,%u,%ld,%ld,%lu,%lu,%lu,%llu]",modestr,(unsigned int)(stbuf->st_mode),(unsigned int)(stbuf->st_nlink),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long int)(stbuf->st_ctime),(unsigned long long int)(stbuf->st_size));
700 #endif
701 }
702
703 #if FUSE_USE_VERSION >= 26
mfs_statfs(fuse_req_t req,fuse_ino_t ino)704 void mfs_statfs(fuse_req_t req,fuse_ino_t ino) {
705 #else
706 void mfs_statfs(fuse_req_t req) {
707 #endif
708 uint64_t totalspace,availspace,trashspace,sustainedspace;
709 uint32_t inodes;
710 uint32_t bsize;
711 struct statvfs stfsbuf;
712 memset(&stfsbuf,0,sizeof(stfsbuf));
713 struct fuse_ctx ctx;
714
715 ctx = *(fuse_req_ctx(req));
716 mfs_stats_inc(OP_STATFS);
717 if (debug_mode) {
718 #if FUSE_USE_VERSION >= 26
719 oplog_printf(&ctx,"statfs (%lu)",(unsigned long int)ino);
720 #else
721 oplog_printf(&ctx,"statfs ()");
722 #endif
723 }
724 #if FUSE_USE_VERSION >= 26
725 (void)ino;
726 #endif
727 fs_statfs(&totalspace,&availspace,&trashspace,&sustainedspace,&inodes);
728
729 #if defined(__APPLE__)
730 if (totalspace>0x0001000000000000ULL) {
731 bsize = 0x20000;
732 } else {
733 bsize = 0x10000;
734 }
735 #else
736 bsize = 0x10000;
737 #endif
738
739 stfsbuf.f_namemax = MFS_NAME_MAX;
740 stfsbuf.f_frsize = bsize;
741 stfsbuf.f_bsize = bsize;
742 #if defined(__APPLE__)
743 // FUSE on apple (or other parts of kernel) expects 32-bit values, so it's better to saturate this values than let being cut on 32-bit
744 // can't change bsize also because 64k seems to be the biggest acceptable value for bsize
745
746 if (totalspace/bsize>0xFFFFFFFFU) {
747 stfsbuf.f_blocks = 0xFFFFFFFFU;
748 } else {
749 stfsbuf.f_blocks = totalspace/bsize;
750 }
751 if (availspace/bsize>0xFFFFFFFFU) {
752 stfsbuf.f_bfree = 0xFFFFFFFFU;
753 stfsbuf.f_bavail = 0xFFFFFFFFU;
754 } else {
755 stfsbuf.f_bfree = availspace/bsize;
756 stfsbuf.f_bavail = availspace/bsize;
757 }
758 #else
759 stfsbuf.f_blocks = totalspace/bsize;
760 stfsbuf.f_bfree = availspace/bsize;
761 stfsbuf.f_bavail = availspace/bsize;
762 #endif
763 stfsbuf.f_files = 1000000000+PKGVERSION+inodes;
764 stfsbuf.f_ffree = 1000000000+PKGVERSION;
765 stfsbuf.f_favail = 1000000000+PKGVERSION;
766 //stfsbuf.f_flag = ST_RDONLY;
767 #if FUSE_USE_VERSION >= 26
768 oplog_printf(&ctx,"statfs (%lu): OK (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu32")",(unsigned long int)ino,totalspace,availspace,trashspace,sustainedspace,inodes);
769 #else
770 oplog_printf(&ctx,"statfs (): OK (%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu32")",totalspace,availspace,trashspace,sustainedspace,inodes);
771 #endif
772 fuse_reply_statfs(req,&stfsbuf);
773 }
774
775 /*
776 static int mfs_node_access(uint8_t attr[32],uint32_t uid,uint32_t gid,int mask) {
777 uint32_t emode,mmode;
778 uint32_t attruid,attrgid;
779 uint16_t attrmode;
780 uint8_t *ptr;
781 if (uid == 0) {
782 return 1;
783 }
784 ptr = attr+2;
785 attrmode = get16bit(&ptr);
786 attruid = get32bit(&ptr);
787 attrgid = get32bit(&ptr);
788 if (uid == attruid) {
789 emode = (attrmode & 0700) >> 6;
790 } else if (gid == attrgid) {
791 emode = (attrmode & 0070) >> 3;
792 } else {
793 emode = attrmode & 0007;
794 }
795 mmode = 0;
796 if (mask & R_OK) {
797 mmode |= 4;
798 }
799 if (mask & W_OK) {
800 mmode |= 2;
801 }
802 if (mask & X_OK) {
803 mmode |= 1;
804 }
805 if ((emode & mmode) == mmode) {
806 return 1;
807 }
808 return 0;
809 }
810 */
811
812 // simple access test for deleted cwd nodes - no ACL's
813 int mfs_access_test(const uint8_t attr[35],int mmode,uint32_t uid,uint32_t gidcnt,uint32_t *gidtab) {
814 uint8_t modebits,gok;
815 uint16_t attrmode;
816 uint32_t attruid,attrgid;
817 const uint8_t *ptr;
818
819 if (uid==0) {
820 return 0;
821 }
822 ptr = attr+1;
823 attrmode = get16bit(&ptr);
824 attruid = get32bit(&ptr);
825 attrgid = get32bit(&ptr);
826
827 if (uid == attruid) {
828 modebits = (attrmode >> 6) & 7;
829 } else {
830 gok = 0;
831 while (gidcnt>0) {
832 gidcnt--;
833 if (gidtab[gidcnt] == attrgid) {
834 modebits = (attrmode >> 3) & 7;
835 gok = 1;
836 break;
837 }
838 }
839 if (gok==0) {
840 modebits = attrmode & 7;
841 }
842 }
843 if ((mmode & modebits) == mmode) {
844 return 0;
845 }
846 return EACCES;
847 }
848
849 void mfs_access(fuse_req_t req, fuse_ino_t ino, int mask) {
850 int status;
851 struct fuse_ctx ctx;
852 uint8_t attr[35];
853 groups *gids;
854 int mmode;
855 int force_mode;
856
857 ctx = *(fuse_req_ctx(req));
858 if (debug_mode) {
859 oplog_printf(&ctx,"access (%lu,0x%X) ...",(unsigned long int)ino,mask);
860 fprintf(stderr,"access (%lu,0x%X)\n",(unsigned long int)ino,mask);
861 }
862 mfs_stats_inc(OP_ACCESS);
863 #if (R_OK==MODE_MASK_R) && (W_OK==MODE_MASK_W) && (X_OK==MODE_MASK_X)
864 mmode = mask;
865 #else
866 mmode = 0;
867 if (mask & R_OK) {
868 mmode |= MODE_MASK_R;
869 }
870 if (mask & W_OK) {
871 mmode |= MODE_MASK_W;
872 }
873 if (mask & X_OK) {
874 mmode |= MODE_MASK_X;
875 }
876 #endif
877 if (IS_SPECIAL_INODE(ino)) {
878 if (mask & (W_OK | X_OK)) {
879 fuse_reply_err(req,EACCES);
880 } else {
881 fuse_reply_err(req,0);
882 }
883 return;
884 }
885
886 if (full_permissions) {
887 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
888 status = fs_access(ino,ctx.uid,gids->gidcnt,gids->gidtab,mmode);
889 groups_rel(gids);
890 } else {
891 uint32_t gidtmp = ctx.gid;
892 status = fs_access(ino,ctx.uid,1,&gidtmp,mmode);
893 }
894 force_mode = 0;
895 if (status==ERROR_ENOENT) {
896 if (ctx.pid == getpid()) {
897 force_mode = 1;
898 }
899 if (sstats_get(ino,attr,force_mode)==STATUS_OK) {
900 if (force_mode==0) {
901 force_mode = 2;
902 }
903 }
904 }
905 if (force_mode) {
906 if (force_mode == 1) {
907 if (debug_mode) {
908 fprintf(stderr,"special case: internal access (%lu,0x%X) - positive answer\n",(unsigned long int)ino,mask);
909 }
910 oplog_printf(&ctx,"special case: internal access (%lu,0x%X): OK",(unsigned long int)ino,mask);
911 status = 0;
912 } else {
913 if (debug_mode) {
914 fprintf(stderr,"special case: sustained access (%lu,0x%X) - using stored data\n",(unsigned long int)ino,mask);
915 }
916 if (full_permissions) {
917 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
918 status = mfs_access_test(attr,mmode,ctx.uid,gids->gidcnt,gids->gidtab);
919 groups_rel(gids);
920 } else {
921 uint32_t gidtmp = ctx.gid;
922 status = mfs_access_test(attr,mmode,ctx.uid,1,&gidtmp);
923 }
924 }
925 } else {
926 status = mfs_errorconv(status);
927 if (status!=0) {
928 oplog_printf(&ctx,"access (%lu,0x%X): %s",(unsigned long int)ino,mask,strerr(status));
929 } else {
930 oplog_printf(&ctx,"access (%lu,0x%X): OK",(unsigned long int)ino,mask);
931 }
932 }
933 fuse_reply_err(req,status);
934 }
935
936 void mfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
937 struct fuse_entry_param e;
938 uint64_t maxfleng;
939 uint32_t inode;
940 uint32_t nleng;
941 uint8_t attr[35];
942 char attrstr[256];
943 uint8_t mattr,type;
944 uint8_t icacheflag;
945 int status;
946 struct fuse_ctx ctx;
947 groups *gids;
948
949 ctx = *(fuse_req_ctx(req));
950 if (debug_mode) {
951 oplog_printf(&ctx,"lookup (%lu,%s) ...",(unsigned long int)parent,name);
952 fprintf(stderr,"lookup (%lu,%s)\n",(unsigned long int)parent,name);
953 }
954 nleng = strlen(name);
955 if (nleng>MFS_NAME_MAX) {
956 mfs_stats_inc(OP_ERRLOOKUP);
957 oplog_printf(&ctx,"lookup (%lu,%s): %s",(unsigned long int)parent,name,strerr(ENAMETOOLONG));
958 fuse_reply_err(req, ENAMETOOLONG);
959 return;
960 }
961 if (parent==FUSE_ROOT_ID) {
962 if (nleng==2 && name[0]=='.' && name[1]=='.') {
963 nleng=1;
964 }
965 if (strcmp(name,MASTERINFO_NAME)==0) {
966 memset(&e, 0, sizeof(e));
967 e.ino = MASTERINFO_INODE;
968 e.generation = 1;
969 e.attr_timeout = 3600.0;
970 e.entry_timeout = 3600.0;
971 mfs_attr_to_stat(MASTERINFO_INODE,masterinfoattr,&e.attr);
972 mfs_stats_inc(OP_LOOKUP_INTERNAL);
973 mfs_makeattrstr(attrstr,256,&e.attr);
974 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: MASTERINFO): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
975 fuse_reply_entry(req, &e);
976 return ;
977 }
978 if (strcmp(name,STATS_NAME)==0) {
979 memset(&e, 0, sizeof(e));
980 e.ino = STATS_INODE;
981 e.generation = 1;
982 e.attr_timeout = 3600.0;
983 e.entry_timeout = 3600.0;
984 mfs_attr_to_stat(STATS_INODE,statsattr,&e.attr);
985 mfs_stats_inc(OP_LOOKUP_INTERNAL);
986 mfs_makeattrstr(attrstr,256,&e.attr);
987 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: STATS): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
988 fuse_reply_entry(req, &e);
989 return ;
990 }
991 if (strcmp(name,MOOSE_NAME)==0) {
992 memset(&e, 0, sizeof(e));
993 e.ino = MOOSE_INODE;
994 e.generation = 1;
995 e.attr_timeout = 3600.0;
996 e.entry_timeout = 3600.0;
997 mfs_attr_to_stat(MOOSE_INODE,mooseattr,&e.attr);
998 mfs_stats_inc(OP_LOOKUP_INTERNAL);
999 mfs_makeattrstr(attrstr,256,&e.attr);
1000 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: MOOSE): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1001 fuse_reply_entry(req, &e);
1002 return ;
1003 }
1004 if (strcmp(name,OPLOG_NAME)==0) {
1005 memset(&e, 0, sizeof(e));
1006 e.ino = OPLOG_INODE;
1007 e.generation = 1;
1008 e.attr_timeout = 3600.0;
1009 e.entry_timeout = 3600.0;
1010 mfs_attr_to_stat(OPLOG_INODE,oplogattr,&e.attr);
1011 mfs_stats_inc(OP_LOOKUP_INTERNAL);
1012 mfs_makeattrstr(attrstr,256,&e.attr);
1013 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: OPLOG): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1014 fuse_reply_entry(req, &e);
1015 return ;
1016 }
1017 if (strcmp(name,OPHISTORY_NAME)==0) {
1018 memset(&e, 0, sizeof(e));
1019 e.ino = OPHISTORY_INODE;
1020 e.generation = 1;
1021 e.attr_timeout = 3600.0;
1022 e.entry_timeout = 3600.0;
1023 mfs_attr_to_stat(OPHISTORY_INODE,oplogattr,&e.attr);
1024 mfs_stats_inc(OP_LOOKUP_INTERNAL);
1025 mfs_makeattrstr(attrstr,256,&e.attr);
1026 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: OPHISTORY): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1027 fuse_reply_entry(req, &e);
1028 return ;
1029 }
1030 /*
1031 if (strcmp(name,ATTRCACHE_NAME)==0) {
1032 memset(&e, 0, sizeof(e));
1033 e.ino = ATTRCACHE_INODE;
1034 e.generation = 1;
1035 e.attr_timeout = 3600.0;
1036 e.entry_timeout = 3600.0;
1037 mfs_attr_to_stat(ATTRCACHE_INODE,attrcacheattr,&e.attr);
1038 mfs_stats_inc(OP_LOOKUP_INTERNAL);
1039 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: ATTRCACHE)",(unsigned long int)parent,name);
1040 fuse_reply_entry(req, &e);
1041 return ;
1042 }
1043 */
1044 }
1045 /*
1046 if (newdircache) {
1047 const uint8_t *dbuff;
1048 uint32_t dsize;
1049 switch (dir_cache_lookup(parent,nleng,(const uint8_t*)name,&inode,attr)) {
1050 case -1:
1051 mfs_stats_inc(OP_DIRCACHE_LOOKUP_NEGATIVE);
1052 oplog_printf(&ctx,"lookup (%lu,%s) (cached answer: %s)",(unsigned long int)parent,name,strerr(ENOENT));
1053 fuse_reply_err(req,ENOENT);
1054 return;
1055 case 1:
1056 mfs_stats_inc(OP_DIRCACHE_LOOKUP_POSITIVE);
1057 status = 0;
1058 oplog_printf(&ctx,"lookup (%lu,%s) (cached answer: %lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1059 break;
1060 case -2:
1061 mfs_stats_inc(OP_LOOKUP);
1062 status = fs_lookup(parent,nleng,(const uint8_t*)name,ctx.uid,ctx.gid,&inode,attr);
1063 status = mfs_errorconv(status);
1064 if (status!=0) {
1065 oplog_printf(&ctx,"lookup (%lu,%s) (lookup forced by cache: %s)",(unsigned long int)parent,name,strerr(status));
1066 } else {
1067 oplog_printf(&ctx,"lookup (%lu,%s) (lookup forced by cache: %lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1068 }
1069 break;
1070 case -3:
1071 mfs_stats_inc(OP_DIRCACHE_LOOKUP_NOATTR);
1072 status = fs_getattr(inode,ctx.uid,ctx.gid,attr);
1073 status = mfs_errorconv(status);
1074 if (status!=0) {
1075 oplog_printf(&ctx,"lookup (%lu,%s) (getattr forced by cache: %s)",(unsigned long int)parent,name,strerr(status));
1076 } else {
1077 oplog_printf(&ctx,"lookup (%lu,%s) (getattr forced by cache: %lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1078 }
1079 break;
1080 default:
1081 status = fs_getdir_plus(parent,ctx.uid,ctx.gid,1,&dbuff,&dsize);
1082 status = mfs_errorconv(status);
1083 if (status!=0) {
1084 oplog_printf(&ctx,"lookup (%lu,%s) (readdir: %s)",(unsigned long int)parent,name,strerr(status));
1085 fuse_reply_err(req, status);
1086 return;
1087 }
1088 mfs_stats_inc(OP_GETDIR_FULL);
1089 dir_cache_newdirdata(parent,dsize,dbuff);
1090 switch (dir_cache_lookup(parent,nleng,(const uint8_t*)name,&inode,attr)) {
1091 case -1:
1092 mfs_stats_inc(OP_DIRCACHE_LOOKUP_NEGATIVE);
1093 oplog_printf(&ctx,"lookup (%lu,%s) (after readdir cached answer: %s)",(unsigned long int)parent,name,strerr(ENOENT));
1094 fuse_reply_err(req,ENOENT);
1095 return;
1096 case 1:
1097 mfs_stats_inc(OP_DIRCACHE_LOOKUP_POSITIVE);
1098 oplog_printf(&ctx,"lookup (%lu,%s) (after readdir cached answer: %lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1099 break;
1100 default:
1101 mfs_stats_inc(OP_LOOKUP);
1102 status = fs_lookup(parent,nleng,(const uint8_t*)name,ctx.uid,ctx.gid,&inode,attr);
1103 status = mfs_errorconv(status);
1104 if (status!=0) {
1105 oplog_printf(&ctx,"lookup (%lu,%s) (after readdir lookup forced by cache: %s)",(unsigned long int)parent,name,strerr(status));
1106 } else {
1107 oplog_printf(&ctx,"lookup (%lu,%s) (after readdir lookup forced by cache: %lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1108 }
1109 }
1110 }
1111 } else
1112 */
1113 if (usedircache && dcache_lookup(&ctx,parent,nleng,(const uint8_t*)name,&inode,attr)) {
1114 if (debug_mode) {
1115 fprintf(stderr,"lookup: sending data from dircache\n");
1116 }
1117 mfs_stats_inc(OP_DIRCACHE_LOOKUP);
1118 status = 0;
1119 icacheflag = 1;
1120 // oplog_printf(&ctx,"lookup (%lu,%s) (using open dir cache): OK (%lu)",(unsigned long int)parent,name,(unsigned long int)inode);
1121 } else {
1122 if (negentry_cache_search(parent,nleng,(const uint8_t*)name)) {
1123 if (debug_mode) {
1124 fprintf(stderr,"lookup: sending data from negcache\n");
1125 }
1126 oplog_printf(&ctx,"lookup (%lu,%s) (using negative entry cache): %s",(unsigned long int)parent,name,strerr(ENOENT));
1127 mfs_stats_inc(OP_NEGCACHE_LOOKUP);
1128 fuse_reply_err(req,ENOENT);
1129 return;
1130 }
1131 if (full_permissions) {
1132 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1133 status = fs_lookup(parent,nleng,(const uint8_t*)name,ctx.uid,gids->gidcnt,gids->gidtab,&inode,attr);
1134 groups_rel(gids);
1135 } else {
1136 uint32_t gidtmp = ctx.gid;
1137 status = fs_lookup(parent,nleng,(const uint8_t*)name,ctx.uid,1,&gidtmp,&inode,attr);
1138 }
1139 status = mfs_errorconv(status);
1140 icacheflag = 0;
1141 if (status==0) {
1142 mfs_stats_inc(OP_POSLOOKUP);
1143 } else if (status==ENOENT) {
1144 if (strcmp(name,MASTERINFO_NAME)==0) {
1145 memset(&e, 0, sizeof(e));
1146 e.ino = MASTERINFO_INODE;
1147 e.generation = 1;
1148 e.attr_timeout = 3600.0;
1149 e.entry_timeout = 3600.0;
1150 mfs_attr_to_stat(MASTERINFO_INODE,masterinfoattr,&e.attr);
1151 mfs_stats_inc(OP_LOOKUP_INTERNAL);
1152 mfs_makeattrstr(attrstr,256,&e.attr);
1153 oplog_printf(&ctx,"lookup (%lu,%s) (internal node: MASTERINFO): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1154 fuse_reply_entry(req, &e);
1155 return ;
1156 } else {
1157 mfs_stats_inc(OP_NEGLOOKUP);
1158 negentry_cache_insert(parent,nleng,(const uint8_t*)name);
1159 }
1160 } else {
1161 mfs_stats_inc(OP_ERRLOOKUP);
1162 }
1163 }
1164 if (status!=0) {
1165 oplog_printf(&ctx,"lookup (%lu,%s): %s",(unsigned long int)parent,name,strerr(status));
1166 fuse_reply_err(req, status);
1167 return;
1168 }
1169 type = mfs_attr_get_type(attr);
1170 if (type==TYPE_FILE) {
1171 maxfleng = write_data_getmaxfleng(inode);
1172 } else {
1173 maxfleng = 0;
1174 }
1175 if (type==TYPE_DIRECTORY) {
1176 sstats_set(inode,attr,1);
1177 }
1178 memset(&e, 0, sizeof(e));
1179 e.ino = inode;
1180 e.generation = 1;
1181 mattr = mfs_attr_get_mattr(attr);
1182 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
1183 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:((type==TYPE_DIRECTORY)?direntry_cache_timeout:entry_cache_timeout);
1184 mfs_attr_to_stat(inode,attr,&e.attr);
1185 if (maxfleng>(uint64_t)(e.attr.st_size)) {
1186 e.attr.st_size=maxfleng;
1187 }
1188 if (mfs_attr_get_type(attr)==TYPE_FILE) {
1189 read_inode_set_length(inode,e.attr.st_size,0);
1190 }
1191 // if (type==TYPE_FILE && debug_mode) {
1192 // fprintf(stderr,"lookup inode %lu - file size: %llu\n",(unsigned long int)inode,(unsigned long long int)e.attr.st_size);
1193 // }
1194 mfs_makeattrstr(attrstr,256,&e.attr);
1195 oplog_printf(&ctx,"lookup (%lu,%s)%s: OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,icacheflag?" (using open dir cache)":"",e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1196 fuse_reply_entry(req, &e);
1197 if (debug_mode) {
1198 fprintf(stderr,"lookup: positive answer timeouts (attr:%.3lf,entry:%.3lf)\n",e.attr_timeout,e.entry_timeout);
1199 }
1200 }
1201
1202 void mfs_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
1203 uint64_t maxfleng;
1204 double attr_timeout;
1205 struct stat o_stbuf;
1206 uint8_t attr[35];
1207 uint8_t type;
1208 char attrstr[256];
1209 int status;
1210 uint8_t icacheflag;
1211 struct fuse_ctx ctx;
1212 int force_mode;
1213 (void)fi;
1214
1215 ctx = *(fuse_req_ctx(req));
1216 // mfs_stats_inc(OP_GETATTR);
1217 if (debug_mode) {
1218 oplog_printf(&ctx,"getattr (%lu) ...",(unsigned long int)ino);
1219 fprintf(stderr,"getattr (%lu)\n",(unsigned long int)ino);
1220 }
1221 // if (ino==MASTER_INODE) {
1222 // memset(&o_stbuf, 0, sizeof(struct stat));
1223 // mfs_attr_to_stat(ino,masterattr,&o_stbuf);
1224 // fuse_reply_attr(req, &o_stbuf, 3600.0);
1225 // mfs_stats_inc(OP_GETATTR);
1226 // return;
1227 // }
1228 if (ino==MASTERINFO_INODE) {
1229 memset(&o_stbuf, 0, sizeof(struct stat));
1230 mfs_attr_to_stat(ino,masterinfoattr,&o_stbuf);
1231 mfs_stats_inc(OP_GETATTR);
1232 mfs_makeattrstr(attrstr,256,&o_stbuf);
1233 oplog_printf(&ctx,"getattr (%lu) (internal node: MASTERINFO): OK (3600,%s)",(unsigned long int)ino,attrstr);
1234 fuse_reply_attr(req, &o_stbuf, 3600.0);
1235 return;
1236 }
1237 if (ino==STATS_INODE) {
1238 memset(&o_stbuf, 0, sizeof(struct stat));
1239 mfs_attr_to_stat(ino,statsattr,&o_stbuf);
1240 mfs_stats_inc(OP_GETATTR);
1241 mfs_makeattrstr(attrstr,256,&o_stbuf);
1242 oplog_printf(&ctx,"getattr (%lu) (internal node: STATS): OK (3600,%s)",(unsigned long int)ino,attrstr);
1243 fuse_reply_attr(req, &o_stbuf, 3600.0);
1244 return;
1245 }
1246 if (ino==MOOSE_INODE) {
1247 memset(&o_stbuf, 0, sizeof(struct stat));
1248 mfs_attr_to_stat(ino,mooseattr,&o_stbuf);
1249 mfs_stats_inc(OP_GETATTR);
1250 mfs_makeattrstr(attrstr,256,&o_stbuf);
1251 oplog_printf(&ctx,"getattr (%lu) (internal node: MOOSE): OK (3600,%s)",(unsigned long int)ino,attrstr);
1252 fuse_reply_attr(req, &o_stbuf, 3600.0);
1253 return;
1254 }
1255 if (ino==OPLOG_INODE || ino==OPHISTORY_INODE) {
1256 memset(&o_stbuf, 0, sizeof(struct stat));
1257 mfs_attr_to_stat(ino,oplogattr,&o_stbuf);
1258 // if (fi && fi->fh) {
1259 // uint64_t *posptr = (uint64_t*)(unsigned long)(fi->fh);
1260 // o_stbuf.st_size = (*posptr)+oplog_getpos();
1261 // }
1262 mfs_stats_inc(OP_GETATTR);
1263 mfs_makeattrstr(attrstr,256,&o_stbuf);
1264 oplog_printf(&ctx,"getattr (%lu) (internal node: %s): OK (3600,%s)",(unsigned long int)ino,(ino==OPLOG_INODE)?"OPLOG":"OPHISTORY",attrstr);
1265 fuse_reply_attr(req, &o_stbuf, 3600.0);
1266 return;
1267 }
1268 /*
1269 if (ino==ATTRCACHE_INODE) {
1270 memset(&o_stbuf, 0, sizeof(struct stat));
1271 mfs_attr_to_stat(ino,attrcacheattr,&o_stbuf);
1272 mfs_stats_inc(OP_GETATTR);
1273 oplog_printf(&ctx,"getattr (%lu) (internal node ATTRCACHE)",(unsigned long int)ino);
1274 fuse_reply_attr(req, &o_stbuf, 3600.0);
1275 return;
1276 }
1277 */
1278 // if (write_data_flush_inode(ino)) {
1279 // mfs_stats_inc(OP_GETATTR);
1280 // status = fs_getattr(ino,ctx.uid,ctx.gid,attr);
1281 // status = mfs_errorconv(status);
1282 /*
1283 if (newdircache) {
1284 if (dir_cache_getattr(ino,attr)) {
1285 mfs_stats_inc(OP_DIRCACHE_GETATTR);
1286 status = 0;
1287 oplog_printf(&ctx,"getattr (%lu) (data found in cache)",(unsigned long int)ino);
1288 } else {
1289 mfs_stats_inc(OP_GETATTR);
1290 status = fs_getattr(ino,ctx.uid,ctx.gid,attr);
1291 status = mfs_errorconv(status);
1292 if (status!=0) {
1293 oplog_printf(&ctx,"getattr (%lu) (data not found in cache: %s)",(unsigned long int)ino,strerr(status));
1294 } else {
1295 oplog_printf(&ctx,"getattr (%lu) (data not found in cache)",(unsigned long int)ino);
1296 }
1297 }
1298 } else
1299 */
1300 force_mode = 0;
1301 if (usedircache && dcache_getattr(&ctx,ino,attr)) {
1302 if (debug_mode) {
1303 fprintf(stderr,"getattr: sending data from dircache\n");
1304 }
1305 mfs_stats_inc(OP_DIRCACHE_GETATTR);
1306 status = 0;
1307 icacheflag = 1;
1308 } else {
1309 mfs_stats_inc(OP_GETATTR);
1310 status = fs_getattr(ino,(fi!=NULL)?1:0,ctx.uid,ctx.gid,attr);
1311 if (status==ERROR_ENOENT) {
1312 if (ctx.pid==getpid()) {
1313 force_mode = 1;
1314 }
1315 status = sstats_get(ino,attr,force_mode);
1316 if (status==STATUS_OK && force_mode==0) {
1317 force_mode = 2;
1318 }
1319 }
1320 status = mfs_errorconv(status);
1321 icacheflag = 0;
1322 }
1323 if (status!=0) {
1324 oplog_printf(&ctx,"getattr (%lu): %s",(unsigned long int)ino,strerr(status));
1325 fuse_reply_err(req, status);
1326 return;
1327 }
1328 type = mfs_attr_get_type(attr);
1329 if (type==TYPE_FILE) {
1330 maxfleng = write_data_getmaxfleng(ino);
1331 } else {
1332 maxfleng = 0;
1333 }
1334 if (type==TYPE_DIRECTORY && force_mode==0) {
1335 sstats_set(ino,attr,1);
1336 }
1337 memset(&o_stbuf, 0, sizeof(struct stat));
1338 mfs_attr_to_stat(ino,attr,&o_stbuf);
1339 if (maxfleng>(uint64_t)(o_stbuf.st_size)) {
1340 o_stbuf.st_size=maxfleng;
1341 }
1342 if (type==TYPE_FILE) {
1343 read_inode_set_length(ino,o_stbuf.st_size,0);
1344 }
1345 attr_timeout = ((mfs_attr_get_mattr(attr)&MATTR_NOACACHE) || force_mode)?0.0:attr_cache_timeout;
1346 mfs_makeattrstr(attrstr,256,&o_stbuf);
1347 oplog_printf(&ctx,"getattr (%lu)%s: OK (%.1lf,%s)",(unsigned long int)ino,icacheflag?" (using open dir cache)":(force_mode==1)?" (internal getattr)":(force_mode==2)?" (sustained nodes)":"",attr_timeout,attrstr);
1348 fuse_reply_attr(req, &o_stbuf, attr_timeout);
1349 }
1350
1351 void mfs_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *stbuf, int to_set, struct fuse_file_info *fi) {
1352 struct stat o_stbuf;
1353 uint64_t maxfleng;
1354 uint8_t attr[35];
1355 char modestr[11];
1356 char attrstr[256];
1357 double attr_timeout;
1358 int status;
1359 struct fuse_ctx ctx;
1360 groups *gids;
1361 uint8_t setmask = 0;
1362
1363 ctx = *(fuse_req_ctx(req));
1364 mfs_makemodestr(modestr,stbuf->st_mode);
1365 mfs_stats_inc(OP_SETATTR);
1366 if (debug_mode) {
1367 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]) ...",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size));
1368 fprintf(stderr,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu])\n",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size));
1369 }
1370 if (ino==MASTERINFO_INODE) {
1371 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(EPERM));
1372 fuse_reply_err(req, EPERM);
1373 return;
1374 }
1375 if (ino==STATS_INODE) {
1376 memset(&o_stbuf, 0, sizeof(struct stat));
1377 mfs_attr_to_stat(ino,statsattr,&o_stbuf);
1378 mfs_makeattrstr(attrstr,256,&o_stbuf);
1379 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]) (internal node: STATS): OK (3600,%s)",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),attrstr);
1380 fuse_reply_attr(req, &o_stbuf, 3600.0);
1381 return;
1382 }
1383 if (ino==MOOSE_INODE) {
1384 memset(&o_stbuf, 0, sizeof(struct stat));
1385 mfs_attr_to_stat(ino,mooseattr,&o_stbuf);
1386 mfs_makeattrstr(attrstr,256,&o_stbuf);
1387 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]) (internal node: MOOSE): OK (3600,%s)",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),attrstr);
1388 fuse_reply_attr(req, &o_stbuf, 3600.0);
1389 return;
1390 }
1391 if (ino==OPLOG_INODE || ino==OPHISTORY_INODE) {
1392 memset(&o_stbuf, 0, sizeof(struct stat));
1393 mfs_attr_to_stat(ino,oplogattr,&o_stbuf);
1394 // if (fi && fi->fh) {
1395 // uint64_t *posptr = (uint64_t*)(unsigned long)(fi->fh);
1396 // o_stbuf.st_size = (*posptr)+oplog_getpos();
1397 // }
1398 mfs_makeattrstr(attrstr,256,&o_stbuf);
1399 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]) (internal node: %s): OK (3600,%s)",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),(ino==OPLOG_INODE)?"OPLOG":"OPHISTORY",attrstr);
1400 fuse_reply_attr(req, &o_stbuf, 3600.0);
1401 return;
1402 }
1403 /*
1404 if (ino==ATTRCACHE_INODE) {
1405 memset(&o_stbuf, 0, sizeof(struct stat));
1406 mfs_attr_to_stat(ino,attrcacheattr,&o_stbuf);
1407 fuse_reply_attr(req, &o_stbuf, 3600.0);
1408 return;
1409 }
1410 */
1411 status = EINVAL;
1412 if ((to_set & (FUSE_SET_ATTR_MODE|FUSE_SET_ATTR_UID|FUSE_SET_ATTR_GID|FUSE_SET_ATTR_ATIME|FUSE_SET_ATTR_MTIME|FUSE_SET_ATTR_SIZE)) == 0) { // change other flags or change nothing
1413 // status = fs_getattr(ino,ctx.uid,ctx.gid,attr);
1414 // ext3 compatibility - change ctime during this operation (usually chown(-1,-1))
1415 if (full_permissions) {
1416 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1417 status = fs_setattr(ino,(fi!=NULL)?1:0,ctx.uid,gids->gidcnt,gids->gidtab,0,0,0,0,0,0,0,attr);
1418 groups_rel(gids);
1419 } else {
1420 uint32_t gidtmp = ctx.gid;
1421 status = fs_setattr(ino,(fi!=NULL)?1:0,ctx.uid,1,&gidtmp,0,0,0,0,0,0,0,attr);
1422 }
1423 if (status==ERROR_ENOENT) {
1424 status = sstats_get(ino,attr,0);
1425 if (status==STATUS_OK) {
1426 mfs_attr_modify(to_set,attr,stbuf);
1427 }
1428 }
1429 if (status==STATUS_OK) {
1430 sstats_set(ino,attr,0);
1431 }
1432 status = mfs_errorconv(status);
1433 if (status!=0) {
1434 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(status));
1435 fuse_reply_err(req, status);
1436 return;
1437 }
1438 }
1439 if (to_set & (FUSE_SET_ATTR_MODE|FUSE_SET_ATTR_UID|FUSE_SET_ATTR_GID|FUSE_SET_ATTR_ATIME|FUSE_SET_ATTR_MTIME)) {
1440 setmask = 0;
1441 if (to_set & FUSE_SET_ATTR_MODE) {
1442 setmask |= SET_MODE_FLAG;
1443 if (xattr_cache_on) {
1444 xattr_cache_del(ino,6+1+5+1+3+1+6,(const uint8_t*)"system.posix_acl_access");
1445 }
1446 }
1447 if (to_set & FUSE_SET_ATTR_UID) {
1448 setmask |= SET_UID_FLAG;
1449 }
1450 if (to_set & FUSE_SET_ATTR_GID) {
1451 setmask |= SET_GID_FLAG;
1452 }
1453 if (to_set & FUSE_SET_ATTR_ATIME) {
1454 setmask |= SET_ATIME_FLAG;
1455 }
1456 if (to_set & FUSE_SET_ATTR_MTIME) {
1457 setmask |= SET_MTIME_FLAG;
1458 write_data_flush_inode(ino); // in this case we want flush all pending writes because they could overwrite mtime
1459 }
1460 if (full_permissions) {
1461 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1462 status = fs_setattr(ino,(fi!=NULL)?1:0,ctx.uid,gids->gidcnt,gids->gidtab,setmask,stbuf->st_mode&07777,stbuf->st_uid,stbuf->st_gid,stbuf->st_atime,stbuf->st_mtime,sugid_clear_mode,attr);
1463 groups_rel(gids);
1464 } else {
1465 uint32_t gidtmp = ctx.gid;
1466 status = fs_setattr(ino,(fi!=NULL)?1:0,ctx.uid,1,&gidtmp,setmask,stbuf->st_mode&07777,stbuf->st_uid,stbuf->st_gid,stbuf->st_atime,stbuf->st_mtime,sugid_clear_mode,attr);
1467 }
1468 if (status==ERROR_ENOENT) {
1469 status = sstats_get(ino,attr,0);
1470 if (status==STATUS_OK) {
1471 mfs_attr_modify(to_set,attr,stbuf);
1472 }
1473 }
1474 if (status==STATUS_OK) {
1475 sstats_set(ino,attr,0);
1476 }
1477 status = mfs_errorconv(status);
1478 if (status!=0) {
1479 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(status));
1480 fuse_reply_err(req, status);
1481 return;
1482 }
1483 }
1484 if (to_set & FUSE_SET_ATTR_SIZE) {
1485 if (stbuf->st_size<0) {
1486 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(EINVAL));
1487 fuse_reply_err(req, EINVAL);
1488 return;
1489 }
1490 if (stbuf->st_size>=MAX_FILE_SIZE) {
1491 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(EFBIG));
1492 fuse_reply_err(req, EFBIG);
1493 return;
1494 }
1495 write_data_flush_inode(ino);
1496 if (full_permissions) {
1497 uint32_t trycnt;
1498 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1499 trycnt = 0;
1500 while (1) {
1501 #ifdef FREEBSD_FALSE_TRUNCATE_WORKAROUND
1502 status = fs_truncate(ino,(fi!=NULL)?(TRUNCATE_FLAG_OPENED|TRUNCATE_FLAG_TIMEFIX):TRUNCATE_FLAG_TIMEFIX,ctx.uid,gids->gidcnt,gids->gidtab,stbuf->st_size,attr);
1503 #else
1504 status = fs_truncate(ino,(fi!=NULL)?TRUNCATE_FLAG_OPENED:0,ctx.uid,gids->gidcnt,gids->gidtab,stbuf->st_size,attr);
1505 #endif
1506 if (status==STATUS_OK || status==ERROR_EROFS || status==ERROR_EACCES || status==ERROR_EPERM || status==ERROR_ENOENT || status==ERROR_QUOTA || status==ERROR_NOSPACE || status==ERROR_CHUNKLOST) {
1507 break;
1508 } else if (status!=ERROR_LOCKED) {
1509 trycnt++;
1510 if (trycnt>=30) {
1511 break;
1512 }
1513 }
1514 sleep(1+((trycnt<30)?(trycnt/3):10));
1515 }
1516 groups_rel(gids);
1517 } else {
1518 uint32_t gidtmp = ctx.gid;
1519 uint32_t trycnt;
1520 trycnt = 0;
1521 while (1) {
1522 #ifdef FREEBSD_FALSE_TRUNCATE_WORKAROUND
1523 status = fs_truncate(ino,(fi!=NULL)?(TRUNCATE_FLAG_OPENED|TRUNCATE_FLAG_TIMEFIX):TRUNCATE_FLAG_TIMEFIX,ctx.uid,1,&gidtmp,stbuf->st_size,attr);
1524 #else
1525 status = fs_truncate(ino,(fi!=NULL)?TRUNCATE_FLAG_OPENED:0,ctx.uid,1,&gidtmp,stbuf->st_size,attr);
1526 #endif
1527 if (status==STATUS_OK || status==ERROR_EROFS || status==ERROR_EACCES || status==ERROR_EPERM || status==ERROR_ENOENT || status==ERROR_QUOTA || status==ERROR_NOSPACE || status==ERROR_CHUNKLOST) {
1528 break;
1529 } else if (status!=ERROR_LOCKED) {
1530 trycnt++;
1531 if (trycnt>=30) {
1532 break;
1533 }
1534 }
1535 sleep(1+((trycnt<30)?(trycnt/3):10));
1536 }
1537 }
1538 status = mfs_errorconv(status);
1539 // read_inode_ops(ino);
1540 write_data_setmaxfleng(ino,stbuf->st_size);
1541 read_inode_set_length(ino,stbuf->st_size,1);
1542 if (status!=0) {
1543 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(status));
1544 fuse_reply_err(req, status);
1545 return;
1546 }
1547 }
1548 if (status!=0) { // should never happened but better check than sorry
1549 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): %s",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),strerr(status));
1550 fuse_reply_err(req, status);
1551 return;
1552 }
1553 dcache_setattr(ino,attr);
1554 if (mfs_attr_get_type(attr)==TYPE_FILE) {
1555 maxfleng = write_data_getmaxfleng(ino);
1556 } else {
1557 maxfleng = 0;
1558 }
1559 memset(&o_stbuf, 0, sizeof(struct stat));
1560 mfs_attr_to_stat(ino,attr,&o_stbuf);
1561 if (maxfleng>(uint64_t)(o_stbuf.st_size)) {
1562 o_stbuf.st_size=maxfleng;
1563 }
1564 attr_timeout = (mfs_attr_get_mattr(attr)&MATTR_NOACACHE)?0.0:attr_cache_timeout;
1565 mfs_makeattrstr(attrstr,256,&o_stbuf);
1566 oplog_printf(&ctx,"setattr (%lu,0x%X,[%s:0%04o,%ld,%ld,%lu,%lu,%llu]): OK (%.1lf,%s)",(unsigned long int)ino,to_set,modestr+1,(unsigned int)(stbuf->st_mode & 07777),(long int)stbuf->st_uid,(long int)stbuf->st_gid,(unsigned long int)(stbuf->st_atime),(unsigned long int)(stbuf->st_mtime),(unsigned long long int)(stbuf->st_size),attr_timeout,attrstr);
1567 fuse_reply_attr(req, &o_stbuf, attr_timeout);
1568 }
1569
1570 void mfs_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) {
1571 struct fuse_entry_param e;
1572 uint32_t inode;
1573 uint8_t attr[35];
1574 char modestr[11];
1575 char attrstr[256];
1576 uint8_t mattr;
1577 uint32_t nleng;
1578 uint16_t cumask;
1579 int status;
1580 uint8_t type;
1581 struct fuse_ctx ctx;
1582 groups *gids;
1583
1584 ctx = *(fuse_req_ctx(req));
1585 mfs_makemodestr(modestr,mode);
1586 mfs_stats_inc(OP_MKNOD);
1587 if (debug_mode) {
1588 #ifdef FUSE_CAP_DONT_MASK
1589 char umaskstr[11];
1590 mfs_makemodestr(umaskstr,ctx.umask);
1591 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o/%s:0%04o,0x%08lX) ...",(unsigned long int)parent,name,modestr,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask),(unsigned long int)rdev);
1592 fprintf(stderr,"mknod (%lu,%s,%s:0%04o/%s:0%04o,0x%08lX)\n",(unsigned long int)parent,name,modestr,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask),(unsigned long int)rdev);
1593 #else
1594 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX) ...",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev);
1595 fprintf(stderr,"mknod (%lu,%s,%s:0%04o,0x%08lX)\n",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev);
1596 #endif
1597 }
1598 nleng = strlen(name);
1599 if (nleng>MFS_NAME_MAX) {
1600 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX): %s",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev,strerr(ENAMETOOLONG));
1601 fuse_reply_err(req, ENAMETOOLONG);
1602 return;
1603 }
1604 if (S_ISFIFO(mode)) {
1605 type = TYPE_FIFO;
1606 } else if (S_ISCHR(mode)) {
1607 type = TYPE_CHARDEV;
1608 } else if (S_ISBLK(mode)) {
1609 type = TYPE_BLOCKDEV;
1610 } else if (S_ISSOCK(mode)) {
1611 type = TYPE_SOCKET;
1612 } else if (S_ISREG(mode) || (mode&0170000)==0) {
1613 type = TYPE_FILE;
1614 } else {
1615 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX): %s",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev,strerr(EPERM));
1616 fuse_reply_err(req, EPERM);
1617 return;
1618 }
1619
1620 if (parent==FUSE_ROOT_ID) {
1621 if (IS_SPECIAL_NAME(name)) {
1622 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX): %s",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev,strerr(EACCES));
1623 fuse_reply_err(req, EACCES);
1624 return;
1625 }
1626 }
1627
1628 #ifdef FUSE_CAP_DONT_MASK
1629 cumask = ctx.umask;
1630 #else
1631 cumask = 0;
1632 #endif
1633 if (full_permissions) {
1634 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1635 status = fs_mknod(parent,nleng,(const uint8_t*)name,type,mode&07777,cumask,ctx.uid,gids->gidcnt,gids->gidtab,rdev,&inode,attr);
1636 groups_rel(gids);
1637 } else {
1638 uint32_t gidtmp = ctx.gid;
1639 status = fs_mknod(parent,nleng,(const uint8_t*)name,type,mode&07777,cumask,ctx.uid,1,&gidtmp,rdev,&inode,attr);
1640 }
1641 status = mfs_errorconv(status);
1642 if (status!=0) {
1643 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX): %s",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev,strerr(status));
1644 fuse_reply_err(req, status);
1645 } else {
1646 negentry_cache_remove(parent,nleng,(const uint8_t*)name);
1647 // if (newdircache) {
1648 // dir_cache_link(parent,nleng,(const uint8_t*)name,inode,attr);
1649 // }
1650 dcache_invalidate_attr(parent);
1651 memset(&e, 0, sizeof(e));
1652 e.ino = inode;
1653 e.generation = 1;
1654 mattr = mfs_attr_get_mattr(attr);
1655 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
1656 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:entry_cache_timeout;
1657 mfs_attr_to_stat(inode,attr,&e.attr);
1658 mfs_makeattrstr(attrstr,256,&e.attr);
1659 oplog_printf(&ctx,"mknod (%lu,%s,%s:0%04o,0x%08lX): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,modestr,(unsigned int)mode,(unsigned long int)rdev,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1660 fuse_reply_entry(req, &e);
1661 }
1662 }
1663
1664 void mfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) {
1665 uint32_t nleng;
1666 int status;
1667 struct fuse_ctx ctx;
1668 groups *gids;
1669
1670 ctx = *(fuse_req_ctx(req));
1671 mfs_stats_inc(OP_UNLINK);
1672 if (debug_mode) {
1673 oplog_printf(&ctx,"unlink (%lu,%s) ...",(unsigned long int)parent,name);
1674 fprintf(stderr,"unlink (%lu,%s)\n",(unsigned long int)parent,name);
1675 }
1676 if (parent==FUSE_ROOT_ID) {
1677 if (IS_SPECIAL_NAME(name)) {
1678 oplog_printf(&ctx,"unlink (%lu,%s): %s",(unsigned long int)parent,name,strerr(EACCES));
1679 fuse_reply_err(req, EACCES);
1680 return;
1681 }
1682 }
1683
1684 nleng = strlen(name);
1685 if (nleng>MFS_NAME_MAX) {
1686 oplog_printf(&ctx,"unlink (%lu,%s): %s",(unsigned long int)parent,name,strerr(ENAMETOOLONG));
1687 fuse_reply_err(req, ENAMETOOLONG);
1688 return;
1689 }
1690
1691 if (full_permissions) {
1692 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1693 status = fs_unlink(parent,nleng,(const uint8_t*)name,ctx.uid,gids->gidcnt,gids->gidtab);
1694 groups_rel(gids);
1695 } else {
1696 uint32_t gidtmp = ctx.gid;
1697 status = fs_unlink(parent,nleng,(const uint8_t*)name,ctx.uid,1,&gidtmp);
1698 }
1699 status = mfs_errorconv(status);
1700 if (status!=0) {
1701 oplog_printf(&ctx,"unlink (%lu,%s): %s",(unsigned long int)parent,name,strerr(status));
1702 fuse_reply_err(req, status);
1703 } else {
1704 negentry_cache_insert(parent,nleng,(const uint8_t*)name);
1705 // if (newdircache) {
1706 // dir_cache_unlink(parent,nleng,(const uint8_t*)name);
1707 // }
1708 dcache_invalidate_attr(parent);
1709 dcache_invalidate_name(&ctx,parent,nleng,(const uint8_t*)name);
1710 oplog_printf(&ctx,"unlink (%lu,%s): OK",(unsigned long int)parent,name);
1711 fuse_reply_err(req, 0);
1712 }
1713 }
1714
1715 void mfs_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) {
1716 struct fuse_entry_param e;
1717 uint32_t inode;
1718 uint8_t attr[35];
1719 char modestr[11];
1720 char attrstr[256];
1721 uint8_t mattr;
1722 uint32_t nleng;
1723 uint16_t cumask;
1724 int status;
1725 struct fuse_ctx ctx;
1726 groups *gids;
1727
1728 ctx = *(fuse_req_ctx(req));
1729 mfs_makemodestr(modestr,mode);
1730 mfs_stats_inc(OP_MKDIR);
1731 if (debug_mode) {
1732 #ifdef FUSE_CAP_DONT_MASK
1733 char umaskstr[11];
1734 mfs_makemodestr(umaskstr,ctx.umask);
1735 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o/%s:0%04o) ...",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask));
1736 fprintf(stderr,"mkdir (%lu,%s,d%s:0%04o/%s:0%04o)\n",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask));
1737 #else
1738 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o) ...",(unsigned long int)parent,name,modestr+1,(unsigned int)mode);
1739 fprintf(stderr,"mkdir (%lu,%s,d%s:0%04o)\n",(unsigned long int)parent,name,modestr+1,(unsigned int)mode);
1740 #endif
1741 }
1742 if (parent==FUSE_ROOT_ID) {
1743 if (IS_SPECIAL_NAME(name)) {
1744 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(EACCES));
1745 fuse_reply_err(req, EACCES);
1746 return;
1747 }
1748 }
1749 nleng = strlen(name);
1750 if (nleng>MFS_NAME_MAX) {
1751 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(ENAMETOOLONG));
1752 fuse_reply_err(req, ENAMETOOLONG);
1753 return;
1754 }
1755
1756 #ifdef FUSE_CAP_DONT_MASK
1757 cumask = ctx.umask;
1758 #else
1759 cumask = 0;
1760 #endif
1761 if (full_permissions) {
1762 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1763 status = fs_mkdir(parent,nleng,(const uint8_t*)name,mode,cumask,ctx.uid,gids->gidcnt,gids->gidtab,mkdir_copy_sgid,&inode,attr);
1764 groups_rel(gids);
1765 } else {
1766 uint32_t gidtmp = ctx.gid;
1767 status = fs_mkdir(parent,nleng,(const uint8_t*)name,mode,cumask,ctx.uid,1,&gidtmp,mkdir_copy_sgid,&inode,attr);
1768 }
1769 status = mfs_errorconv(status);
1770 if (status!=0) {
1771 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(status));
1772 fuse_reply_err(req, status);
1773 } else {
1774 sstats_set(inode,attr,1);
1775 negentry_cache_remove(parent,nleng,(const uint8_t*)name);
1776 // if (newdircache) {
1777 // dir_cache_link(parent,nleng,(const uint8_t*)name,inode,attr);
1778 // }
1779 dcache_invalidate_attr(parent);
1780 memset(&e, 0, sizeof(e));
1781 e.ino = inode;
1782 e.generation = 1;
1783 mattr = mfs_attr_get_mattr(attr);
1784 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
1785 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:direntry_cache_timeout;
1786 mfs_attr_to_stat(inode,attr,&e.attr);
1787 mfs_makeattrstr(attrstr,256,&e.attr);
1788 oplog_printf(&ctx,"mkdir (%lu,%s,d%s:0%04o): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1789 fuse_reply_entry(req, &e);
1790 }
1791 }
1792
1793 void mfs_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) {
1794 uint32_t nleng;
1795 int status;
1796 struct fuse_ctx ctx;
1797 groups *gids;
1798
1799 ctx = *(fuse_req_ctx(req));
1800 mfs_stats_inc(OP_RMDIR);
1801 if (debug_mode) {
1802 oplog_printf(&ctx,"rmdir (%lu,%s) ...",(unsigned long int)parent,name);
1803 fprintf(stderr,"rmdir (%lu,%s)\n",(unsigned long int)parent,name);
1804 }
1805 if (parent==FUSE_ROOT_ID) {
1806 if (IS_SPECIAL_NAME(name)) {
1807 oplog_printf(&ctx,"rmdir (%lu,%s): %s",(unsigned long int)parent,name,strerr(EACCES));
1808 fuse_reply_err(req, EACCES);
1809 return;
1810 }
1811 }
1812 nleng = strlen(name);
1813 if (nleng>MFS_NAME_MAX) {
1814 oplog_printf(&ctx,"rmdir (%lu,%s): %s",(unsigned long int)parent,name,strerr(ENAMETOOLONG));
1815 fuse_reply_err(req, ENAMETOOLONG);
1816 return;
1817 }
1818
1819 if (full_permissions) {
1820 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1821 status = fs_rmdir(parent,nleng,(const uint8_t*)name,ctx.uid,gids->gidcnt,gids->gidtab);
1822 groups_rel(gids);
1823 } else {
1824 uint32_t gidtmp = ctx.gid;
1825 status = fs_rmdir(parent,nleng,(const uint8_t*)name,ctx.uid,1,&gidtmp);
1826 }
1827 status = mfs_errorconv(status);
1828 if (status!=0) {
1829 oplog_printf(&ctx,"rmdir (%lu,%s): %s",(unsigned long int)parent,name,strerr(status));
1830 fuse_reply_err(req, status);
1831 } else {
1832 negentry_cache_insert(parent,nleng,(const uint8_t*)name);
1833 // if (newdircache) {
1834 // dir_cache_unlink(parent,nleng,(const uint8_t*)name);
1835 // }
1836 dcache_invalidate_attr(parent);
1837 dcache_invalidate_name(&ctx,parent,nleng,(const uint8_t*)name);
1838 oplog_printf(&ctx,"rmdir (%lu,%s): OK",(unsigned long int)parent,name);
1839 fuse_reply_err(req, 0);
1840 }
1841 }
1842
1843 void mfs_symlink(fuse_req_t req, const char *path, fuse_ino_t parent, const char *name) {
1844 struct fuse_entry_param e;
1845 uint32_t inode;
1846 uint8_t attr[35];
1847 char attrstr[256];
1848 uint8_t mattr;
1849 uint32_t nleng;
1850 int status;
1851 struct fuse_ctx ctx;
1852 groups *gids;
1853
1854 ctx = *(fuse_req_ctx(req));
1855 mfs_stats_inc(OP_SYMLINK);
1856 if (debug_mode) {
1857 oplog_printf(&ctx,"symlink (%s,%lu,%s) ...",path,(unsigned long int)parent,name);
1858 fprintf(stderr,"symlink (%s,%lu,%s)\n",path,(unsigned long int)parent,name);
1859 }
1860 if (parent==FUSE_ROOT_ID) {
1861 if (IS_SPECIAL_NAME(name)) {
1862 oplog_printf(&ctx,"symlink (%s,%lu,%s): %s",path,(unsigned long int)parent,name,strerr(EACCES));
1863 fuse_reply_err(req, EACCES);
1864 return;
1865 }
1866 }
1867 nleng = strlen(name);
1868 if (nleng>MFS_NAME_MAX || (strlen(path)+1)>MFS_SYMLINK_MAX) {
1869 oplog_printf(&ctx,"symlink (%s,%lu,%s): %s",path,(unsigned long int)parent,name,strerr(ENAMETOOLONG));
1870 fuse_reply_err(req, ENAMETOOLONG);
1871 return;
1872 }
1873
1874 if (full_permissions) {
1875 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1876 status = fs_symlink(parent,nleng,(const uint8_t*)name,(const uint8_t*)path,ctx.uid,gids->gidcnt,gids->gidtab,&inode,attr);
1877 groups_rel(gids);
1878 } else {
1879 uint32_t gidtmp = ctx.gid;
1880 status = fs_symlink(parent,nleng,(const uint8_t*)name,(const uint8_t*)path,ctx.uid,1,&gidtmp,&inode,attr);
1881 }
1882 status = mfs_errorconv(status);
1883 if (status!=0) {
1884 oplog_printf(&ctx,"symlink (%s,%lu,%s): %s",path,(unsigned long int)parent,name,strerr(status));
1885 fuse_reply_err(req, status);
1886 } else {
1887 negentry_cache_remove(parent,nleng,(const uint8_t*)name);
1888 // if (newdircache) {
1889 // dir_cache_link(parent,nleng,(const uint8_t*)name,inode,attr);
1890 // }
1891 dcache_invalidate_attr(parent);
1892 memset(&e, 0, sizeof(e));
1893 e.ino = inode;
1894 e.generation = 1;
1895 mattr = mfs_attr_get_mattr(attr);
1896 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
1897 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:entry_cache_timeout;
1898 mfs_attr_to_stat(inode,attr,&e.attr);
1899 mfs_makeattrstr(attrstr,256,&e.attr);
1900 oplog_printf(&ctx,"symlink (%s,%lu,%s): OK (%.1lf,%lu,%.1lf,%s)",path,(unsigned long int)parent,name,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
1901 fuse_reply_entry(req, &e);
1902 }
1903 }
1904
1905 void mfs_readlink(fuse_req_t req, fuse_ino_t ino) {
1906 int status;
1907 const uint8_t *path;
1908 struct fuse_ctx ctx;
1909
1910 ctx = *(fuse_req_ctx(req));
1911 if (debug_mode) {
1912 oplog_printf(&ctx,"readlink (%lu) ...",(unsigned long int)ino);
1913 fprintf(stderr,"readlink (%lu)\n",(unsigned long int)ino);
1914 }
1915 if (symlink_cache_search(ino,&path)) {
1916 mfs_stats_inc(OP_READLINK_CACHED);
1917 oplog_printf(&ctx,"readlink (%lu) (using cache): OK (%s)",(unsigned long int)ino,(char*)path);
1918 fuse_reply_readlink(req, (char*)path);
1919 return;
1920 }
1921 mfs_stats_inc(OP_READLINK_MASTER);
1922 status = fs_readlink(ino,&path);
1923 status = mfs_errorconv(status);
1924 if (status!=0) {
1925 oplog_printf(&ctx,"readlink (%lu): %s",(unsigned long int)ino,strerr(status));
1926 fuse_reply_err(req, status);
1927 } else {
1928 dcache_invalidate_attr(ino);
1929 symlink_cache_insert(ino,path);
1930 oplog_printf(&ctx,"readlink (%lu): OK (%s)",(unsigned long int)ino,(char*)path);
1931 fuse_reply_readlink(req, (char*)path);
1932 }
1933 }
1934
1935 void mfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname) {
1936 uint32_t nleng,newnleng;
1937 int status;
1938 uint32_t inode;
1939 uint8_t attr[35];
1940 struct fuse_ctx ctx;
1941 groups *gids;
1942
1943 ctx = *(fuse_req_ctx(req));
1944 mfs_stats_inc(OP_RENAME);
1945 if (debug_mode) {
1946 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s) ...",(unsigned long int)parent,name,(unsigned long int)newparent,newname);
1947 fprintf(stderr,"rename (%lu,%s,%lu,%s)\n",(unsigned long int)parent,name,(unsigned long int)newparent,newname);
1948 }
1949 if (parent==FUSE_ROOT_ID) {
1950 if (IS_SPECIAL_NAME(name)) {
1951 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): %s",(unsigned long int)parent,name,(unsigned long int)newparent,newname,strerr(EACCES));
1952 fuse_reply_err(req, EACCES);
1953 return;
1954 }
1955 }
1956 if (newparent==FUSE_ROOT_ID) {
1957 if (IS_SPECIAL_NAME(newname)) {
1958 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): %s",(unsigned long int)parent,name,(unsigned long int)newparent,newname,strerr(EACCES));
1959 fuse_reply_err(req, EACCES);
1960 return;
1961 }
1962 }
1963 nleng = strlen(name);
1964 if (nleng>MFS_NAME_MAX) {
1965 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): %s",(unsigned long int)parent,name,(unsigned long int)newparent,newname,strerr(ENAMETOOLONG));
1966 fuse_reply_err(req, ENAMETOOLONG);
1967 return;
1968 }
1969 newnleng = strlen(newname);
1970 if (newnleng>MFS_NAME_MAX) {
1971 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): %s",(unsigned long int)parent,name,(unsigned long int)newparent,newname,strerr(ENAMETOOLONG));
1972 fuse_reply_err(req, ENAMETOOLONG);
1973 return;
1974 }
1975
1976 if (full_permissions) {
1977 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
1978 status = fs_rename(parent,nleng,(const uint8_t*)name,newparent,newnleng,(const uint8_t*)newname,ctx.uid,gids->gidcnt,gids->gidtab,&inode,attr);
1979 groups_rel(gids);
1980 } else {
1981 uint32_t gidtmp = ctx.gid;
1982 status = fs_rename(parent,nleng,(const uint8_t*)name,newparent,newnleng,(const uint8_t*)newname,ctx.uid,1,&gidtmp,&inode,attr);
1983 }
1984 status = mfs_errorconv(status);
1985 if (status!=0) {
1986 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): %s",(unsigned long int)parent,name,(unsigned long int)newparent,newname,strerr(status));
1987 fuse_reply_err(req, status);
1988 } else {
1989 negentry_cache_insert(parent,nleng,(const uint8_t*)name);
1990 negentry_cache_remove(newparent,newnleng,(const uint8_t*)newname);
1991 // if (newdircache) {
1992 // dir_cache_unlink(parent,nleng,(const uint8_t*)name);
1993 // dir_cache_link(newparent,newnleng,(const uint8_t*)newname,inode,attr);
1994 // }
1995 dcache_invalidate_attr(parent);
1996 if (newparent!=parent) {
1997 dcache_invalidate_attr(newparent);
1998 }
1999 dcache_invalidate_name(&ctx,parent,nleng,(const uint8_t*)name);
2000 oplog_printf(&ctx,"rename (%lu,%s,%lu,%s): OK",(unsigned long int)parent,name,(unsigned long int)newparent,newname);
2001 fuse_reply_err(req, 0);
2002 }
2003 }
2004
2005 void mfs_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) {
2006 uint32_t newnleng;
2007 int status;
2008 struct fuse_entry_param e;
2009 uint32_t inode;
2010 uint8_t attr[35];
2011 char attrstr[256];
2012 uint8_t mattr;
2013 struct fuse_ctx ctx;
2014 groups *gids;
2015
2016 ctx = *(fuse_req_ctx(req));
2017 mfs_stats_inc(OP_LINK);
2018 if (debug_mode) {
2019 oplog_printf(&ctx,"link (%lu,%lu,%s) ...",(unsigned long int)ino,(unsigned long int)newparent,newname);
2020 fprintf(stderr,"link (%lu,%lu,%s)\n",(unsigned long int)ino,(unsigned long int)newparent,newname);
2021 }
2022 if (IS_SPECIAL_INODE(ino)) {
2023 oplog_printf(&ctx,"link (%lu,%lu,%s): %s",(unsigned long int)ino,(unsigned long int)newparent,newname,strerr(EACCES));
2024 fuse_reply_err(req, EACCES);
2025 return;
2026 }
2027 if (newparent==FUSE_ROOT_ID) {
2028 if (IS_SPECIAL_NAME(newname)) {
2029 oplog_printf(&ctx,"link (%lu,%lu,%s): %s",(unsigned long int)ino,(unsigned long int)newparent,newname,strerr(EACCES));
2030 fuse_reply_err(req, EACCES);
2031 return;
2032 }
2033 }
2034 newnleng = strlen(newname);
2035 if (newnleng>MFS_NAME_MAX) {
2036 oplog_printf(&ctx,"link (%lu,%lu,%s): %s",(unsigned long int)ino,(unsigned long int)newparent,newname,strerr(ENAMETOOLONG));
2037 fuse_reply_err(req, ENAMETOOLONG);
2038 return;
2039 }
2040
2041 // write_data_flush_inode(ino);
2042 if (full_permissions) {
2043 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2044 status = fs_link(ino,newparent,newnleng,(const uint8_t*)newname,ctx.uid,gids->gidcnt,gids->gidtab,&inode,attr);
2045 groups_rel(gids);
2046 } else {
2047 uint32_t gidtmp = ctx.gid;
2048 status = fs_link(ino,newparent,newnleng,(const uint8_t*)newname,ctx.uid,1,&gidtmp,&inode,attr);
2049 }
2050 status = mfs_errorconv(status);
2051 if (status!=0) {
2052 oplog_printf(&ctx,"link (%lu,%lu,%s): %s",(unsigned long int)ino,(unsigned long int)newparent,newname,strerr(status));
2053 fuse_reply_err(req, status);
2054 } else {
2055 negentry_cache_remove(newparent,newnleng,(const uint8_t*)newname);
2056 // if (newdircache) {
2057 // dir_cache_link(newparent,newnleng,(const uint8_t*)newname,inode,attr);
2058 // }
2059 if (ino!=inode) {
2060 dcache_invalidate_attr(ino);
2061 }
2062 dcache_invalidate_attr(newparent);
2063 dcache_setattr(inode,attr);
2064 memset(&e, 0, sizeof(e));
2065 e.ino = inode;
2066 e.generation = 1;
2067 mattr = mfs_attr_get_mattr(attr);
2068 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
2069 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:entry_cache_timeout;
2070 mfs_attr_to_stat(inode,attr,&e.attr);
2071 mfs_makeattrstr(attrstr,256,&e.attr);
2072 oplog_printf(&ctx,"link (%lu,%lu,%s): OK (%.1lf,%lu,%.1lf,%s)",(unsigned long int)ino,(unsigned long int)newparent,newname,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr);
2073 fuse_reply_entry(req, &e);
2074 }
2075 }
2076
2077 void mfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
2078 dirbuf *dirinfo;
2079 int status;
2080 uint8_t attr[35];
2081 struct fuse_ctx ctx;
2082 groups *gids;
2083
2084 ctx = *(fuse_req_ctx(req));
2085 mfs_stats_inc(OP_OPENDIR);
2086 if (debug_mode) {
2087 oplog_printf(&ctx,"opendir (%lu) ...",(unsigned long int)ino);
2088 fprintf(stderr,"opendir (%lu)\n",(unsigned long int)ino);
2089 }
2090 if (IS_SPECIAL_INODE(ino)) {
2091 oplog_printf(&ctx,"opendir (%lu): %s",(unsigned long int)ino,strerr(ENOTDIR));
2092 fuse_reply_err(req, ENOTDIR);
2093 }
2094 if (full_permissions) {
2095 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2096 status = fs_access(ino,ctx.uid,gids->gidcnt,gids->gidtab,MODE_MASK_R); // at least test rights
2097 groups_rel(gids);
2098 } else { // no acl means - we are using default permissions, so do not check supplementary groups
2099 status = fs_access(ino,ctx.uid,1,&(ctx.gid),MODE_MASK_R); // at least test rights
2100 }
2101 if (status==ERROR_ENOENT && sstats_get(ino,attr,0)==STATUS_OK) {
2102 if (full_permissions) {
2103 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2104 status = mfs_access_test(attr,MODE_MASK_R,ctx.uid,gids->gidcnt,gids->gidtab);
2105 groups_rel(gids);
2106 } else {
2107 uint32_t gidtmp = ctx.gid;
2108 status = mfs_access_test(attr,MODE_MASK_R,ctx.uid,1,&gidtmp);
2109 }
2110 if (status!=STATUS_OK) {
2111 status = mfs_errorconv(status);
2112 oplog_printf(&ctx,"opendir (%lu): %s",(unsigned long int)ino,strerr(status));
2113 fuse_reply_err(req, status);
2114 } else {
2115 dirinfo = malloc(sizeof(dirbuf));
2116 pthread_mutex_init(&(dirinfo->lock),NULL);
2117 dirinfo->p = NULL;
2118 dirinfo->size = 0;
2119 dirinfo->dcache = NULL;
2120 dirinfo->wasread = 2;
2121 pthread_mutex_unlock(&(dirinfo->lock)); // make valgrind happy
2122 fi->fh = (unsigned long)dirinfo;;
2123 oplog_printf(&ctx,"sustained opendir (%lu): forced OK with empty directory",(unsigned long int)ino);
2124 if (fuse_reply_open(req,fi) == -ENOENT) {
2125 fi->fh = 0;
2126 pthread_mutex_destroy(&(dirinfo->lock));
2127 free(dirinfo);
2128 }
2129 }
2130 } else if (status!=STATUS_OK) {
2131 status = mfs_errorconv(status);
2132 oplog_printf(&ctx,"opendir (%lu): %s",(unsigned long int)ino,strerr(status));
2133 fuse_reply_err(req, status);
2134 } else {
2135 dirinfo = malloc(sizeof(dirbuf));
2136 pthread_mutex_init(&(dirinfo->lock),NULL);
2137 pthread_mutex_lock(&(dirinfo->lock)); // make valgrind happy
2138 dirinfo->p = NULL;
2139 dirinfo->size = 0;
2140 dirinfo->dcache = NULL;
2141 dirinfo->wasread = 0;
2142 pthread_mutex_unlock(&(dirinfo->lock)); // make valgrind happy
2143 fi->fh = (unsigned long)dirinfo;
2144 oplog_printf(&ctx,"opendir (%lu): OK",(unsigned long int)ino);
2145 if (fuse_reply_open(req,fi) == -ENOENT) {
2146 fi->fh = 0;
2147 pthread_mutex_destroy(&(dirinfo->lock));
2148 free(dirinfo);
2149 }
2150 }
2151 }
2152
2153 void mfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
2154 int status;
2155 dirbuf *dirinfo = (dirbuf *)((unsigned long)(fi->fh));
2156 char buffer[READDIR_BUFFSIZE];
2157 char name[MFS_NAME_MAX+1];
2158 const uint8_t *ptr,*eptr;
2159 uint8_t end;
2160 size_t opos,oleng;
2161 uint8_t nleng;
2162 uint32_t inode;
2163 uint8_t type;
2164 struct stat stbuf;
2165 struct fuse_ctx ctx;
2166 groups *gids;
2167
2168 ctx = *(fuse_req_ctx(req));
2169 mfs_stats_inc(OP_READDIR);
2170 if (debug_mode) {
2171 oplog_printf(&ctx,"readdir (%lu,%llu,%llu) ...",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2172 fprintf(stderr,"readdir (%lu,%llu,%llu)\n",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2173 }
2174 if (off<0) {
2175 oplog_printf(&ctx,"readdir (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EINVAL));
2176 fuse_reply_err(req,EINVAL);
2177 return;
2178 }
2179 pthread_mutex_lock(&(dirinfo->lock));
2180 if (dirinfo->wasread==0 || (dirinfo->wasread==1 && off==0)) {
2181 const uint8_t *dbuff;
2182 uint32_t dsize;
2183 uint8_t needscopy;
2184 /*
2185 if (newdircache) {
2186 status = dir_cache_getdirdata(ino,&dsize,&dbuff);
2187 if (status==1) { // got dir from new cache
2188 mfs_stats_inc(OP_GETDIR_CACHED);
2189 needscopy = 0;
2190 dirinfo->dataformat = 0;
2191 status = 0;
2192 } else {
2193 status = fs_getdir_plus(ino,ctx.uid,ctx.gid,1,&dbuff,&dsize);
2194 if (status==0) {
2195 mfs_stats_inc(OP_GETDIR_FULL);
2196 dir_cache_newdirdata(ino,dsize,dbuff);
2197 }
2198 needscopy = 1;
2199 dirinfo->dataformat = 1;
2200 }
2201 } else
2202 */
2203 if (usedircache) {
2204 uint8_t df;
2205 df = 1;
2206 if (full_permissions) {
2207 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2208 status = fs_readdir(ino,ctx.uid,gids->gidcnt,gids->gidtab,1,0,&dbuff,&dsize);
2209 if (status==ERROR_EACCES) {
2210 df = 0;
2211 status = fs_readdir(ino,ctx.uid,gids->gidcnt,gids->gidtab,0,0,&dbuff,&dsize);
2212 }
2213 groups_rel(gids);
2214 } else {
2215 uint32_t gidtmp = ctx.gid;
2216 status = fs_readdir(ino,ctx.uid,1,&gidtmp,1,0,&dbuff,&dsize);
2217 if (status==ERROR_EACCES) {
2218 df = 0;
2219 status = fs_readdir(ino,ctx.uid,1,&gidtmp,0,0,&dbuff,&dsize);
2220 }
2221 }
2222 if (status==0) {
2223 if (df) {
2224 mfs_stats_inc(OP_GETDIR_FULL);
2225 } else {
2226 mfs_stats_inc(OP_GETDIR_SMALL);
2227 }
2228 }
2229 needscopy = 1;
2230 dirinfo->dataformat = df;
2231 } else {
2232 if (full_permissions) {
2233 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2234 status = fs_readdir(ino,ctx.uid,gids->gidcnt,gids->gidtab,0,0,&dbuff,&dsize);
2235 groups_rel(gids);
2236 } else {
2237 uint32_t gidtmp = ctx.gid;
2238 status = fs_readdir(ino,ctx.uid,1,&gidtmp,0,0,&dbuff,&dsize);
2239 }
2240 if (status==0) {
2241 mfs_stats_inc(OP_GETDIR_SMALL);
2242 }
2243 needscopy = 1;
2244 dirinfo->dataformat = 0;
2245 }
2246 status = mfs_errorconv(status);
2247 if (status!=0) {
2248 oplog_printf(&ctx,"readdir (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(status));
2249 fuse_reply_err(req, status);
2250 pthread_mutex_unlock(&(dirinfo->lock));
2251 return;
2252 }
2253 if (dirinfo->dcache) {
2254 dcache_release(dirinfo->dcache);
2255 dirinfo->dcache = NULL;
2256 }
2257 if (dirinfo->p) {
2258 free((uint8_t*)(dirinfo->p));
2259 dirinfo->p = NULL;
2260 }
2261 if (needscopy) {
2262 dirinfo->p = malloc(dsize);
2263 if (dirinfo->p == NULL) {
2264 oplog_printf(&ctx,"readdir (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EINVAL));
2265 fuse_reply_err(req,EINVAL);
2266 pthread_mutex_unlock(&(dirinfo->lock));
2267 return;
2268 }
2269 memcpy((uint8_t*)(dirinfo->p),dbuff,dsize);
2270 } else {
2271 dirinfo->p = dbuff;
2272 }
2273 dirinfo->size = dsize;
2274 if (usedircache && dirinfo->dataformat==1) {
2275 dirinfo->dcache = dcache_new(&ctx,ino,dirinfo->p,dirinfo->size);
2276 }
2277 }
2278 dirinfo->wasread=1;
2279
2280 if (off>=(off_t)(dirinfo->size)) {
2281 oplog_printf(&ctx,"readdir (%lu,%llu,%llu): OK (no data)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2282 fuse_reply_buf(req, NULL, 0);
2283 } else {
2284 if (size>READDIR_BUFFSIZE) {
2285 size=READDIR_BUFFSIZE;
2286 }
2287 ptr = dirinfo->p+off;
2288 eptr = dirinfo->p+dirinfo->size;
2289 opos = 0;
2290 end = 0;
2291
2292 while (ptr<eptr && end==0) {
2293 nleng = ptr[0];
2294 ptr++;
2295 memcpy(name,ptr,nleng);
2296 name[nleng]=0;
2297 ptr+=nleng;
2298 off+=nleng+((dirinfo->dataformat)?40:6);
2299 if (ptr+5<=eptr) {
2300 inode = get32bit(&ptr);
2301 if (dirinfo->dataformat) {
2302 mfs_attr_to_stat(inode,ptr,&stbuf);
2303 ptr+=35;
2304 } else {
2305 type = get8bit(&ptr);
2306 mfs_type_to_stat(inode,type,&stbuf);
2307 }
2308 oleng = fuse_add_direntry(req, buffer + opos, size - opos, name, &stbuf, off);
2309 if (opos+oleng>size) {
2310 end=1;
2311 } else {
2312 opos+=oleng;
2313 }
2314 }
2315 }
2316
2317 oplog_printf(&ctx,"readdir (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)opos);
2318 fuse_reply_buf(req,buffer,opos);
2319 }
2320 pthread_mutex_unlock(&(dirinfo->lock));
2321 }
2322
2323 void mfs_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
2324 (void)ino;
2325 dirbuf *dirinfo = (dirbuf *)((unsigned long)(fi->fh));
2326 struct fuse_ctx ctx;
2327
2328 ctx = *(fuse_req_ctx(req));
2329 mfs_stats_inc(OP_RELEASEDIR);
2330 if (debug_mode) {
2331 oplog_printf(&ctx,"releasedir (%lu) ...",(unsigned long int)ino);
2332 fprintf(stderr,"releasedir (%lu)\n",(unsigned long int)ino);
2333 }
2334 pthread_mutex_lock(&(dirinfo->lock));
2335 pthread_mutex_unlock(&(dirinfo->lock));
2336 pthread_mutex_destroy(&(dirinfo->lock));
2337 if (dirinfo->dcache) {
2338 dcache_release(dirinfo->dcache);
2339 }
2340 if (dirinfo->p) {
2341 free((uint8_t*)(dirinfo->p));
2342 }
2343 free(dirinfo);
2344 fi->fh = 0;
2345 oplog_printf(&ctx,"releasedir (%lu): OK",(unsigned long int)ino);
2346 fuse_reply_err(req,0);
2347 }
2348
2349 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2350 static void mfs_real_removefileinfo(finfo* fileinfo) {
2351 pthread_mutex_lock(&(fileinfo->lock));
2352 if (fileinfo->mode == IO_READONLY || fileinfo->mode == IO_READ) {
2353 read_data_end(fileinfo->data);
2354 } else if (fileinfo->mode == IO_WRITEONLY || fileinfo->mode == IO_WRITE) {
2355 // write_data_flush(fileinfo->data);
2356 write_data_end(fileinfo->data);
2357 }
2358 pthread_mutex_unlock(&(fileinfo->lock));
2359 pthread_mutex_destroy(&(fileinfo->lock));
2360 free(fileinfo);
2361 }
2362 #endif
2363
2364 static finfo* mfs_newfileinfo(uint8_t accmode,uint32_t inode) {
2365 finfo *fileinfo;
2366 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2367 finfo **fileinfoptr;
2368 double now;
2369 now = monotonic_seconds();
2370 pthread_mutex_lock(&finfo_list_lock);
2371 fileinfoptr = &finfo_head;
2372 while ((fileinfo=*fileinfoptr)) {
2373 if (fileinfo->ops_in_progress==0 && fileinfo->lastuse+FREEBSD_EARLY_RELEASE_DELAY<now) {
2374 *fileinfoptr = fileinfo->next;
2375 mfs_real_removefileinfo(fileinfo);
2376 } else {
2377 fileinfoptr = &(fileinfo->next);
2378 }
2379 }
2380 pthread_mutex_unlock(&finfo_list_lock);
2381 #endif
2382 fileinfo = malloc(sizeof(finfo));
2383 pthread_mutex_init(&(fileinfo->lock),NULL);
2384 pthread_mutex_lock(&(fileinfo->lock)); // make helgrind happy
2385 #ifdef __FreeBSD__
2386 /* old FreeBSD fuse reads whole file when opening with O_WRONLY|O_APPEND,
2387 * so can't open it write-only */
2388 (void)accmode;
2389 (void)inode;
2390 fileinfo->mode = IO_NONE;
2391 fileinfo->data = NULL;
2392 #else
2393 if (accmode == O_RDONLY) {
2394 fileinfo->mode = IO_READONLY;
2395 fileinfo->data = read_data_new(inode);
2396 } else if (accmode == O_WRONLY) {
2397 fileinfo->mode = IO_WRITEONLY;
2398 fileinfo->data = write_data_new(inode);
2399 } else {
2400 fileinfo->mode = IO_NONE;
2401 fileinfo->data = NULL;
2402 }
2403 #endif
2404 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2405 fileinfo->ops_in_progress = 0;
2406 fileinfo->lastuse = now;
2407 fileinfo->next = NULL;
2408 #endif
2409 pthread_mutex_unlock(&(fileinfo->lock)); // make helgrind happy
2410 return fileinfo;
2411 }
2412
2413 static void mfs_removefileinfo(finfo* fileinfo) {
2414 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2415 pthread_mutex_lock(&(fileinfo->lock));
2416 fileinfo->lastuse = monotonic_seconds();
2417 pthread_mutex_unlock(&(fileinfo->lock));
2418 pthread_mutex_lock(&finfo_list_lock);
2419 fileinfo->next = finfo_head;
2420 finfo_head = fileinfo;
2421 pthread_mutex_unlock(&finfo_list_lock);
2422 #else
2423 pthread_mutex_lock(&(fileinfo->lock));
2424 if (fileinfo->mode == IO_READONLY || fileinfo->mode == IO_READ) {
2425 read_data_end(fileinfo->data);
2426 } else if (fileinfo->mode == IO_WRITEONLY || fileinfo->mode == IO_WRITE) {
2427 // write_data_flush(fileinfo->data);
2428 write_data_end(fileinfo->data);
2429 }
2430 pthread_mutex_unlock(&(fileinfo->lock));
2431 pthread_mutex_destroy(&(fileinfo->lock));
2432 free(fileinfo);
2433 #endif
2434 }
2435
2436 void mfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) {
2437 struct fuse_entry_param e;
2438 uint32_t inode;
2439 uint8_t attr[35];
2440 char modestr[11];
2441 char attrstr[256];
2442 uint8_t mattr;
2443 uint32_t nleng;
2444 uint16_t cumask;
2445 int status;
2446 struct fuse_ctx ctx;
2447 groups *gids;
2448 finfo *fileinfo;
2449
2450 ctx = *(fuse_req_ctx(req));
2451 mfs_makemodestr(modestr,mode);
2452 mfs_stats_inc(OP_CREATE);
2453 if (debug_mode) {
2454 #ifdef FUSE_CAP_DONT_MASK
2455 char umaskstr[11];
2456 mfs_makemodestr(umaskstr,ctx.umask);
2457 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o/%s:0%04o)",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask));
2458 fprintf(stderr,"create (%lu,%s,-%s:0%04o/%s:0%04o)\n",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,umaskstr+1,(unsigned int)(ctx.umask));
2459 #else
2460 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o)",(unsigned long int)parent,name,modestr+1,(unsigned int)mode);
2461 fprintf(stderr,"create (%lu,%s,-%s:0%04o)\n",(unsigned long int)parent,name,modestr+1,(unsigned int)mode);
2462 #endif
2463 }
2464 if (parent==FUSE_ROOT_ID) {
2465 if (IS_SPECIAL_NAME(name)) {
2466 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(EACCES));
2467 fuse_reply_err(req,EACCES);
2468 return;
2469 }
2470 }
2471 nleng = strlen(name);
2472 if (nleng>MFS_NAME_MAX) {
2473 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(ENAMETOOLONG));
2474 fuse_reply_err(req, ENAMETOOLONG);
2475 return;
2476 }
2477
2478 #ifdef FUSE_CAP_DONT_MASK
2479 cumask = ctx.umask;
2480 #else
2481 cumask = 0;
2482 #endif
2483 if (full_permissions) {
2484 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
2485 status = fs_create(parent,nleng,(const uint8_t*)name,mode&07777,cumask,ctx.uid,gids->gidcnt,gids->gidtab,&inode,attr);
2486 groups_rel(gids);
2487 } else {
2488 uint32_t gidtmp = ctx.gid;
2489 status = fs_create(parent,nleng,(const uint8_t*)name,mode&07777,cumask,ctx.uid,1,&gidtmp,&inode,attr);
2490 }
2491 if (status!=ERROR_ENOTSUP) {
2492 #if defined(__APPLE__)
2493 // due to bug in os x - create in deleted directory goes into infinite loop when it gets ENOENT, so we should change it to different error - we use EACCES
2494 if (status==ERROR_ENOENT && sstats_get(parent,attr,0)==STATUS_OK) {
2495 status=ERROR_EACCES;
2496 }
2497 #endif
2498 status = mfs_errorconv(status);
2499 if (status!=0) {
2500 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(status));
2501 fuse_reply_err(req, status);
2502 return;
2503 }
2504 negentry_cache_remove(parent,nleng,(const uint8_t*)name);
2505 if (xattr_cache_on) { // Linux asks for this xattr before every write, so after create we can safely assume that there is no such attribute, and set it in xattr cache (improve efficiency on small files)
2506 xattr_cache_set(inode,ctx.uid,ctx.gid,8+1+10,(const uint8_t*)"security.capability",NULL,0,ERROR_ENOATTR);
2507 }
2508 // if (newdircache) {
2509 // dir_cache_link(parent,nleng,(const uint8_t*)name,inode,attr);
2510 // }
2511 } else {
2512 uint8_t oflags;
2513 uint32_t gidtmp = ctx.gid;
2514 oflags = AFTER_CREATE;
2515 if ((fi->flags & O_ACCMODE) == O_RDONLY) {
2516 oflags |= WANT_READ;
2517 } else if ((fi->flags & O_ACCMODE) == O_WRONLY) {
2518 oflags |= WANT_WRITE;
2519 } else if ((fi->flags & O_ACCMODE) == O_RDWR) {
2520 oflags |= WANT_READ | WANT_WRITE;
2521 } else {
2522 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(EINVAL));
2523 fuse_reply_err(req, EINVAL);
2524 return;
2525 }
2526 status = fs_mknod(parent,nleng,(const uint8_t*)name,TYPE_FILE,mode&07777,cumask,ctx.uid,1,&gidtmp,0,&inode,attr);
2527 status = mfs_errorconv(status);
2528 if (status!=0) {
2529 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o) (mknod): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(status));
2530 fuse_reply_err(req, status);
2531 return;
2532 }
2533 negentry_cache_remove(parent,nleng,(const uint8_t*)name);
2534 // if (newdircache) {
2535 // dir_cache_link(parent,nleng,(const uint8_t*)name,inode,attr);
2536 // }
2537 status = fs_opencheck(inode,ctx.uid,1,&gidtmp,oflags,NULL);
2538 status = mfs_errorconv(status);
2539 if (status!=0) {
2540 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o) (open): %s",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,strerr(status));
2541 fuse_reply_err(req, status);
2542 return;
2543 }
2544 }
2545
2546 mattr = mfs_attr_get_mattr(attr);
2547 fileinfo = mfs_newfileinfo(fi->flags & O_ACCMODE,inode);
2548 fi->fh = (unsigned long)fileinfo;
2549 #if defined(__FreeBSD__) || defined(__APPLE__)
2550 fi->keep_cache = 0;
2551 fi->direct_io = 1;
2552 #else
2553 if (keep_cache==1) {
2554 fi->keep_cache=1;
2555 } else if (keep_cache==2) {
2556 fi->keep_cache=0;
2557 } else {
2558 fi->keep_cache = (mattr&MATTR_ALLOWDATACACHE)?1:0;
2559 }
2560 fi->direct_io = 0;
2561 #endif
2562 if (debug_mode) {
2563 fprintf(stderr,"create (%lu) ok -> keep cache: %u\n",(unsigned long int)inode,(unsigned int)fi->keep_cache);
2564 }
2565 dcache_invalidate_attr(parent);
2566 memset(&e, 0, sizeof(e));
2567 e.ino = inode;
2568 e.generation = 1;
2569 e.attr_timeout = (mattr&MATTR_NOACACHE)?0.0:attr_cache_timeout;
2570 e.entry_timeout = (mattr&MATTR_NOECACHE)?0.0:entry_cache_timeout;
2571 mfs_attr_to_stat(inode,attr,&e.attr);
2572 mfs_makeattrstr(attrstr,256,&e.attr);
2573 oplog_printf(&ctx,"create (%lu,%s,-%s:0%04o): OK (%.1lf,%lu,%.1lf,%s,%u)",(unsigned long int)parent,name,modestr+1,(unsigned int)mode,e.entry_timeout,(unsigned long int)e.ino,e.attr_timeout,attrstr,(unsigned int)fi->keep_cache);
2574 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
2575 mfs_removefileinfo(fileinfo);
2576 fi->fh = 0;
2577 }
2578 }
2579
2580 void mfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
2581 uint8_t oflags;
2582 uint8_t attr[35];
2583 #if !(defined(__FreeBSD__) || defined(__APPLE__))
2584 uint8_t mattr;
2585 #endif
2586 int status;
2587 struct fuse_ctx ctx;
2588 groups *gids;
2589 finfo *fileinfo;
2590
2591 ctx = *(fuse_req_ctx(req));
2592 mfs_stats_inc(OP_OPEN);
2593 if (debug_mode) {
2594 oplog_printf(&ctx,"open (%lu) ...",(unsigned long int)ino);
2595 fprintf(stderr,"open (%lu)\n",(unsigned long int)ino);
2596 }
2597 // if (ino==MASTER_INODE) {
2598 // minfo *masterinfo;
2599 // status = fs_direct_connect();
2600 // if (status<0) {
2601 // fuse_reply_err(req,EIO);
2602 // return;
2603 // }
2604 // masterinfo = malloc(sizeof(minfo));
2605 // if (masterinfo==NULL) {
2606 // fuse_reply_err(req,ENOMEM);
2607 // return;
2608 // }
2609 // masterinfo->sd = status;
2610 // masterinfo->sent = 0;
2611 // fi->direct_io = 1;
2612 // fi->fh = (unsigned long)masterinfo;
2613 // fuse_reply_open(req, fi);
2614 // return;
2615 // }
2616 if (ino==MASTERINFO_INODE) {
2617 if ((fi->flags & O_ACCMODE) != O_RDONLY) {
2618 oplog_printf(&ctx,"open (%lu) (internal node: MASTERINFO): %s",(unsigned long int)ino,strerr(EACCES));
2619 fuse_reply_err(req,EACCES);
2620 return;
2621 }
2622 fi->fh = 0;
2623 fi->direct_io = 0;
2624 fi->keep_cache = 1;
2625 oplog_printf(&ctx,"open (%lu) (internal node: MASTERINFO): OK (0,1)",(unsigned long int)ino);
2626 fuse_reply_open(req, fi);
2627 return;
2628 }
2629
2630 if (ino==STATS_INODE) {
2631 sinfo *statsinfo;
2632 // if ((fi->flags & O_ACCMODE) != O_RDONLY) {
2633 // stats_reset_all();
2634 // fuse_reply_err(req,EACCES);
2635 // return;
2636 // }
2637 statsinfo = malloc(sizeof(sinfo));
2638 if (statsinfo==NULL) {
2639 oplog_printf(&ctx,"open (%lu) (internal node: STATS): %s",(unsigned long int)ino,strerr(ENOMEM));
2640 fuse_reply_err(req,ENOMEM);
2641 return;
2642 }
2643 pthread_mutex_init(&(statsinfo->lock),NULL); // make helgrind happy
2644 pthread_mutex_lock(&(statsinfo->lock)); // make helgrind happy
2645 stats_show_all(&(statsinfo->buff),&(statsinfo->leng));
2646 statsinfo->reset = 0;
2647 pthread_mutex_unlock(&(statsinfo->lock)); // make helgrind happy
2648 fi->fh = (unsigned long)statsinfo;
2649 fi->direct_io = 1;
2650 fi->keep_cache = 0;
2651 oplog_printf(&ctx,"open (%lu) (internal node: STATS): OK (1,0)",(unsigned long int)ino);
2652 fuse_reply_open(req, fi);
2653 return;
2654 }
2655 if (ino==MOOSE_INODE) {
2656 fi->fh = 0;
2657 fi->direct_io = 1;
2658 fi->keep_cache = 0;
2659 oplog_printf(&ctx,"open (%lu) (internal node: MOOSE): OK (1,0)",(unsigned long int)ino);
2660 fuse_reply_open(req, fi);
2661 return;
2662 }
2663 if (ino==OPLOG_INODE || ino==OPHISTORY_INODE) {
2664 if ((fi->flags & O_ACCMODE) != O_RDONLY) {
2665 oplog_printf(&ctx,"open (%lu) (internal node: %s): %s",(unsigned long int)ino,(ino==OPLOG_INODE)?"OPLOG":"OPHISTORY",strerr(EACCES));
2666 fuse_reply_err(req,EACCES);
2667 return;
2668 }
2669 fi->fh = oplog_newhandle((ino==OPHISTORY_INODE)?1:0);
2670 fi->direct_io = 1;
2671 fi->keep_cache = 0;
2672 oplog_printf(&ctx,"open (%lu) (internal node: %s): OK (1,0)",(unsigned long int)ino,(ino==OPLOG_INODE)?"OPLOG":"OPHISTORY");
2673 fuse_reply_open(req, fi);
2674 return;
2675 }
2676 /*
2677 if (ino==ATTRCACHE_INODE) {
2678 fi->fh = 0;
2679 fi->direct_io = 1;
2680 fi->keep_cache = 0;
2681 fuse_reply_open(req, fi);
2682 return;
2683 }
2684 */
2685 oflags = 0;
2686 if ((fi->flags & O_ACCMODE) == O_RDONLY) {
2687 oflags |= WANT_READ;
2688 } else if ((fi->flags & O_ACCMODE) == O_WRONLY) {
2689 oflags |= WANT_WRITE;
2690 } else if ((fi->flags & O_ACCMODE) == O_RDWR) {
2691 oflags |= WANT_READ | WANT_WRITE;
2692 }
2693 // TODO: idea - only recently used inodes may have their data in cache, so if inode wasn't recently used then return ok status and force cache clear
2694 // fs_opencheck should always return status ok (because system should check access rights before using attributes), but even though perform opencheck
2695 // and if it returns error then save this error in fileinfo record, and return it on the first following I/O operation
2696 //
2697 // This should significantly speed up opening process.
2698 //
2699 // if (usedinodes_cache_check(ino)==0 || keep_cache>0) {
2700 // usedinodes_cache_add(ino);
2701 // fileinfo = mfs_newfileinfo(fi->flags & O_ACCMODE,ino);
2702 // fi->fh = (unsigned long)fileinfo;
2703 // if (keep_cache==1) {
2704 // fi->keep_cache=1;
2705 // } else {
2706 // fi->keep_cache=0;
2707 // }
2708 // if (debug_mode) {
2709 // fprintf(stderr,"open (%lu) ok -> keep cache: %lu\n",(unsigned long int)ino,(unsigned long int)fi->keep_cache);
2710 // }
2711 // fi->direct_io = 0;
2712 // oplog_printf(&ctx,"open (%lu): OK (%lu,%lu)",(unsigned long int)ino,(unsigned long int)fi->direct_io,(unsigned long int)fi->keep_cache);
2713 // if (fuse_reply_open(req, fi) == -ENOENT) {
2714 // mfs_removefileinfo(fileinfo);
2715 // }
2716 // status = fs_opencheck(ino,ctx.uid,ctx.gid,oflags,attr);
2717 // status = mfs_errorconv(status);
2718 // if (status!=0) {
2719 // pthread_mutes_lock(&(fileinfo->lock));
2720 // fileinfo->status = status;
2721 // pthread_mutex_unlock(&(fileinfo->lock));
2722 // }
2723 // } else {
2724 if (full_permissions) {
2725 gids = groups_get_x(ctx.pid,ctx.uid,ctx.gid,2);
2726 status = fs_opencheck(ino,ctx.uid,gids->gidcnt,gids->gidtab,oflags,attr);
2727 groups_rel(gids);
2728 } else {
2729 uint32_t gidtmp = ctx.gid;
2730 status = fs_opencheck(ino,ctx.uid,1,&gidtmp,oflags,attr);
2731 }
2732 status = mfs_errorconv(status);
2733 if (status!=0) {
2734 oplog_printf(&ctx,"open (%lu): %s",(unsigned long int)ino,strerr(status));
2735 fuse_reply_err(req, status);
2736 return ;
2737 }
2738
2739 fileinfo = mfs_newfileinfo(fi->flags & O_ACCMODE,ino);
2740 fi->fh = (unsigned long)fileinfo;
2741 #if defined(__FreeBSD__) || defined(__APPLE__)
2742 fi->keep_cache = 0;
2743 fi->direct_io = 1;
2744 #else
2745 mattr = mfs_attr_get_mattr(attr);
2746 if (keep_cache==1) {
2747 fi->keep_cache=1;
2748 } else if (keep_cache==2) {
2749 fi->keep_cache=0;
2750 } else {
2751 fi->keep_cache = (mattr&MATTR_ALLOWDATACACHE)?1:0;
2752 }
2753 fi->direct_io = 0;
2754 #endif
2755 if (debug_mode) {
2756 fprintf(stderr,"open (%lu) ok -> keep cache: %u\n",(unsigned long int)ino,(unsigned int)fi->keep_cache);
2757 }
2758 oplog_printf(&ctx,"open (%lu): OK (%u,%u)",(unsigned long int)ino,(unsigned int)fi->direct_io,(unsigned int)fi->keep_cache);
2759 if (fuse_reply_open(req, fi) == -ENOENT) {
2760 mfs_removefileinfo(fileinfo);
2761 }
2762 // }
2763 }
2764
2765 void mfs_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
2766 finfo *fileinfo = (finfo*)(unsigned long)(fi->fh);
2767 struct fuse_ctx ctx;
2768
2769 ctx = *(fuse_req_ctx(req));
2770 mfs_stats_inc(OP_RELEASE);
2771 if (debug_mode) {
2772 oplog_printf(&ctx,"release (%lu) ...",(unsigned long int)ino);
2773 fprintf(stderr,"release (%lu)\n",(unsigned long int)ino);
2774 }
2775 // if (ino==MASTER_INODE) {
2776 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
2777 // if (masterinfo!=NULL) {
2778 // fs_direct_close(masterinfo->sd);
2779 // free(masterinfo);
2780 // }
2781 // fuse_reply_err(req,0);
2782 // return;
2783 // }
2784 if (ino==MASTERINFO_INODE/* || ino==ATTRCACHE_INODE*/) {
2785 oplog_printf(&ctx,"release (%lu) (internal node: MASTERINFO): OK",(unsigned long int)ino);
2786 fuse_reply_err(req,0);
2787 return;
2788 }
2789 if (ino==STATS_INODE) {
2790 sinfo *statsinfo = (sinfo*)(unsigned long)(fi->fh);
2791 if (statsinfo!=NULL) {
2792 pthread_mutex_lock(&(statsinfo->lock)); // make helgrind happy
2793 if (statsinfo->buff!=NULL) {
2794 free(statsinfo->buff);
2795 }
2796 if (statsinfo->reset) {
2797 stats_reset_all();
2798 }
2799 pthread_mutex_unlock(&(statsinfo->lock)); // make helgrind happy
2800 pthread_mutex_destroy(&(statsinfo->lock)); // make helgrind happy
2801 free(statsinfo);
2802 }
2803 oplog_printf(&ctx,"release (%lu) (internal node: STATS): OK",(unsigned long int)ino);
2804 fuse_reply_err(req,0);
2805 return;
2806 }
2807 if (ino==MOOSE_INODE) {
2808 oplog_printf(&ctx,"release (%lu) (internal node: MOOSE): OK",(unsigned long int)ino);
2809 fuse_reply_err(req,0);
2810 return;
2811 }
2812 if (ino==OPLOG_INODE || ino==OPHISTORY_INODE) {
2813 oplog_releasehandle(fi->fh);
2814 oplog_printf(&ctx,"release (%lu) (internal node: %s): OK",(unsigned long int)ino,(ino==OPLOG_INODE)?"OPLOG":"OPHISTORY");
2815 fuse_reply_err(req,0);
2816 return;
2817 }
2818 // fuse_reply_err(req,0);
2819 dcache_invalidate_attr(ino);
2820 fs_release(ino);
2821 oplog_printf(&ctx,"release (%lu): OK",(unsigned long int)ino);
2822 fuse_reply_err(req,0);
2823 if (fileinfo!=NULL) {
2824 mfs_removefileinfo(fileinfo);
2825 }
2826 }
2827
2828 void mfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
2829 finfo *fileinfo = (finfo*)(unsigned long)(fi->fh);
2830 uint8_t *buff;
2831 uint32_t ssize;
2832 struct iovec *iov;
2833 uint32_t iovcnt;
2834 void *buffptr;
2835 int err;
2836 struct fuse_ctx ctx;
2837
2838 ctx = *(fuse_req_ctx(req));
2839 mfs_stats_inc(OP_READ);
2840 if (debug_mode) {
2841 if (ino!=OPLOG_INODE && ino!=OPHISTORY_INODE) {
2842 oplog_printf(&ctx,"read (%lu,%llu,%llu) ...",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2843 }
2844 fprintf(stderr,"read from inode %lu up to %llu bytes from position %llu\n",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2845 }
2846 if (ino==MASTERINFO_INODE) {
2847 uint8_t masterinfo[14];
2848 fs_getmasterlocation(masterinfo);
2849 masterproxy_getlocation(masterinfo);
2850 #ifdef MASTERINFO_WITH_VERSION
2851 if (off>=14) {
2852 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (no data)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2853 fuse_reply_buf(req,NULL,0);
2854 } else if (off+size>14) {
2855 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)(14-off));
2856 fuse_reply_buf(req,(char*)(masterinfo+off),14-off);
2857 #else
2858 if (off>=10) {
2859 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (no data)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2860 fuse_reply_buf(req,NULL,0);
2861 } else if (off+size>10) {
2862 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)(10-off));
2863 fuse_reply_buf(req,(char*)(masterinfo+off),10-off);
2864 #endif
2865 } else {
2866 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)size);
2867 fuse_reply_buf(req,(char*)(masterinfo+off),size);
2868 }
2869 return;
2870 }
2871 if (ino==STATS_INODE) {
2872 sinfo *statsinfo = (sinfo*)(unsigned long)(fi->fh);
2873 if (statsinfo!=NULL) {
2874 pthread_mutex_lock(&(statsinfo->lock)); // make helgrind happy
2875 if (off>=statsinfo->leng) {
2876 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (no data)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2877 fuse_reply_buf(req,NULL,0);
2878 } else if ((uint64_t)(off+size)>(uint64_t)(statsinfo->leng)) {
2879 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)(statsinfo->leng-off));
2880 fuse_reply_buf(req,statsinfo->buff+off,statsinfo->leng-off);
2881 } else {
2882 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)size);
2883 fuse_reply_buf(req,statsinfo->buff+off,size);
2884 }
2885 pthread_mutex_unlock(&(statsinfo->lock)); // make helgrind happy
2886 } else {
2887 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (no data)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
2888 fuse_reply_buf(req,NULL,0);
2889 }
2890 return;
2891 }
2892 if (ino==MOOSE_INODE) {
2893 static char mooseascii[175] = {
2894 0x20, 0x5C, 0x5F, 0x5C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2895 0x2F, 0x5F, 0x2F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5C, 0x5F, 0x5C, 0x5F, 0x20, 0x20, 0x20, 0x20,
2896 0x5F, 0x2F, 0x5F, 0x2F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5C, 0x2D, 0x2D,
2897 0x2F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x40, 0x40, 0x5C, 0x5F, 0x2D,
2898 0x2D, 0x5F, 0x5F, 0x5F, 0x5F, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5F, 0x5F,
2899 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
2900 0x20, 0x20, 0x20, 0x60, 0x60, 0x5C, 0x20, 0x20, 0x20, 0x20, 0x5F, 0x5F, 0x20, 0x20, 0x7C, 0x0A,
2901 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0x7C, 0x2D, 0x27, 0x20,
2902 0x20, 0x60, 0x7C, 0x7C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2903 0x7C, 0x7C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0x7C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2904 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x0A};
2905 uint32_t t = monotonic_useconds()%5000000;
2906 if (t<150000 || (t>=600000 && t<750000)) {
2907 mooseascii[59]='O';
2908 mooseascii[60]='O';
2909 } else if ((t>=150000 && t<300000) || (t>=450000 && t<600000)) {
2910 mooseascii[59]='O';
2911 mooseascii[60]='o';
2912 } else if (t>=300000 && t<450000) {
2913 mooseascii[59]='O';
2914 mooseascii[60]='-';
2915 } else {
2916 mooseascii[59]='O';
2917 mooseascii[60]='O';
2918 }
2919 if (off>=175) {
2920 fuse_reply_buf(req,NULL,0);
2921 } else if ((uint64_t)(off+size)>175) {
2922 fuse_reply_buf(req,mooseascii+off,175-off);
2923 } else {
2924 fuse_reply_buf(req,mooseascii+off,size);
2925 }
2926 return;
2927 }
2928 if (ino==OPLOG_INODE || ino==OPHISTORY_INODE) {
2929 oplog_getdata(fi->fh,&buff,&ssize,size);
2930 fuse_reply_buf(req,(char*)buff,ssize);
2931 oplog_releasedata(fi->fh);
2932 return;
2933 }
2934 /*
2935 if (ino==ATTRCACHE_INODE) {
2936 uint8_t info[2];
2937 info[0]=dir_cache_ison()+'0';
2938 if (info[0]!='0' && info[0]!='1') {
2939 info[0]='X';
2940 }
2941 info[1]='\n';
2942 if (off>2) {
2943 fuse_reply_buf(req,NULL,0);
2944 } else if (off+size>2) {
2945 fuse_reply_buf(req,(char*)(info+off),2-off);
2946 } else {
2947 fuse_reply_buf(req,(char*)(info+off),size);
2948 }
2949 return;
2950 }
2951 */
2952 if (fileinfo==NULL) {
2953 oplog_printf(&ctx,"read (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EBADF));
2954 fuse_reply_err(req,EBADF);
2955 return;
2956 }
2957 // if (ino==MASTER_INODE) {
2958 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
2959 // if (masterinfo->sent) {
2960 // int rsize;
2961 // buff = malloc(size);
2962 // rsize = fs_direct_read(masterinfo->sd,buff,size);
2963 // fuse_reply_buf(req,(char*)buff,rsize);
2964 // //syslog(LOG_WARNING,"master received: %d/%llu",rsize,(unsigned long long int)size);
2965 // free(buff);
2966 // } else {
2967 // syslog(LOG_WARNING,"master: read before write");
2968 // fuse_reply_buf(req,NULL,0);
2969 // }
2970 // return;
2971 // }
2972 if (off>=MAX_FILE_SIZE || off+size>=MAX_FILE_SIZE) {
2973 oplog_printf(&ctx,"read (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EFBIG));
2974 fuse_reply_err(req,EFBIG);
2975 return;
2976 }
2977 pthread_mutex_lock(&(fileinfo->lock));
2978 if (fileinfo->mode==IO_WRITEONLY) {
2979 pthread_mutex_unlock(&(fileinfo->lock));
2980 oplog_printf(&ctx,"read (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EACCES));
2981 fuse_reply_err(req,EACCES);
2982 return;
2983 }
2984 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2985 fileinfo->ops_in_progress++;
2986 #endif
2987 if (fileinfo->mode==IO_WRITE) {
2988 err = write_data_flush(fileinfo->data);
2989 if (err!=0) {
2990 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
2991 fileinfo->ops_in_progress--;
2992 fileinfo->lastuse = monotonic_seconds();
2993 #endif
2994 pthread_mutex_unlock(&(fileinfo->lock));
2995 if (debug_mode) {
2996 fprintf(stderr,"IO error occurred while writing inode %lu\n",(unsigned long int)ino);
2997 }
2998 oplog_printf(&ctx,"read (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(err));
2999 fuse_reply_err(req,err);
3000 return;
3001 }
3002 write_data_end(fileinfo->data);
3003 }
3004 if (fileinfo->mode==IO_WRITE || fileinfo->mode==IO_NONE) {
3005 fileinfo->mode = IO_READ;
3006 fileinfo->data = read_data_new(ino);
3007 }
3008 write_data_flush_inode(ino);
3009 /* stable version
3010 ssize = size;
3011 buff = NULL; // use internal 'readdata' buffer
3012 err = read_data(fileinfo->data,off,&ssize,&buff);
3013 */
3014 ssize = size;
3015 err = read_data(fileinfo->data,off,&ssize,&buffptr,&iov,&iovcnt);
3016
3017 if (err!=0) {
3018 if (debug_mode) {
3019 fprintf(stderr,"IO error occurred while reading inode %lu\n",(unsigned long int)ino);
3020 }
3021 oplog_printf(&ctx,"read (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(err));
3022 fuse_reply_err(req,err);
3023 } else {
3024 if (debug_mode) {
3025 fprintf(stderr,"%"PRIu32" bytes have been read from inode %lu\n",ssize,(unsigned long int)ino);
3026 }
3027 oplog_printf(&ctx,"read (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)ssize);
3028 // fuse_reply_buf(req,(char*)buff,ssize);
3029 fuse_reply_iov(req,iov,iovcnt);
3030 }
3031 // read_data_freebuff(fileinfo->data);
3032 read_data_free_buff(fileinfo->data,buffptr,iov);
3033 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3034 fileinfo->ops_in_progress--;
3035 fileinfo->lastuse = monotonic_seconds();
3036 #endif
3037 pthread_mutex_unlock(&(fileinfo->lock));
3038 }
3039
3040 void mfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
3041 finfo *fileinfo = (finfo*)(unsigned long)(fi->fh);
3042 int err;
3043 struct fuse_ctx ctx;
3044
3045 ctx = *(fuse_req_ctx(req));
3046 mfs_stats_inc(OP_WRITE);
3047 if (debug_mode) {
3048 oplog_printf(&ctx,"write (%lu,%llu,%llu) ...",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
3049 fprintf(stderr,"write to inode %lu %llu bytes at position %llu\n",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off);
3050 }
3051 if (ino==MASTERINFO_INODE || ino==OPLOG_INODE || ino==OPHISTORY_INODE || ino==MOOSE_INODE) {
3052 oplog_printf(&ctx,"write (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EACCES));
3053 fuse_reply_err(req,EACCES);
3054 return;
3055 }
3056 if (ino==STATS_INODE) {
3057 sinfo *statsinfo = (sinfo*)(unsigned long)(fi->fh);
3058 if (statsinfo!=NULL) {
3059 pthread_mutex_lock(&(statsinfo->lock)); // make helgrind happy
3060 statsinfo->reset=1;
3061 pthread_mutex_unlock(&(statsinfo->lock)); // make helgrind happy
3062 }
3063 oplog_printf(&ctx,"write (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)size);
3064 fuse_reply_write(req,size);
3065 return;
3066 }
3067 /*
3068 if (ino==ATTRCACHE_INODE) {
3069 if (off==0 && size>0 && buf[0]>='0' && buf[0]<='1') {
3070 dir_cache_user_switch(buf[0]-'0');
3071 newdircache = buf[0]-'0';
3072 }
3073 fuse_reply_write(req,size);
3074 return;
3075 }
3076 */
3077 if (fileinfo==NULL) {
3078 oplog_printf(&ctx,"write (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EBADF));
3079 fuse_reply_err(req,EBADF);
3080 return;
3081 }
3082 // if (ino==MASTER_INODE) {
3083 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
3084 // int wsize;
3085 // masterinfo->sent=1;
3086 // wsize = fs_direct_write(masterinfo->sd,(const uint8_t*)buf,size);
3087 // //syslog(LOG_WARNING,"master sent: %d/%llu",wsize,(unsigned long long int)size);
3088 // fuse_reply_write(req,wsize);
3089 // return;
3090 // }
3091 if (off>=MAX_FILE_SIZE || off+size>=MAX_FILE_SIZE) {
3092 oplog_printf(&ctx,"write (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EFBIG));
3093 fuse_reply_err(req, EFBIG);
3094 return;
3095 }
3096 pthread_mutex_lock(&(fileinfo->lock));
3097 if (fileinfo->mode==IO_READONLY) {
3098 pthread_mutex_unlock(&(fileinfo->lock));
3099 oplog_printf(&ctx,"write (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(EACCES));
3100 fuse_reply_err(req,EACCES);
3101 return;
3102 }
3103 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3104 fileinfo->ops_in_progress++;
3105 #endif
3106 if (fileinfo->mode==IO_READ) {
3107 read_data_end(fileinfo->data);
3108 }
3109 if (fileinfo->mode==IO_READ || fileinfo->mode==IO_NONE) {
3110 fileinfo->mode = IO_WRITE;
3111 fileinfo->data = write_data_new(ino);
3112 }
3113 err = write_data(fileinfo->data,off,size,(const uint8_t*)buf);
3114 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3115 fileinfo->ops_in_progress--;
3116 fileinfo->lastuse = monotonic_seconds();
3117 #endif
3118 if (err!=0) {
3119 pthread_mutex_unlock(&(fileinfo->lock));
3120 if (debug_mode) {
3121 fprintf(stderr,"IO error occurred while writing inode %lu\n",(unsigned long int)ino);
3122 }
3123 oplog_printf(&ctx,"write (%lu,%llu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,strerr(err));
3124 fuse_reply_err(req,err);
3125 } else {
3126 pthread_mutex_unlock(&(fileinfo->lock));
3127 if (debug_mode) {
3128 fprintf(stderr,"%llu bytes have been written to inode %lu\n",(unsigned long long int)size,(unsigned long int)ino);
3129 }
3130 oplog_printf(&ctx,"write (%lu,%llu,%llu): OK (%lu)",(unsigned long int)ino,(unsigned long long int)size,(unsigned long long int)off,(unsigned long int)size);
3131 read_inode_dirty_region(ino,off,size,buf);
3132 fuse_reply_write(req,size);
3133 }
3134 }
3135
3136 void mfs_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
3137 finfo *fileinfo = (finfo*)(unsigned long)(fi->fh);
3138 int err;
3139 struct fuse_ctx ctx;
3140
3141 ctx = *(fuse_req_ctx(req));
3142 mfs_stats_inc(OP_FLUSH);
3143 if (debug_mode) {
3144 oplog_printf(&ctx,"flush (%lu) ...",(unsigned long int)ino);
3145 fprintf(stderr,"flush (%lu)\n",(unsigned long int)ino);
3146 }
3147 if (IS_SPECIAL_INODE(ino)) {
3148 oplog_printf(&ctx,"flush (%lu): OK",(unsigned long int)ino);
3149 fuse_reply_err(req,0);
3150 return;
3151 }
3152 if (fileinfo==NULL) {
3153 oplog_printf(&ctx,"flush (%lu): %s",(unsigned long int)ino,strerr(EBADF));
3154 fuse_reply_err(req,EBADF);
3155 return;
3156 }
3157 // syslog(LOG_NOTICE,"remove_locks inode:%lu owner:%llu",(unsigned long int)ino,(unsigned long long int)fi->lock_owner);
3158 err = 0;
3159 // fuse_reply_err(req,err);
3160 pthread_mutex_lock(&(fileinfo->lock));
3161 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3162 fileinfo->ops_in_progress++;
3163 #endif
3164 if (fileinfo->mode==IO_WRITE || fileinfo->mode==IO_WRITEONLY) {
3165 err = write_data_flush(fileinfo->data);
3166 }
3167 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3168 fileinfo->ops_in_progress--;
3169 fileinfo->lastuse = monotonic_seconds();
3170 #endif
3171 pthread_mutex_unlock(&(fileinfo->lock));
3172 if (err!=0) {
3173 oplog_printf(&ctx,"flush (%lu): %s",(unsigned long int)ino,strerr(err));
3174 } else {
3175 dcache_invalidate_attr(ino);
3176 oplog_printf(&ctx,"flush (%lu): OK",(unsigned long int)ino);
3177 }
3178 fuse_reply_err(req,err);
3179 }
3180
3181 void mfs_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) {
3182 finfo *fileinfo = (finfo*)(unsigned long)(fi->fh);
3183 int err;
3184 struct fuse_ctx ctx;
3185
3186 ctx = *(fuse_req_ctx(req));
3187 mfs_stats_inc(OP_FSYNC);
3188 if (debug_mode) {
3189 oplog_printf(&ctx,"fsync (%lu,%d) ...",(unsigned long int)ino,datasync);
3190 fprintf(stderr,"fsync (%lu,%d)\n",(unsigned long int)ino,datasync);
3191 }
3192 if (IS_SPECIAL_INODE(ino)) {
3193 oplog_printf(&ctx,"fsync (%lu,%d): OK",(unsigned long int)ino,datasync);
3194 fuse_reply_err(req,0);
3195 return;
3196 }
3197 if (fileinfo==NULL) {
3198 oplog_printf(&ctx,"fsync (%lu,%d): %s",(unsigned long int)ino,datasync,strerr(EBADF));
3199 fuse_reply_err(req,EBADF);
3200 return;
3201 }
3202 err = 0;
3203 pthread_mutex_lock(&(fileinfo->lock));
3204 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3205 fileinfo->ops_in_progress++;
3206 #endif
3207 if (fileinfo->mode==IO_WRITE || fileinfo->mode==IO_WRITEONLY) {
3208 err = write_data_flush(fileinfo->data);
3209 }
3210 #ifdef FREEBSD_EARLY_RELEASE_BUG_WORKAROUND
3211 fileinfo->ops_in_progress--;
3212 fileinfo->lastuse = monotonic_seconds();
3213 #endif
3214 pthread_mutex_unlock(&(fileinfo->lock));
3215 if (err!=0) {
3216 oplog_printf(&ctx,"fsync (%lu,%d): %s",(unsigned long int)ino,datasync,strerr(err));
3217 } else {
3218 dcache_invalidate_attr(ino);
3219 oplog_printf(&ctx,"fsync (%lu,%d): OK",(unsigned long int)ino,datasync);
3220 }
3221 fuse_reply_err(req,err);
3222 }
3223
3224 // Linux ACL format:
3225 // version:8 (2)
3226 // flags:8 (0)
3227 // filler:16
3228 // N * [ tag:16 perm:16 id:32 ]
3229 // tag:
3230 // 01 - user
3231 // 02 - named user
3232 // 04 - group
3233 // 08 - named group
3234 // 10 - mask
3235 // 20 - other
3236
3237 int mfs_getacl(fuse_req_t req, fuse_ino_t ino, uint8_t opened,uint32_t uid,uint32_t gids,uint32_t *gid,uint8_t aclxattr,const uint8_t **buff,uint32_t *leng) {
3238 uint16_t userperm;
3239 uint16_t groupperm;
3240 uint16_t otherperm;
3241 uint16_t maskperm;
3242 uint16_t namedusers;
3243 uint16_t namedgroups;
3244 const uint8_t *namedacls;
3245 uint8_t *b;
3246 uint32_t namedaclssize;
3247 const uint8_t *p;
3248 uint32_t i;
3249 int status;
3250
3251 (void)req;
3252 *buff = NULL;
3253 *leng = 0;
3254 status = fs_getacl(ino,opened,uid,gids,gid,aclxattr,&userperm,&groupperm,&otherperm,&maskperm,&namedusers,&namedgroups,&namedacls,&namedaclssize);
3255
3256 if (status!=STATUS_OK) {
3257 return status;
3258 }
3259
3260 if (((namedusers+namedgroups)*6U) != namedaclssize) {
3261 return ERROR_EINVAL;
3262 }
3263
3264 *leng = 4+32+(namedusers+namedgroups)*8;
3265 b = mfs_aclstorage_get(4+32+(namedusers+namedgroups)*8);
3266 // fprintf(stderr,"getacl buff ptr: %p (size: %u)\n",(void*)b,4+32+(namedusers+namedgroups)*8);
3267 *buff = b;
3268 p = namedacls;
3269 b[0] = 2;
3270 b[1] = 0;
3271 b[2] = 0;
3272 b[3] = 0;
3273 b+=4;
3274 *(uint16_t*)(b) = 1;
3275 *(uint16_t*)(b+2) = userperm;
3276 *(uint32_t*)(b+4) = UINT32_C(0xFFFFFFFF);
3277 b+=8;
3278 for (i=0 ; i<namedusers ; i++) {
3279 *(uint32_t*)(b+4) = get32bit(&p);
3280 *(uint16_t*)(b) = 2;
3281 *(uint16_t*)(b+2) = get16bit(&p);
3282 b+=8;
3283 }
3284 *(uint16_t*)(b) = 4;
3285 *(uint16_t*)(b+2) = groupperm;
3286 *(uint32_t*)(b+4) = UINT32_C(0xFFFFFFFF);
3287 b+=8;
3288 for (i=0 ; i<namedgroups ; i++) {
3289 *(uint32_t*)(b+4) = get32bit(&p);
3290 *(uint16_t*)(b) = 8;
3291 *(uint16_t*)(b+2) = get16bit(&p);
3292 b+=8;
3293 }
3294 *(uint16_t*)(b) = 16;
3295 *(uint16_t*)(b+2) = maskperm;
3296 *(uint32_t*)(b+4) = UINT32_C(0xFFFFFFFF);
3297 b+=8;
3298 *(uint16_t*)(b) = 32;
3299 *(uint16_t*)(b+2) = otherperm;
3300 *(uint32_t*)(b+4) = UINT32_C(0xFFFFFFFF);
3301 b+=8;
3302 // fprintf(stderr,"getacl buff end ptr: %p\n",(void*)b);
3303 return STATUS_OK;
3304 }
3305
3306 int mfs_setacl(fuse_req_t req,fuse_ino_t ino,uint32_t uid,uint8_t aclxattr,const char *buff,uint32_t leng) {
3307 uint16_t userperm;
3308 uint16_t groupperm;
3309 uint16_t otherperm;
3310 uint16_t maskperm;
3311 uint16_t namedusers;
3312 uint16_t namedgroups;
3313 uint16_t acls;
3314 uint8_t *p,*namedacls;
3315 uint32_t i;
3316 uint16_t tag;
3317
3318 (void)req;
3319 if (leng<4 || ((leng % 8) != 4) ) {
3320 return ERROR_EINVAL;
3321 }
3322
3323 if (buff[0]!=2) {
3324 return ERROR_EINVAL;
3325 }
3326
3327 acls = (leng - 4) / 8;
3328 userperm = 0xFFFF; // means empty
3329 groupperm = 0xFFFF; // means empty
3330 otherperm = 0xFFFF; // means empty
3331 maskperm = 0xFFFF; // means no mask
3332 namedusers = 0;
3333 namedgroups = 0;
3334
3335 for (i=0 ; i<acls ; i++) {
3336 tag = *(const uint16_t*)(buff+4+i*8);
3337 if (tag & 1) {
3338 if (userperm!=0xFFFF) {
3339 return ERROR_EINVAL;
3340 }
3341 userperm = *(const uint16_t*)(buff+6+i*8);
3342 }
3343 if (tag & 2) {
3344 namedusers++;
3345 }
3346 if (tag & 4) {
3347 if (groupperm!=0xFFFF) {
3348 return ERROR_EINVAL;
3349 }
3350 groupperm = *(const uint16_t*)(buff+6+i*8);
3351 }
3352 if (tag & 8) {
3353 namedgroups++;
3354 }
3355 if (tag & 16) {
3356 if (maskperm!=0xFFFF) {
3357 return ERROR_EINVAL;
3358 }
3359 maskperm = *(const uint16_t*)(buff+6+i*8);
3360 }
3361 if (tag & 32) {
3362 if (otherperm!=0xFFFF) {
3363 return ERROR_EINVAL;
3364 }
3365 otherperm = *(const uint16_t*)(buff+6+i*8);
3366 }
3367 }
3368 if (maskperm==0xFFFF && (namedusers|namedgroups)>0) {
3369 return ERROR_EINVAL;
3370 }
3371
3372 namedacls = mfs_aclstorage_get((namedusers+namedgroups)*6);
3373 // fprintf(stderr,"namedacls ptr: %p (size: %u)\n",(void*)namedacls,(namedusers+namedgroups)*6);
3374 p = namedacls;
3375 for (i=0 ; i<acls ; i++) {
3376 tag = *(const uint16_t*)(buff+4+i*8);
3377 if (tag & 2) {
3378 put32bit(&p,*(const uint32_t*)(buff+8+i*8));
3379 put16bit(&p,*(const uint16_t*)(buff+6+i*8));
3380 }
3381 }
3382 for (i=0 ; i<acls ; i++) {
3383 tag = *(const uint16_t*)(buff+4+i*8);
3384 if (tag & 8) {
3385 put32bit(&p,*(const uint32_t*)(buff+8+i*8));
3386 put16bit(&p,*(const uint16_t*)(buff+6+i*8));
3387 }
3388 }
3389 // fprintf(stderr,"namedacls end ptr: %p\n",(void*)p);
3390 return fs_setacl(ino,uid,aclxattr,userperm,groupperm,otherperm,maskperm,namedusers,namedgroups,namedacls,(namedusers+namedgroups)*6);
3391 }
3392
3393 #if defined(__APPLE__)
3394 void mfs_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags, uint32_t position) {
3395 #else
3396 void mfs_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) {
3397 uint32_t position=0;
3398 #endif
3399 uint32_t nleng;
3400 int status;
3401 uint8_t mode;
3402 struct fuse_ctx ctx;
3403 groups *gids;
3404 uint8_t aclxattr;
3405
3406 ctx = *(fuse_req_ctx(req));
3407 mfs_stats_inc(OP_SETXATTR);
3408 if (debug_mode) {
3409 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d) ...",(unsigned long int)ino,name,(unsigned long long int)size,flags);
3410 fprintf(stderr,"setxattr (%lu,%s,%llu,%d)\n",(unsigned long int)ino,name,(unsigned long long int)size,flags);
3411 }
3412 if (IS_SPECIAL_INODE(ino)) {
3413 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(EPERM));
3414 fuse_reply_err(req,EPERM);
3415 return;
3416 }
3417 if (size>MFS_XATTR_SIZE_MAX) {
3418 #if defined(__APPLE__)
3419 // Mac OS X returns E2BIG here
3420 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(E2BIG));
3421 fuse_reply_err(req,E2BIG);
3422 #else
3423 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(ERANGE));
3424 fuse_reply_err(req,ERANGE);
3425 #endif
3426 return;
3427 }
3428 nleng = strlen(name);
3429 if (nleng>MFS_XATTR_NAME_MAX) {
3430 #if defined(__APPLE__)
3431 // Mac OS X returns EPERM here
3432 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(EPERM));
3433 fuse_reply_err(req,EPERM);
3434 #else
3435 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(ERANGE));
3436 fuse_reply_err(req,ERANGE);
3437 #endif
3438 return;
3439 }
3440 if (nleng==0) {
3441 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(EINVAL));
3442 fuse_reply_err(req,EINVAL);
3443 return;
3444 }
3445 #if defined(XATTR_CREATE) && defined(XATTR_REPLACE)
3446 if ((flags&XATTR_CREATE) && (flags&XATTR_REPLACE)) {
3447 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(EINVAL));
3448 fuse_reply_err(req,EINVAL);
3449 return;
3450 }
3451 mode = (flags==XATTR_CREATE)?MFS_XATTR_CREATE_ONLY:(flags==XATTR_REPLACE)?MFS_XATTR_REPLACE_ONLY:MFS_XATTR_CREATE_OR_REPLACE;
3452 #else
3453 mode = 0;
3454 #endif
3455 aclxattr = 0;
3456 if (strcmp(name,"system.posix_acl_access")==0) {
3457 aclxattr=1;
3458 } else if (strcmp(name,"system.posix_acl_default")==0) {
3459 aclxattr=2;
3460 }
3461 (void)position;
3462 if (xattr_cache_on) {
3463 xattr_cache_del(ino,nleng,(const uint8_t*)name);
3464 }
3465 if (aclxattr && xattr_acl_support==0) {
3466 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(ENOTSUP));
3467 fuse_reply_err(req,ENOTSUP);
3468 return;
3469 }
3470 if (aclxattr) {
3471 status = mfs_setacl(req,ino,ctx.uid,aclxattr,value,size);
3472 } else {
3473 if (full_permissions) {
3474 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
3475 status = fs_setxattr(ino,0,ctx.uid,gids->gidcnt,gids->gidtab,nleng,(const uint8_t*)name,(uint32_t)size,(const uint8_t*)value,mode);
3476 groups_rel(gids);
3477 } else {
3478 uint32_t gidtmp = ctx.gid;
3479 status = fs_setxattr(ino,0,ctx.uid,1,&gidtmp,nleng,(const uint8_t*)name,(uint32_t)size,(const uint8_t*)value,mode);
3480 }
3481 }
3482 status = mfs_errorconv(status);
3483 if (status!=0) {
3484 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): %s",(unsigned long int)ino,name,(unsigned long long int)size,flags,strerr(status));
3485 fuse_reply_err(req,status);
3486 return;
3487 }
3488 oplog_printf(&ctx,"setxattr (%lu,%s,%llu,%d): OK",(unsigned long int)ino,name,(unsigned long long int)size,flags);
3489 fuse_reply_err(req,0);
3490 }
3491
3492 #if defined(__APPLE__)
3493 void mfs_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size, uint32_t position) {
3494 #else
3495 void mfs_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) {
3496 uint32_t position=0;
3497 #endif /* __APPLE__ */
3498 uint32_t nleng;
3499 uint8_t attr[35];
3500 int status;
3501 uint8_t mode;
3502 const uint8_t *buff;
3503 uint32_t leng;
3504 struct fuse_ctx ctx;
3505 groups *gids;
3506 void *xattr_value_release;
3507 uint8_t aclxattr;
3508
3509 ctx = *(fuse_req_ctx(req));
3510 mfs_stats_inc(OP_GETXATTR);
3511 if (debug_mode) {
3512 oplog_printf(&ctx,"getxattr (%lu,%s,%llu) ...",(unsigned long int)ino,name,(unsigned long long int)size);
3513 fprintf(stderr,"getxattr (%lu,%s,%llu)\n",(unsigned long int)ino,name,(unsigned long long int)size);
3514 }
3515 if (IS_SPECIAL_INODE(ino)) {
3516 oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(EPERM));
3517 fuse_reply_err(req,EPERM);
3518 return;
3519 }
3520 // if (xattr_acl_support==0 && (strcmp(name,"system.posix_acl_default")==0 || strcmp(name,"system.posix_acl_access")==0)) {
3521 // oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(ENOTSUP));
3522 // fuse_reply_err(req,ENOTSUP);
3523 // return;
3524 // }
3525 nleng = strlen(name);
3526 if (nleng>MFS_XATTR_NAME_MAX) {
3527 #if defined(__APPLE__)
3528 // Mac OS X returns EPERM here
3529 oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(EPERM));
3530 fuse_reply_err(req,EPERM);
3531 #else
3532 oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(ERANGE));
3533 fuse_reply_err(req,ERANGE);
3534 #endif
3535 return;
3536 }
3537 if (nleng==0) {
3538 oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(EINVAL));
3539 fuse_reply_err(req,EINVAL);
3540 return;
3541 }
3542 if (size==0) {
3543 mode = MFS_XATTR_LENGTH_ONLY;
3544 } else {
3545 mode = MFS_XATTR_GETA_DATA;
3546 }
3547 aclxattr = 0;
3548 if (strcmp(name,"system.posix_acl_access")==0) {
3549 aclxattr=1;
3550 } else if (strcmp(name,"system.posix_acl_default")==0) {
3551 aclxattr=2;
3552 }
3553 if (aclxattr && xattr_acl_support==0) {
3554 oplog_printf(&ctx,"getxattr (%lu,%s,%llu): %s",(unsigned long int)ino,name,(unsigned long long int)size,strerr(ENOTSUP));
3555 fuse_reply_err(req,ENOTSUP);
3556 return;
3557 }
3558 (void)position;
3559 gids = NULL; // make gcc happy
3560 if (full_permissions) {
3561 if (strcmp(name,"com.apple.quarantine")==0) {
3562 gids = groups_get_x(ctx.pid,ctx.uid,ctx.gid,1);
3563 } else {
3564 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
3565 }
3566 }
3567 xattr_value_release = NULL;
3568 if (xattr_cache_on) {
3569 xattr_value_release = xattr_cache_get(ino,ctx.uid,ctx.gid,nleng,(const uint8_t*)name,&buff,&leng,&status);
3570 if (xattr_value_release==NULL) {
3571 if (usedircache && dcache_getattr(&ctx,ino,attr) && (mfs_attr_get_mattr(attr)&MATTR_NOXATTR)) { // no xattr
3572 status = ERROR_ENOATTR;
3573 buff = NULL;
3574 leng = 0;
3575 } else {
3576 if (aclxattr) {
3577 if (full_permissions) {
3578 status = mfs_getacl(req,ino,0,ctx.uid,gids->gidcnt,gids->gidtab,aclxattr,&buff,&leng);
3579 } else {
3580 uint32_t gidtmp = ctx.gid;
3581 status = mfs_getacl(req,ino,0,ctx.uid,1,&gidtmp,aclxattr,&buff,&leng);
3582 }
3583 } else {
3584 if (full_permissions) {
3585 status = fs_getxattr(ino,0,ctx.uid,gids->gidcnt,gids->gidtab,nleng,(const uint8_t*)name,MFS_XATTR_GETA_DATA,&buff,&leng);
3586 } else {
3587 uint32_t gidtmp = ctx.gid;
3588 status = fs_getxattr(ino,0,ctx.uid,1,&gidtmp,nleng,(const uint8_t*)name,MFS_XATTR_GETA_DATA,&buff,&leng);
3589 }
3590 }
3591 }
3592 xattr_cache_set(ino,ctx.uid,ctx.gid,nleng,(const uint8_t*)name,buff,leng,status);
3593 } else if (debug_mode) {
3594 fprintf(stderr,"getxattr: sending data from cache\n");
3595 }
3596 } else {
3597 if (usedircache && dcache_getattr(&ctx,ino,attr) && (mfs_attr_get_mattr(attr)&MATTR_NOXATTR)) { // no xattr
3598 status = ERROR_ENOATTR;
3599 buff = NULL;
3600 leng = 0;
3601 } else {
3602 if (aclxattr) {
3603 if (full_permissions) {
3604 status = mfs_getacl(req,ino,0,ctx.uid,gids->gidcnt,gids->gidtab,aclxattr,&buff,&leng);
3605 } else {
3606 uint32_t gidtmp = ctx.gid;
3607 status = mfs_getacl(req,ino,0,ctx.uid,1,&gidtmp,aclxattr,&buff,&leng);
3608 }
3609 } else {
3610 if (full_permissions) {
3611 status = fs_getxattr(ino,0,ctx.uid,gids->gidcnt,gids->gidtab,nleng,(const uint8_t*)name,mode,&buff,&leng);
3612 } else {
3613 uint32_t gidtmp = ctx.gid;
3614 status = fs_getxattr(ino,0,ctx.uid,1,&gidtmp,nleng,(const uint8_t*)name,mode,&buff,&leng);
3615 }
3616 }
3617 }
3618 }
3619 if (full_permissions) {
3620 groups_rel(gids);
3621 }
3622 status = mfs_errorconv(status);
3623 if (status!=0) {
3624 oplog_printf(&ctx,"getxattr (%lu,%s,%llu)%s: %s",(unsigned long int)ino,name,(unsigned long long int)size,(xattr_value_release==NULL)?"":" (using cache)",strerr(status));
3625 fuse_reply_err(req,status);
3626 if (xattr_value_release!=NULL) {
3627 xattr_cache_rel(xattr_value_release);
3628 }
3629 return;
3630 }
3631 if (size==0) {
3632 oplog_printf(&ctx,"getxattr (%lu,%s,%llu)%s: OK (%"PRIu32")",(unsigned long int)ino,name,(unsigned long long int)size,(xattr_value_release==NULL)?"":" (using cache)",leng);
3633 fuse_reply_xattr(req,leng);
3634 } else {
3635 if (leng>size) {
3636 oplog_printf(&ctx,"getxattr (%lu,%s,%llu)%s: %s",(unsigned long int)ino,name,(unsigned long long int)size,(xattr_value_release==NULL)?"":" (using cache)",strerr(ERANGE));
3637 fuse_reply_err(req,ERANGE);
3638 } else {
3639 oplog_printf(&ctx,"getxattr (%lu,%s,%llu)%s: OK (%"PRIu32")",(unsigned long int)ino,name,(unsigned long long int)size,(xattr_value_release==NULL)?"":" (using cache)",leng);
3640 fuse_reply_buf(req,(const char*)buff,leng);
3641 }
3642 }
3643 if (xattr_value_release!=NULL) {
3644 xattr_cache_rel(xattr_value_release);
3645 }
3646 }
3647
3648 void mfs_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) {
3649 const uint8_t *buff;
3650 uint32_t leng;
3651 uint8_t attr[35];
3652 int status;
3653 uint8_t mode;
3654 struct fuse_ctx ctx;
3655 groups *gids;
3656
3657 ctx = *(fuse_req_ctx(req));
3658 mfs_stats_inc(OP_LISTXATTR);
3659 if (debug_mode) {
3660 oplog_printf(&ctx,"listxattr (%lu,%llu) ...",(unsigned long int)ino,(unsigned long long int)size);
3661 fprintf(stderr,"listxattr (%lu,%llu)\n",(unsigned long int)ino,(unsigned long long int)size);
3662 }
3663 if (IS_SPECIAL_INODE(ino)) {
3664 oplog_printf(&ctx,"listxattr (%lu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,strerr(EPERM));
3665 fuse_reply_err(req,EPERM);
3666 return;
3667 }
3668 if (size==0) {
3669 mode = MFS_XATTR_LENGTH_ONLY;
3670 } else {
3671 mode = MFS_XATTR_GETA_DATA;
3672 }
3673 if (usedircache && dcache_getattr(&ctx,ino,attr) && (mfs_attr_get_mattr(attr)&MATTR_NOXATTR)) { // no xattr
3674 status = STATUS_OK;
3675 buff = NULL;
3676 leng = 0;
3677 } else {
3678 if (full_permissions) {
3679 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
3680 status = fs_listxattr(ino,0,ctx.uid,gids->gidcnt,gids->gidtab,mode,&buff,&leng);
3681 groups_rel(gids);
3682 } else {
3683 uint32_t gidtmp = ctx.gid;
3684 status = fs_listxattr(ino,0,ctx.uid,1,&gidtmp,mode,&buff,&leng);
3685 }
3686 }
3687 status = mfs_errorconv(status);
3688 if (status!=0) {
3689 oplog_printf(&ctx,"listxattr (%lu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,strerr(status));
3690 fuse_reply_err(req,status);
3691 return;
3692 }
3693 if (size==0) {
3694 oplog_printf(&ctx,"listxattr (%lu,%llu): OK (%"PRIu32")",(unsigned long int)ino,(unsigned long long int)size,leng);
3695 fuse_reply_xattr(req,leng);
3696 } else {
3697 if (leng>size) {
3698 oplog_printf(&ctx,"listxattr (%lu,%llu): %s",(unsigned long int)ino,(unsigned long long int)size,strerr(ERANGE));
3699 fuse_reply_err(req,ERANGE);
3700 } else {
3701 oplog_printf(&ctx,"listxattr (%lu,%llu): OK (%"PRIu32")",(unsigned long int)ino,(unsigned long long int)size,leng);
3702 fuse_reply_buf(req,(const char*)buff,leng);
3703 }
3704 }
3705 }
3706
3707 void mfs_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) {
3708 uint32_t nleng;
3709 int status;
3710 struct fuse_ctx ctx;
3711 groups *gids;
3712 uint8_t aclxattr;
3713
3714 ctx = *(fuse_req_ctx(req));
3715 mfs_stats_inc(OP_REMOVEXATTR);
3716 if (debug_mode) {
3717 oplog_printf(&ctx,"removexattr (%lu,%s) ...",(unsigned long int)ino,name);
3718 fprintf(stderr,"removexattr (%lu,%s)\n",(unsigned long int)ino,name);
3719 }
3720 if (IS_SPECIAL_INODE(ino)) {
3721 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(EPERM));
3722 fuse_reply_err(req,EPERM);
3723 return;
3724 }
3725 aclxattr = 0;
3726 if (strcmp(name,"system.posix_acl_access")==0) {
3727 aclxattr=1;
3728 } else if (strcmp(name,"system.posix_acl_default")==0) {
3729 aclxattr=2;
3730 }
3731 if (aclxattr && xattr_acl_support==0) {
3732 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(ENOTSUP));
3733 fuse_reply_err(req,ENOTSUP);
3734 return;
3735 }
3736 nleng = strlen(name);
3737 if (nleng>MFS_XATTR_NAME_MAX) {
3738 #if defined(__APPLE__)
3739 // Mac OS X returns EPERM here
3740 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(EPERM));
3741 fuse_reply_err(req,EPERM);
3742 #else
3743 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(ERANGE));
3744 fuse_reply_err(req,ERANGE);
3745 #endif
3746 return;
3747 }
3748 if (nleng==0) {
3749 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(EINVAL));
3750 fuse_reply_err(req,EINVAL);
3751 return;
3752 }
3753 if (xattr_cache_on) {
3754 xattr_cache_del(ino,nleng,(const uint8_t*)name);
3755 }
3756 if (aclxattr) {
3757 status = fs_setacl(ino,ctx.uid,aclxattr,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0,0,NULL,0);
3758 } else {
3759 if (full_permissions) {
3760 gids = groups_get(ctx.pid,ctx.uid,ctx.gid);
3761 status = fs_removexattr(ino,0,ctx.uid,gids->gidcnt,gids->gidtab,nleng,(const uint8_t*)name);
3762 groups_rel(gids);
3763 } else {
3764 uint32_t gidtmp = ctx.gid;
3765 status = fs_removexattr(ino,0,ctx.uid,1,&gidtmp,nleng,(const uint8_t*)name);
3766 }
3767 }
3768 status = mfs_errorconv(status);
3769 if (status!=0) {
3770 oplog_printf(&ctx,"removexattr (%lu,%s): %s",(unsigned long int)ino,name,strerr(status));
3771 fuse_reply_err(req,status);
3772 } else {
3773 oplog_printf(&ctx,"removexattr (%lu,%s): OK",(unsigned long int)ino,name);
3774 fuse_reply_err(req,0);
3775 }
3776 }
3777
3778 void mfs_init(int debug_mode_in,int keep_cache_in,double direntry_cache_timeout_in,double entry_cache_timeout_in,double attr_cache_timeout_in,double xattr_cache_timeout_in,double groups_cache_timeout,int mkdir_copy_sgid_in,int sugid_clear_mode_in,int xattr_acl_support_in) {
3779 const char* sugid_clear_mode_strings[] = {SUGID_CLEAR_MODE_STRINGS};
3780 debug_mode = debug_mode_in;
3781 keep_cache = keep_cache_in;
3782 direntry_cache_timeout = direntry_cache_timeout_in;
3783 entry_cache_timeout = entry_cache_timeout_in;
3784 attr_cache_timeout = attr_cache_timeout_in;
3785 mkdir_copy_sgid = mkdir_copy_sgid_in;
3786 sugid_clear_mode = sugid_clear_mode_in;
3787 xattr_cache_init(xattr_cache_timeout_in);
3788 xattr_cache_on = (xattr_cache_timeout_in>0.0)?1:0;
3789 xattr_acl_support = xattr_acl_support_in;
3790 if (groups_cache_timeout>0.0) {
3791 groups_init(groups_cache_timeout,debug_mode);
3792 full_permissions = 1;
3793 } else {
3794 full_permissions = 0;
3795 }
3796 mfs_aclstorage_init();
3797 if (debug_mode) {
3798 fprintf(stderr,"cache parameters: file_keep_cache=%s direntry_cache_timeout=%.2lf entry_cache_timeout=%.2lf attr_cache_timeout=%.2lf xattr_cache_timeout_in=%.2lf (%s)\n",(keep_cache==1)?"always":(keep_cache==2)?"never":"auto",direntry_cache_timeout,entry_cache_timeout,attr_cache_timeout,xattr_cache_timeout_in,xattr_cache_on?"on":"off");
3799 fprintf(stderr,"mkdir copy sgid=%d\nsugid clear mode=%s\n",mkdir_copy_sgid_in,(sugid_clear_mode_in<SUGID_CLEAR_MODE_OPTIONS)?sugid_clear_mode_strings[sugid_clear_mode_in]:"???");
3800 }
3801 mfs_statsptr_init();
3802 }
3803