1 /*
2 * Copyright (C) 2021 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 // patch for old osxfuse
22 //#if defined(__APPLE__)
23 //# if ! defined(__DARWIN_64_BIT_INO_T) && ! defined(_DARWIN_USE_64_BIT_INODE)
24 //# define __DARWIN_64_BIT_INO_T 0
25 //# endif
26 //#endif
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "fusecommon.h"
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <syslog.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <pthread.h>
41
42 #include "datapack.h"
43 #include "mastercomm.h"
44 #include "masterproxy.h"
45 #include "MFSCommunication.h"
46
47 #define READDIR_BUFFSIZE 50000
48
49 //typedef struct _minfo {
50 // int sd;
51 // int sent;
52 //} minfo;
53 typedef struct _dirbuf {
54 int wasread;
55 uint8_t *p;
56 size_t size;
57 pthread_mutex_t lock;
58 } dirbuf;
59
60 typedef struct _pathbuf {
61 int changed;
62 char *p;
63 size_t size;
64 pthread_mutex_t lock;
65 } pathbuf;
66
67 #define NAME_MAX 255
68 #define PATH_SIZE_LIMIT 1024
69
70 #define META_ROOT_INODE FUSE_ROOT_ID
71 #define META_ROOT_MODE 0555
72
73 #define META_SUBTRASH_INODE_MIN 0x7FFF0000
74 #define META_SUBTRASH_INODE_MAX ((0x7FFF0000+TRASH_BUCKETS)-1)
75 #define META_SUBTRASH_MODE 0700
76
77 #define META_TRASH_INODE 0x7FFFFFF8
78 #define META_TRASH_MODE 0700
79 #define META_TRASH_NAME "trash"
80 #define META_UNDEL_INODE 0x7FFFFFF9
81 #define META_UNDEL_MODE 0200
82 #define META_UNDEL_NAME "undel"
83 #define META_SUSTAINED_INODE 0x7FFFFFFA
84 #define META_SUSTAINED_MODE 0500
85 #define META_SUSTAINED_NAME "sustained"
86
87 //#define META_INODE_MIN META_ROOT_INODE
88 //#define META_INODE_MAX META_SUSTAINED_INODE
89
90 //#define INODE_VALUE_MASK 0x1FFFFFFF
91 //#define INODE_TYPE_MASK 0x60000000
92 //#define INODE_TYPE_TRASH 0x20000000
93 //#define INODE_TYPE_SUSTAINED 0x40000000
94 //#define INODE_TYPE_SPECIAL 0x00000000
95
96 // standard fs - inode(.master)=0x7FFFFFFF / inode(.masterinfo)=0x7FFFFFFE
97 // meta fs - inode(.master)=0x7FFFFFFE / inode(.masterinfo)=0x7FFFFFFF
98 //#define MASTER_NAME ".master"
99 //#define MASTER_INODE 0x7FFFFFFE
100 // 0x01b6 = 0666
101 //static uint8_t masterattr[ATTR_RECORD_SIZE]={'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};
102
103 #define MASTERINFO_WITH_VERSION 1
104
105 #define MASTERINFO_NAME ".masterinfo"
106 #define MASTERINFO_INODE 0x7FFFFFFF
107 // 0x0124 = 0444
108 #ifdef MASTERINFO_WITH_VERSION
109 static uint8_t masterinfoattr[ATTR_RECORD_SIZE]={'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};
110 #else
111 static uint8_t masterinfoattr[ATTR_RECORD_SIZE]={'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};
112 #endif
113
114 #define MIN_SPECIAL_INODE 0x7FFF0000
115 #define IS_SPECIAL_INODE(ino) ((ino)>=MIN_SPECIAL_INODE || (ino)==META_ROOT_INODE)
116
117 // info - todo
118 //#define META_INFO_INODE 0x7FFFFFFD
119 //#define META_INFO_NAME "info"
120
121 #define PKGVERSION ((VERSMAJ)*1000000+(VERSMID)*1000+(VERSMIN))
122
123 static int debug_mode = 0;
124 static int flat_trash = 0;
125 static double entry_cache_timeout = 0.0;
126 static double attr_cache_timeout = 1.0;
127
mfs_meta_name_to_inode(const char * name)128 uint32_t mfs_meta_name_to_inode(const char *name) {
129 uint32_t inode=0;
130 char *end;
131 inode = strtoul(name,&end,16);
132 if (*end=='|' && end[1]!=0) {
133 return inode;
134 } else {
135 return 0;
136 }
137 }
138
mfs_errorconv(int status)139 static int mfs_errorconv(int status) {
140 switch (status) {
141 case MFS_STATUS_OK:
142 return 0;
143 case MFS_ERROR_EPERM:
144 return EPERM;
145 case MFS_ERROR_ENOTDIR:
146 return ENOTDIR;
147 case MFS_ERROR_ENOENT:
148 return ENOENT;
149 case MFS_ERROR_EACCES:
150 return EACCES;
151 case MFS_ERROR_EEXIST:
152 return EEXIST;
153 case MFS_ERROR_EINVAL:
154 return EINVAL;
155 case MFS_ERROR_ENOTEMPTY:
156 return ENOTEMPTY;
157 case MFS_ERROR_IO:
158 return EIO;
159 case MFS_ERROR_EROFS:
160 return EROFS;
161 case MFS_ERROR_QUOTA:
162 #ifdef EDQUOT
163 return EDQUOT;
164 #else
165 return ENOSPC;
166 #endif
167 default:
168 return EINVAL;
169 }
170 }
171
fsnodes_type_convert(uint8_t type)172 static inline uint8_t fsnodes_type_convert(uint8_t type) {
173 switch (type) {
174 case DISP_TYPE_FILE:
175 return TYPE_FILE;
176 case DISP_TYPE_DIRECTORY:
177 return TYPE_DIRECTORY;
178 case DISP_TYPE_SYMLINK:
179 return TYPE_SYMLINK;
180 case DISP_TYPE_FIFO:
181 return TYPE_FIFO;
182 case DISP_TYPE_BLOCKDEV:
183 return TYPE_BLOCKDEV;
184 case DISP_TYPE_CHARDEV:
185 return TYPE_CHARDEV;
186 case DISP_TYPE_SOCKET:
187 return TYPE_SOCKET;
188 case DISP_TYPE_TRASH:
189 return TYPE_TRASH;
190 case DISP_TYPE_SUSTAINED:
191 return TYPE_SUSTAINED;
192 }
193 return 0;
194 }
195
mfs_meta_type_to_stat(uint32_t inode,uint8_t type,struct stat * stbuf)196 static void mfs_meta_type_to_stat(uint32_t inode,uint8_t type, struct stat *stbuf) {
197 memset(stbuf,0,sizeof(struct stat));
198 stbuf->st_ino = inode;
199 switch (type&0x7F) {
200 case DISP_TYPE_DIRECTORY:
201 case TYPE_DIRECTORY:
202 stbuf->st_mode = S_IFDIR;
203 break;
204 case DISP_TYPE_SYMLINK:
205 case TYPE_SYMLINK:
206 stbuf->st_mode = S_IFLNK;
207 break;
208 case DISP_TYPE_FILE:
209 case TYPE_FILE:
210 stbuf->st_mode = S_IFREG;
211 break;
212 case DISP_TYPE_FIFO:
213 case TYPE_FIFO:
214 stbuf->st_mode = S_IFIFO;
215 break;
216 case DISP_TYPE_SOCKET:
217 case TYPE_SOCKET:
218 stbuf->st_mode = S_IFSOCK;
219 break;
220 case DISP_TYPE_BLOCKDEV:
221 case TYPE_BLOCKDEV:
222 stbuf->st_mode = S_IFBLK;
223 break;
224 case DISP_TYPE_CHARDEV:
225 case TYPE_CHARDEV:
226 stbuf->st_mode = S_IFCHR;
227 break;
228 default:
229 stbuf->st_mode = 0;
230 }
231 }
232
233
mfs_meta_stat(uint32_t inode,struct stat * stbuf)234 static void mfs_meta_stat(uint32_t inode, struct stat *stbuf) {
235 int now;
236 stbuf->st_ino = inode;
237 stbuf->st_size = 0;
238 //#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
239 // stbuf->st_blocks = 0;
240 //#endif
241 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
242 stbuf->st_blksize = MFSBLOCKSIZE;
243 #endif
244 switch (inode) {
245 case META_ROOT_INODE:
246 stbuf->st_nlink = 4;
247 stbuf->st_mode = S_IFDIR | META_ROOT_MODE ;
248 break;
249 case META_TRASH_INODE:
250 stbuf->st_nlink = 3+TRASH_BUCKETS;
251 stbuf->st_mode = S_IFDIR | META_TRASH_MODE ;
252 break;
253 case META_UNDEL_INODE:
254 stbuf->st_nlink = 2+TRASH_BUCKETS;
255 stbuf->st_mode = S_IFDIR | META_UNDEL_MODE ;
256 break;
257 case META_SUSTAINED_INODE:
258 stbuf->st_nlink = 2;
259 stbuf->st_mode = S_IFDIR | META_SUSTAINED_MODE ;
260 break;
261 default:
262 if (inode>=META_SUBTRASH_INODE_MIN && inode<=META_SUBTRASH_INODE_MAX) {
263 stbuf->st_nlink = 3;
264 stbuf->st_mode = S_IFDIR | META_SUBTRASH_MODE ;
265 }
266 }
267 stbuf->st_uid = 0;
268 stbuf->st_gid = 0;
269 now = time(NULL);
270 stbuf->st_atime = now;
271 stbuf->st_mtime = now;
272 stbuf->st_ctime = now;
273 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
274 stbuf->st_birthtime = now; // for future use
275 #endif
276 }
277
278 /*
279 static void mfs_inode_to_stat(uint32_t inode, struct stat *stbuf) {
280 memset(stbuf,0,sizeof(struct stat));
281 stbuf->st_ino = inode;
282 stbuf->st_mode = S_IFREG;
283 }
284 */
285
mfs_attr_to_stat(uint32_t inode,const uint8_t attr[ATTR_RECORD_SIZE],struct stat * stbuf)286 static void mfs_attr_to_stat(uint32_t inode,const uint8_t attr[ATTR_RECORD_SIZE], struct stat *stbuf) {
287 uint16_t attrmode;
288 uint8_t attrtype;
289 uint32_t attruid,attrgid,attratime,attrmtime,attrctime,attrnlink;
290 uint64_t attrlength;
291 const uint8_t *ptr;
292 ptr = attr;
293 if (attr[0]<64) { // 1.7.29 and up
294 ptr++;
295 attrmode = get16bit(&ptr);
296 attrtype = (attrmode>>12);
297 } else {
298 attrtype = get8bit(&ptr);
299 attrtype = fsnodes_type_convert(attrtype&0x7F);
300 attrmode = get16bit(&ptr);
301 }
302 attrmode &= 0x0FFF;
303 attruid = get32bit(&ptr);
304 attrgid = get32bit(&ptr);
305 attratime = get32bit(&ptr);
306 attrmtime = get32bit(&ptr);
307 attrctime = get32bit(&ptr);
308 attrnlink = get32bit(&ptr);
309 attrlength = get64bit(&ptr);
310 stbuf->st_ino = inode;
311 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
312 stbuf->st_blksize = MFSBLOCKSIZE;
313 #endif
314 if (attrtype==TYPE_FILE || attrtype==TYPE_TRASH || attrtype==TYPE_SUSTAINED) {
315 stbuf->st_mode = S_IFREG | ( attrmode & 07777);
316 } else {
317 stbuf->st_mode = 0;
318 }
319 stbuf->st_size = attrlength;
320 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
321 stbuf->st_blocks = (attrlength+511)/512;
322 #endif
323 stbuf->st_uid = attruid;
324 stbuf->st_gid = attrgid;
325 stbuf->st_atime = attratime;
326 stbuf->st_mtime = attrmtime;
327 stbuf->st_ctime = attrctime;
328 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
329 stbuf->st_birthtime = attrctime; // for future use
330 #endif
331 stbuf->st_nlink = attrnlink;
332 }
333
334 #if FUSE_USE_VERSION >= 26
mfs_meta_statfs(fuse_req_t req,fuse_ino_t ino)335 void mfs_meta_statfs(fuse_req_t req, fuse_ino_t ino) {
336 #else
337 void mfs_meta_statfs(fuse_req_t req) {
338 #endif
339 uint64_t totalspace,availspace,freespace,trashspace,sustainedspace;
340 uint32_t inodes;
341 struct statvfs stfsbuf;
342 memset(&stfsbuf,0,sizeof(stfsbuf));
343
344 #if FUSE_USE_VERSION >= 26
345 (void)ino;
346 #endif
347 fs_statfs(&totalspace,&availspace,&freespace,&trashspace,&sustainedspace,&inodes);
348
349 stfsbuf.f_namemax = NAME_MAX;
350 stfsbuf.f_frsize = MFSBLOCKSIZE;
351 stfsbuf.f_bsize = MFSBLOCKSIZE;
352 stfsbuf.f_blocks = trashspace/MFSBLOCKSIZE+sustainedspace/MFSBLOCKSIZE;
353 stfsbuf.f_bfree = sustainedspace/MFSBLOCKSIZE;
354 stfsbuf.f_bavail = sustainedspace/MFSBLOCKSIZE;
355 stfsbuf.f_files = 1000000000+PKGVERSION;
356 stfsbuf.f_ffree = 1000000000+PKGVERSION;
357 stfsbuf.f_favail = 1000000000+PKGVERSION;
358
359 fuse_reply_statfs(req,&stfsbuf);
360 }
361
362 /*
363 void mfs_meta_access(fuse_req_t req, fuse_ino_t ino, int mask) {
364 const struct fuse_ctx *ctx;
365 ctx = fuse_req_ctx(req);
366 switch (ino) {
367 case FUSE_ROOT_ID:
368 if (mask & W_OK) {
369 fuse_reply_err(req,EACCES);
370 return;
371 }
372 break;
373 case META_TRASH_INODE:
374 if (mask & W_OK && ctx->uid!=0) {
375 fuse_reply_err(req,EACCES);
376 return;
377 }
378 break;
379 case META_UNDEL_INODE:
380 if (mask & (R_OK|X_OK)) {
381 fuse_reply_err(req,EACCES);
382 return;
383 }
384 break;
385 }
386 fuse_reply_err(req,0);
387 }
388 */
389
390 void mfs_meta_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) {
391 struct fuse_entry_param e;
392 uint32_t inode;
393 // const struct fuse_ctx *ctx;
394 // ctx = fuse_req_ctx(req);
395 memset(&e, 0, sizeof(e));
396 inode = 0;
397 switch (parent) {
398 case META_ROOT_INODE:
399 if (strcmp(name,".")==0 || strcmp(name,"..")==0) {
400 inode = META_ROOT_INODE;
401 } else if (strcmp(name,META_TRASH_NAME)==0) {
402 inode = META_TRASH_INODE;
403 } else if (strcmp(name,META_SUSTAINED_NAME)==0) {
404 inode = META_SUSTAINED_INODE;
405 // } else if (strcmp(name,MASTER_NAME)==0) {
406 // memset(&e, 0, sizeof(e));
407 // e.ino = MASTER_INODE;
408 // e.attr_timeout = 3600.0;
409 // e.entry_timeout = 3600.0;
410 // mfs_attr_to_stat(MASTER_INODE,masterattr,&e.attr);
411 // fuse_reply_entry(req, &e);
412 // return ;
413 } else if (strcmp(name,MASTERINFO_NAME)==0) {
414 memset(&e, 0, sizeof(e));
415 e.ino = MASTERINFO_INODE;
416 e.attr_timeout = 3600.0;
417 e.entry_timeout = 3600.0;
418 mfs_attr_to_stat(MASTERINFO_INODE,masterinfoattr,&e.attr);
419 fuse_reply_entry(req, &e);
420 return ;
421 }
422 break;
423 case META_TRASH_INODE:
424 if (strcmp(name,".")==0) {
425 inode = META_TRASH_INODE;
426 } else if (strcmp(name,"..")==0) {
427 inode = META_ROOT_INODE;
428 } else if (strcmp(name,META_UNDEL_NAME)==0) {
429 inode = META_UNDEL_INODE;
430 } else if (master_version()>=VERSION2INT(3,0,64) && flat_trash==0) { // subtrashes
431 inode = strtoul(name,NULL,16);
432 if (inode<TRASH_BUCKETS) {
433 inode += META_SUBTRASH_INODE_MIN;
434 } else {
435 inode = 0;
436 }
437 } else { // flat trash
438 inode = mfs_meta_name_to_inode(name);
439 if (inode>0) {
440 int status;
441 uint8_t attr[ATTR_RECORD_SIZE];
442 status = fs_getdetachedattr(inode,attr);
443 status = mfs_errorconv(status);
444 if (status!=0) {
445 fuse_reply_err(req, status);
446 } else {
447 e.ino = inode;
448 e.attr_timeout = attr_cache_timeout;
449 e.entry_timeout = entry_cache_timeout;
450 mfs_attr_to_stat(inode,attr,&e.attr);
451 fuse_reply_entry(req,&e);
452 }
453 return;
454 }
455 }
456 break;
457 case META_UNDEL_INODE:
458 if (strcmp(name,".")==0) {
459 inode = META_UNDEL_INODE;
460 } else if (strcmp(name,"..")==0) {
461 inode = META_TRASH_INODE;
462 }
463 break;
464 case META_SUSTAINED_INODE:
465 if (strcmp(name,".")==0) {
466 inode = META_SUSTAINED_INODE;
467 } else if (strcmp(name,"..")==0) {
468 inode = META_ROOT_INODE;
469 } else {
470 inode = mfs_meta_name_to_inode(name);
471 if (inode>0) {
472 int status;
473 uint8_t attr[ATTR_RECORD_SIZE];
474 status = fs_getdetachedattr(inode,attr);
475 status = mfs_errorconv(status);
476 if (status!=0) {
477 fuse_reply_err(req, status);
478 } else {
479 e.ino = inode;
480 e.attr_timeout = attr_cache_timeout;
481 e.entry_timeout = entry_cache_timeout;
482 mfs_attr_to_stat(inode,attr,&e.attr);
483 fuse_reply_entry(req,&e);
484 }
485 return;
486 }
487 }
488 break;
489 default:
490 if (parent>=META_SUBTRASH_INODE_MIN && parent<=META_SUBTRASH_INODE_MAX) {
491 if (strcmp(name,".")==0) {
492 inode = parent;
493 } else if (strcmp(name,"..")==0) {
494 inode = META_TRASH_INODE;
495 } else if (strcmp(name,META_UNDEL_NAME)==0) {
496 inode = META_UNDEL_INODE;
497 } else {
498 inode = mfs_meta_name_to_inode(name);
499 if (inode>0) {
500 int status;
501 uint8_t attr[ATTR_RECORD_SIZE];
502 status = fs_getdetachedattr(inode,attr);
503 status = mfs_errorconv(status);
504 if (status!=0) {
505 fuse_reply_err(req, status);
506 } else {
507 e.ino = inode;
508 e.attr_timeout = attr_cache_timeout;
509 e.entry_timeout = entry_cache_timeout;
510 mfs_attr_to_stat(inode,attr,&e.attr);
511 fuse_reply_entry(req,&e);
512 }
513 return;
514 }
515 }
516 }
517 }
518 if (inode==0) {
519 fuse_reply_err(req,ENOENT);
520 } else {
521 e.ino = inode;
522 e.attr_timeout = attr_cache_timeout;
523 e.entry_timeout = entry_cache_timeout;
524 mfs_meta_stat(inode,&e.attr);
525 fuse_reply_entry(req,&e);
526 }
527 }
528
529 void mfs_meta_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
530 struct stat o_stbuf;
531 (void)fi;
532 // if (ino==MASTER_INODE) {
533 // memset(&o_stbuf, 0, sizeof(struct stat));
534 // mfs_attr_to_stat(ino,masterattr,&o_stbuf);
535 // fuse_reply_attr(req, &o_stbuf, 3600.0);
536 // } else
537 if (ino==MASTERINFO_INODE) {
538 memset(&o_stbuf, 0, sizeof(struct stat));
539 mfs_attr_to_stat(ino,masterinfoattr,&o_stbuf);
540 fuse_reply_attr(req, &o_stbuf, 3600.0);
541 } else if (IS_SPECIAL_INODE(ino)) {
542 memset(&o_stbuf, 0, sizeof(struct stat));
543 mfs_meta_stat(ino,&o_stbuf);
544 fuse_reply_attr(req, &o_stbuf, attr_cache_timeout);
545 } else {
546 int status;
547 uint8_t attr[ATTR_RECORD_SIZE];
548 status = fs_getdetachedattr(ino,attr);
549 status = mfs_errorconv(status);
550 if (status!=0) {
551 fuse_reply_err(req, status);
552 } else {
553 memset(&o_stbuf, 0, sizeof(struct stat));
554 mfs_attr_to_stat(ino,attr,&o_stbuf);
555 fuse_reply_attr(req, &o_stbuf, attr_cache_timeout);
556 }
557 }
558 }
559
560 void mfs_meta_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *stbuf, int to_set, struct fuse_file_info *fi) {
561 (void)to_set;
562 (void)stbuf;
563 mfs_meta_getattr(req,ino,fi);
564 }
565
566 void mfs_meta_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) {
567 int status;
568 uint32_t inode;
569 if (!(parent==META_TRASH_INODE || (parent>=META_SUBTRASH_INODE_MIN && parent<=META_SUBTRASH_INODE_MAX))) {
570 fuse_reply_err(req,EACCES);
571 return;
572 }
573 inode = mfs_meta_name_to_inode(name);
574 if (inode==0) {
575 fuse_reply_err(req,ENOENT);
576 return;
577 }
578 status = fs_purge(inode);
579 status = mfs_errorconv(status);
580 // if (status!=0) {
581 fuse_reply_err(req, status);
582 // } else {
583 // fuse_reply_err(req,0);
584 // }
585 }
586
587 #if FUSE_VERSION >= 30
588 void mfs_meta_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname,unsigned int flags) {
589 #else
590 void mfs_meta_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname) {
591 #endif
592 int status;
593 uint32_t inode;
594 (void)newname;
595 #if FUSE_VERSION >= 30
596 (void)flags;
597 #endif
598 if ((!(parent==META_TRASH_INODE || (parent>=META_SUBTRASH_INODE_MIN && parent<=META_SUBTRASH_INODE_MAX))) && newparent!=META_UNDEL_INODE) {
599 fuse_reply_err(req,EACCES);
600 return;
601 }
602 inode = mfs_meta_name_to_inode(name);
603 if (inode==0) {
604 fuse_reply_err(req,ENOENT);
605 return;
606 }
607 status = fs_undel(inode);
608 status = mfs_errorconv(status);
609 // if (status!=0) {
610 fuse_reply_err(req, status);
611 // } else {
612 // fuse_reply_err(req,0);
613 // }
614 }
615
616 /*
617 static void dirbuf_add(dirbuf *b, const char *name, fuse_ino_t ino, uint8_t attr[32]) {
618 struct stat stbuf;
619 size_t oldsize = b->size;
620 b->size += fuse_dirent_size(strlen(name));
621 b->p = (char *) realloc(b->p, b->size);
622 mfs_attr_to_stat(ino,attr,&stbuf);
623 fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size);
624 }
625
626 static void dirbuf_meta_add(dirbuf *b, const char *name, fuse_ino_t ino) {
627 struct stat stbuf;
628 size_t oldsize = b->size;
629 b->size += fuse_dirent_size(strlen(name));
630 b->p = (char *) realloc(b->p, b->size);
631 memset(&stbuf,0,sizeof(struct stat));
632 mfs_meta_stat(ino,&stbuf);
633 fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size);
634 }
635 */
636
637 static uint32_t dir_metaentries_size(uint32_t ino) {
638 switch (ino) {
639 case META_ROOT_INODE:
640 return 4*6+1+2+strlen(META_TRASH_NAME)+strlen(META_SUSTAINED_NAME);
641 case META_TRASH_INODE:
642 if (master_version()>=VERSION2INT(3,0,64) && flat_trash==0) {
643 return (3+TRASH_BUCKETS)*6+1+2+strlen(META_UNDEL_NAME)+(TRASH_BUCKETS*((TRASH_BUCKETS<=4096)?3:4));
644 } else {
645 return 3*6+1+2+strlen(META_UNDEL_NAME);
646 }
647 case META_UNDEL_INODE:
648 return 2*6+1+2;
649 case META_SUSTAINED_INODE:
650 return 2*6+1+2;
651 default:
652 if (ino>=META_SUBTRASH_INODE_MIN && ino<=META_SUBTRASH_INODE_MAX) {
653 return 3*6+1+2+strlen(META_UNDEL_NAME);
654 }
655 }
656 return 0;
657 }
658
659 static void dir_metaentries_fill(uint8_t *buff,uint32_t ino) {
660 uint8_t l;
661 switch (ino) {
662 case META_ROOT_INODE:
663 // .
664 put8bit(&buff,1);
665 put8bit(&buff,'.');
666 put32bit(&buff,META_ROOT_INODE);
667 put8bit(&buff,TYPE_DIRECTORY);
668 // ..
669 put8bit(&buff,2);
670 put8bit(&buff,'.');
671 put8bit(&buff,'.');
672 put32bit(&buff,META_ROOT_INODE);
673 put8bit(&buff,TYPE_DIRECTORY);
674 // trash
675 l = strlen(META_TRASH_NAME);
676 put8bit(&buff,l);
677 memcpy(buff,META_TRASH_NAME,l);
678 buff+=l;
679 put32bit(&buff,META_TRASH_INODE);
680 put8bit(&buff,TYPE_DIRECTORY);
681 // sustained
682 l = strlen(META_SUSTAINED_NAME);
683 put8bit(&buff,l);
684 memcpy(buff,META_SUSTAINED_NAME,l);
685 buff+=l;
686 put32bit(&buff,META_SUSTAINED_INODE);
687 put8bit(&buff,TYPE_DIRECTORY);
688 return;
689 case META_TRASH_INODE:
690 // .
691 put8bit(&buff,1);
692 put8bit(&buff,'.');
693 put32bit(&buff,META_TRASH_INODE);
694 put8bit(&buff,TYPE_DIRECTORY);
695 // ..
696 put8bit(&buff,2);
697 put8bit(&buff,'.');
698 put8bit(&buff,'.');
699 put32bit(&buff,META_ROOT_INODE);
700 put8bit(&buff,TYPE_DIRECTORY);
701 // undel
702 l = strlen(META_UNDEL_NAME);
703 put8bit(&buff,l);
704 memcpy(buff,META_UNDEL_NAME,l);
705 buff+=l;
706 put32bit(&buff,META_UNDEL_INODE);
707 put8bit(&buff,TYPE_DIRECTORY);
708 if (master_version()>=VERSION2INT(3,0,64) && flat_trash==0) {
709 uint32_t tid;
710 for (tid=0 ; tid<TRASH_BUCKETS ; tid++) {
711 if (TRASH_BUCKETS>4096) {
712 put8bit(&buff,4);
713 put8bit(&buff,"0123456789ABCDEF"[(tid>>12)&15]);
714 } else {
715 put8bit(&buff,3);
716 }
717 put8bit(&buff,"0123456789ABCDEF"[(tid>>8)&15]);
718 put8bit(&buff,"0123456789ABCDEF"[(tid>>4)&15]);
719 put8bit(&buff,"0123456789ABCDEF"[tid&15]);
720 put32bit(&buff,tid+META_SUBTRASH_INODE_MIN);
721 put8bit(&buff,TYPE_DIRECTORY);
722 }
723 }
724 return;
725 case META_UNDEL_INODE:
726 // .
727 put8bit(&buff,1);
728 put8bit(&buff,'.');
729 put32bit(&buff,META_UNDEL_INODE);
730 put8bit(&buff,TYPE_DIRECTORY);
731 // ..
732 put8bit(&buff,2);
733 put8bit(&buff,'.');
734 put8bit(&buff,'.');
735 put32bit(&buff,META_TRASH_INODE);
736 put8bit(&buff,TYPE_DIRECTORY);
737 return;
738 case META_SUSTAINED_INODE:
739 // .
740 put8bit(&buff,1);
741 put8bit(&buff,'.');
742 put32bit(&buff,META_SUSTAINED_INODE);
743 put8bit(&buff,TYPE_DIRECTORY);
744 // ..
745 put8bit(&buff,2);
746 put8bit(&buff,'.');
747 put8bit(&buff,'.');
748 put32bit(&buff,META_ROOT_INODE);
749 put8bit(&buff,TYPE_DIRECTORY);
750 return;
751 default:
752 if (ino>=META_SUBTRASH_INODE_MIN && ino<=META_SUBTRASH_INODE_MAX) {
753 // .
754 put8bit(&buff,1);
755 put8bit(&buff,'.');
756 put32bit(&buff,META_TRASH_INODE);
757 put8bit(&buff,TYPE_DIRECTORY);
758 // ..
759 put8bit(&buff,2);
760 put8bit(&buff,'.');
761 put8bit(&buff,'.');
762 put32bit(&buff,META_ROOT_INODE);
763 put8bit(&buff,TYPE_DIRECTORY);
764 // undel
765 l = strlen(META_UNDEL_NAME);
766 put8bit(&buff,l);
767 memcpy(buff,META_UNDEL_NAME,l);
768 buff+=l;
769 put32bit(&buff,META_UNDEL_INODE);
770 put8bit(&buff,TYPE_DIRECTORY);
771 return;
772 }
773 }
774 }
775
776 static uint32_t dir_dataentries_size(const uint8_t *dbuff,uint32_t dsize) {
777 uint8_t nleng;
778 uint32_t eleng;
779 const uint8_t *eptr;
780 eleng=0;
781 if (dbuff==NULL || dsize==0) {
782 return 0;
783 }
784 eptr = dbuff+dsize;
785 while (dbuff<eptr) {
786 nleng = dbuff[0];
787 dbuff+=5+nleng;
788 if (nleng>255-9) {
789 eleng+=6+255;
790 } else {
791 eleng+=6+nleng+9;
792 }
793 }
794 return eleng;
795 }
796
797 static void dir_dataentries_convert(uint8_t *buff,const uint8_t *dbuff,uint32_t dsize) {
798 const char *name;
799 uint32_t inode;
800 uint8_t nleng;
801 uint8_t inoleng;
802 const uint8_t *eptr;
803 eptr = dbuff+dsize;
804 while (dbuff<eptr) {
805 nleng = dbuff[0];
806 if (dbuff+nleng+5<=eptr) {
807 dbuff++;
808 if (nleng>255-9) {
809 inoleng = 255;
810 } else {
811 inoleng = nleng+9;
812 }
813 put8bit(&buff,inoleng);
814 name = (const char*)dbuff;
815 dbuff+=nleng;
816 inode = get32bit(&dbuff);
817 sprintf((char*)buff,"%08"PRIX32"|",inode);
818 if (nleng>255-9) {
819 memcpy(buff+9,name,255-9);
820 buff+=255;
821 } else {
822 memcpy(buff+9,name,nleng);
823 buff+=9+nleng;
824 }
825 put32bit(&buff,inode);
826 put8bit(&buff,TYPE_FILE);
827 } else {
828 syslog(LOG_WARNING,"dir data malformed (trash)");
829 dbuff=eptr;
830 }
831 }
832 }
833
834
835 static void dirbuf_meta_fill(dirbuf *b, uint32_t ino) {
836 int status;
837 uint32_t msize,dcsize;
838 const uint8_t *dbuff;
839 uint32_t dsize;
840
841 b->p = NULL;
842 b->size = 0;
843 msize = dir_metaentries_size(ino);
844 if (ino==META_TRASH_INODE && (master_version()<VERSION2INT(3,0,64) || flat_trash)) {
845 status = fs_gettrash(0xFFFFFFFF,&dbuff,&dsize);
846 if (status!=MFS_STATUS_OK) {
847 return;
848 }
849 dcsize = dir_dataentries_size(dbuff,dsize);
850 } else if (ino==META_SUSTAINED_INODE) {
851 status = fs_getsustained(&dbuff,&dsize);
852 if (status!=MFS_STATUS_OK) {
853 return;
854 }
855 dcsize = dir_dataentries_size(dbuff,dsize);
856 } else if (ino>=META_SUBTRASH_INODE_MIN && ino<=META_SUBTRASH_INODE_MAX && master_version()>=VERSION2INT(3,0,64) && flat_trash==0) {
857 status = fs_gettrash(ino-META_SUBTRASH_INODE_MIN,&dbuff,&dsize);
858 if (status!=MFS_STATUS_OK) {
859 return;
860 }
861 dcsize = dir_dataentries_size(dbuff,dsize);
862 } else {
863 dcsize = 0;
864 }
865 if (msize+dcsize==0) {
866 return;
867 }
868 b->p = malloc(msize+dcsize);
869 if (b->p==NULL) {
870 syslog(LOG_WARNING,"out of memory");
871 return;
872 }
873 if (msize>0) {
874 dir_metaentries_fill(b->p,ino);
875 }
876 if (dcsize>0) {
877 dir_dataentries_convert(b->p+msize,dbuff,dsize);
878 }
879 b->size = msize+dcsize;
880 }
881
882 void mfs_meta_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
883 dirbuf *dirinfo;
884 if (ino==META_ROOT_INODE || ino==META_TRASH_INODE || ino==META_UNDEL_INODE || ino==META_SUSTAINED_INODE || (ino>=META_SUBTRASH_INODE_MIN && ino<=META_SUBTRASH_INODE_MAX)) {
885 dirinfo = malloc(sizeof(dirbuf));
886 pthread_mutex_init(&(dirinfo->lock),NULL);
887 dirinfo->p = NULL;
888 dirinfo->size = 0;
889 dirinfo->wasread = 0;
890 fi->fh = (unsigned long)dirinfo;
891 if (fuse_reply_open(req,fi) == -ENOENT) {
892 fi->fh = 0;
893 pthread_mutex_destroy(&(dirinfo->lock));
894 free(dirinfo->p);
895 free(dirinfo);
896 }
897 } else {
898 fuse_reply_err(req, ENOTDIR);
899 }
900 }
901
902 void mfs_meta_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
903 dirbuf *dirinfo = (dirbuf *)((unsigned long)(fi->fh));
904 char buffer[READDIR_BUFFSIZE];
905 char *name,c;
906 const uint8_t *ptr,*eptr;
907 uint8_t end;
908 size_t opos,oleng;
909 uint8_t nleng;
910 uint32_t inode;
911 uint8_t type;
912 struct stat stbuf;
913
914 if (off<0) {
915 fuse_reply_err(req,EINVAL);
916 return;
917 }
918 pthread_mutex_lock(&(dirinfo->lock));
919 if (dirinfo->wasread==0 || (dirinfo->wasread==1 && off==0)) {
920 if (dirinfo->p!=NULL) {
921 free(dirinfo->p);
922 }
923 dirbuf_meta_fill(dirinfo,ino);
924 // syslog(LOG_WARNING,"inode: %lu , dirinfo->p: %p , dirinfo->size: %lu",(unsigned long)ino,dirinfo->p,(unsigned long)dirinfo->size);
925 }
926 dirinfo->wasread=1;
927
928 if (off>=(off_t)(dirinfo->size)) {
929 fuse_reply_buf(req, NULL, 0);
930 } else {
931 if (size>READDIR_BUFFSIZE) {
932 size=READDIR_BUFFSIZE;
933 }
934 ptr = (const uint8_t*)(dirinfo->p)+off;
935 eptr = (const uint8_t*)(dirinfo->p)+dirinfo->size;
936 opos = 0;
937 end = 0;
938
939 while (ptr<eptr && end==0) {
940 nleng = ptr[0];
941 ptr++;
942 name = (char*)ptr;
943 ptr+=nleng;
944 off+=nleng+6;
945 if (ptr+5<=eptr) {
946 inode = get32bit(&ptr);
947 type = get8bit(&ptr);
948 mfs_meta_type_to_stat(inode,type,&stbuf);
949 c = name[nleng];
950 name[nleng]=0;
951 oleng = fuse_add_direntry(req, buffer + opos, size - opos, name, &stbuf, off);
952 name[nleng] = c;
953 if (opos+oleng>size) {
954 end=1;
955 } else {
956 opos+=oleng;
957 }
958 }
959 }
960 fuse_reply_buf(req,buffer,opos);
961 }
962 pthread_mutex_unlock(&(dirinfo->lock));
963 }
964
965 void mfs_meta_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
966 (void)ino;
967 dirbuf *dirinfo = (dirbuf *)((unsigned long)(fi->fh));
968 pthread_mutex_lock(&(dirinfo->lock));
969 pthread_mutex_unlock(&(dirinfo->lock));
970 pthread_mutex_destroy(&(dirinfo->lock));
971 free(dirinfo->p);
972 free(dirinfo);
973 fi->fh = 0;
974 fuse_reply_err(req,0);
975 }
976
977 void mfs_meta_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
978 pathbuf *pathinfo;
979 const uint8_t *path;
980 //size_t pleng;
981 int status;
982 // if (ino==MASTER_INODE) {
983 // minfo *masterinfo;
984 // status = fs_direct_connect();
985 // if (status<0) {
986 // fuse_reply_err(req,EIO);
987 // return;
988 // }
989 // masterinfo = malloc(sizeof(minfo));
990 // if (masterinfo==NULL) {
991 // fuse_reply_err(req,ENOMEM);
992 // return;
993 // }
994 // masterinfo->sd = status;
995 // masterinfo->sent = 0;
996 // fi->direct_io = 1;
997 // fi->fh = (unsigned long)masterinfo;
998 // fuse_reply_open(req, fi);
999 // return;
1000 // }
1001 if (ino==MASTERINFO_INODE) {
1002 fi->fh = 0;
1003 fi->direct_io = 0;
1004 fi->keep_cache = 1;
1005 fuse_reply_open(req, fi);
1006 return;
1007 }
1008
1009 if (IS_SPECIAL_INODE(ino)) {
1010 fuse_reply_err(req, EACCES);
1011 } else {
1012 status = fs_gettrashpath(ino,&path);
1013 status = mfs_errorconv(status);
1014 if (status!=0) {
1015 fuse_reply_err(req, status);
1016 } else {
1017 pathinfo = malloc(sizeof(pathbuf));
1018 pthread_mutex_init(&(pathinfo->lock),NULL);
1019 pathinfo->changed = 0;
1020 pathinfo->size = strlen((char*)path)+1;
1021 pathinfo->p = malloc(pathinfo->size);
1022 memcpy(pathinfo->p,path,pathinfo->size-1);
1023 pathinfo->p[pathinfo->size-1]='\n';
1024 fi->direct_io = 1;
1025 fi->fh = (unsigned long)pathinfo;
1026 if (fuse_reply_open(req,fi) == -ENOENT) {
1027 fi->fh = 0;
1028 pthread_mutex_destroy(&(pathinfo->lock));
1029 free(pathinfo->p);
1030 free(pathinfo);
1031 }
1032 }
1033 }
1034 }
1035
1036 void mfs_meta_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
1037 if (ino==MASTERINFO_INODE) {
1038 fuse_reply_err(req,0);
1039 return;
1040 }
1041 // if (ino==MASTER_INODE) {
1042 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
1043 // if (masterinfo!=NULL) {
1044 // fs_direct_close(masterinfo->sd);
1045 // free(masterinfo);
1046 // }
1047 // fuse_reply_err(req,0);
1048 // return;
1049 // }
1050 pathbuf *pathinfo = (pathbuf *)((unsigned long)(fi->fh));
1051 pthread_mutex_lock(&(pathinfo->lock));
1052 if (pathinfo->changed) {
1053 if (pathinfo->p[pathinfo->size-1]=='\n') {
1054 pathinfo->p[pathinfo->size-1]=0;
1055 } else {
1056 pathinfo->p = realloc(pathinfo->p,pathinfo->size+1);
1057 pathinfo->p[pathinfo->size]=0;
1058 }
1059 fs_settrashpath(ino,(uint8_t*)pathinfo->p);
1060 }
1061 pthread_mutex_unlock(&(pathinfo->lock));
1062 pthread_mutex_destroy(&(pathinfo->lock));
1063 free(pathinfo->p);
1064 free(pathinfo);
1065 fi->fh = 0;
1066 fuse_reply_err(req,0);
1067 }
1068
1069 void mfs_meta_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
1070 pathbuf *pathinfo = (pathbuf *)((unsigned long)(fi->fh));
1071 if (ino==MASTERINFO_INODE) {
1072 uint8_t masterinfo[14];
1073 fs_getmasterlocation(masterinfo);
1074 masterproxy_getlocation(masterinfo);
1075 #ifdef MASTERINFO_WITH_VERSION
1076 if (off>=14) {
1077 fuse_reply_buf(req,NULL,0);
1078 } else if (off+size>14) {
1079 fuse_reply_buf(req,(char*)(masterinfo+off),14-off);
1080 #else
1081 if (off>=10) {
1082 fuse_reply_buf(req,NULL,0);
1083 } else if (off+size>10) {
1084 fuse_reply_buf(req,(char*)(masterinfo+off),10-off);
1085 #endif
1086 } else {
1087 fuse_reply_buf(req,(char*)(masterinfo+off),size);
1088 }
1089 return;
1090 }
1091 if (pathinfo==NULL) {
1092 fuse_reply_err(req,EBADF);
1093 return;
1094 }
1095 // if (ino==MASTER_INODE) {
1096 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
1097 // if (masterinfo->sent) {
1098 // int rsize;
1099 // uint8_t *buff;
1100 // buff = malloc(size);
1101 // rsize = fs_direct_read(masterinfo->sd,buff,size);
1102 // fuse_reply_buf(req,(char*)buff,rsize);
1103 //syslog(LOG_WARNING,"master received: %d/%u",rsize,size);
1104 // free(buff);
1105 // } else {
1106 // syslog(LOG_WARNING,"master: read before write");
1107 // fuse_reply_buf(req,NULL,0);
1108 // }
1109 // return;
1110 // }
1111 pthread_mutex_lock(&(pathinfo->lock));
1112 if (off<0) {
1113 pthread_mutex_unlock(&(pathinfo->lock));
1114 fuse_reply_err(req,EINVAL);
1115 return;
1116 }
1117 if ((size_t)off>pathinfo->size) {
1118 fuse_reply_buf(req, NULL, 0);
1119 } else if (off + size > pathinfo->size) {
1120 fuse_reply_buf(req, (pathinfo->p)+off,(pathinfo->size)-off);
1121 } else {
1122 fuse_reply_buf(req, (pathinfo->p)+off,size);
1123 }
1124 pthread_mutex_unlock(&(pathinfo->lock));
1125 }
1126
1127 void mfs_meta_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) {
1128 pathbuf *pathinfo = (pathbuf *)((unsigned long)(fi->fh));
1129 if (ino==MASTERINFO_INODE) {
1130 fuse_reply_err(req,EACCES);
1131 return;
1132 }
1133 if (pathinfo==NULL) {
1134 fuse_reply_err(req,EBADF);
1135 return;
1136 }
1137 // if (ino==MASTER_INODE) {
1138 // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh);
1139 // int wsize;
1140 // masterinfo->sent=1;
1141 // wsize = fs_direct_write(masterinfo->sd,(const uint8_t*)buf,size);
1142 //syslog(LOG_WARNING,"master sent: %d/%u",wsize,size);
1143 // fuse_reply_write(req,wsize);
1144 // return;
1145 // }
1146 if (off + size > PATH_SIZE_LIMIT) {
1147 fuse_reply_err(req,EINVAL);
1148 return;
1149 }
1150 pthread_mutex_lock(&(pathinfo->lock));
1151 if (pathinfo->changed==0) {
1152 pathinfo->size = 0;
1153 }
1154 if (off+size > pathinfo->size) {
1155 size_t s = pathinfo->size;
1156 pathinfo->p = realloc(pathinfo->p,off+size);
1157 pathinfo->size = off+size;
1158 memset(pathinfo->p+s,0,off+size-s);
1159 }
1160 memcpy((pathinfo->p)+off,buf,size);
1161 pathinfo->changed = 1;
1162 pthread_mutex_unlock(&(pathinfo->lock));
1163 fuse_reply_write(req,size);
1164 }
1165
1166 void mfs_meta_init(int debug_mode_in,double entry_cache_timeout_in,double attr_cache_timeout_in,int flat_trash_in) {
1167 debug_mode = debug_mode_in;
1168 entry_cache_timeout = entry_cache_timeout_in;
1169 attr_cache_timeout = attr_cache_timeout_in;
1170 flat_trash = flat_trash_in;
1171 if (debug_mode) {
1172 fprintf(stderr,"cache parameters: entry_cache_timeout=%.2lf attr_cache_timeout=%.2lf\n",entry_cache_timeout,attr_cache_timeout);
1173 if (flat_trash) {
1174 fprintf(stderr,"force using 'flat' trash\n");
1175 }
1176 }
1177 }
1178