16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci Implementation of the high-level FUSE API on top of the low-level 66881f68fSopenharmony_ci API. 76881f68fSopenharmony_ci 86881f68fSopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 96881f68fSopenharmony_ci See the file COPYING.LIB 106881f68fSopenharmony_ci*/ 116881f68fSopenharmony_ci 126881f68fSopenharmony_ci#include "fuse_config.h" 136881f68fSopenharmony_ci#include "fuse_i.h" 146881f68fSopenharmony_ci#include "fuse_lowlevel.h" 156881f68fSopenharmony_ci#include "fuse_opt.h" 166881f68fSopenharmony_ci#include "fuse_misc.h" 176881f68fSopenharmony_ci#include "fuse_kernel.h" 186881f68fSopenharmony_ci 196881f68fSopenharmony_ci#include <stdio.h> 206881f68fSopenharmony_ci#include <string.h> 216881f68fSopenharmony_ci#include <stdlib.h> 226881f68fSopenharmony_ci#include <stddef.h> 236881f68fSopenharmony_ci#include <stdbool.h> 246881f68fSopenharmony_ci#include <unistd.h> 256881f68fSopenharmony_ci#include <time.h> 266881f68fSopenharmony_ci#include <fcntl.h> 276881f68fSopenharmony_ci#include <limits.h> 286881f68fSopenharmony_ci#include <errno.h> 296881f68fSopenharmony_ci#include <signal.h> 306881f68fSopenharmony_ci#include <dlfcn.h> 316881f68fSopenharmony_ci#include <assert.h> 326881f68fSopenharmony_ci#include <poll.h> 336881f68fSopenharmony_ci#include <sys/param.h> 346881f68fSopenharmony_ci#include <sys/uio.h> 356881f68fSopenharmony_ci#include <sys/time.h> 366881f68fSopenharmony_ci#include <sys/mman.h> 376881f68fSopenharmony_ci#include <sys/file.h> 386881f68fSopenharmony_ci 396881f68fSopenharmony_ci#define FUSE_NODE_SLAB 1 406881f68fSopenharmony_ci 416881f68fSopenharmony_ci#ifndef MAP_ANONYMOUS 426881f68fSopenharmony_ci#undef FUSE_NODE_SLAB 436881f68fSopenharmony_ci#endif 446881f68fSopenharmony_ci 456881f68fSopenharmony_ci#ifndef RENAME_EXCHANGE 466881f68fSopenharmony_ci#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ 476881f68fSopenharmony_ci#endif 486881f68fSopenharmony_ci 496881f68fSopenharmony_ci#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1 506881f68fSopenharmony_ci 516881f68fSopenharmony_ci#define FUSE_UNKNOWN_INO 0xffffffff 526881f68fSopenharmony_ci#define OFFSET_MAX 0x7fffffffffffffffLL 536881f68fSopenharmony_ci 546881f68fSopenharmony_ci#define NODE_TABLE_MIN_SIZE 8192 556881f68fSopenharmony_ci 566881f68fSopenharmony_cistruct fuse_fs { 576881f68fSopenharmony_ci struct fuse_operations op; 586881f68fSopenharmony_ci void *user_data; 596881f68fSopenharmony_ci int debug; 606881f68fSopenharmony_ci}; 616881f68fSopenharmony_ci 626881f68fSopenharmony_cistruct fusemod_so { 636881f68fSopenharmony_ci void *handle; 646881f68fSopenharmony_ci int ctr; 656881f68fSopenharmony_ci}; 666881f68fSopenharmony_ci 676881f68fSopenharmony_cistruct lock_queue_element { 686881f68fSopenharmony_ci struct lock_queue_element *next; 696881f68fSopenharmony_ci pthread_cond_t cond; 706881f68fSopenharmony_ci fuse_ino_t nodeid1; 716881f68fSopenharmony_ci const char *name1; 726881f68fSopenharmony_ci char **path1; 736881f68fSopenharmony_ci struct node **wnode1; 746881f68fSopenharmony_ci fuse_ino_t nodeid2; 756881f68fSopenharmony_ci const char *name2; 766881f68fSopenharmony_ci char **path2; 776881f68fSopenharmony_ci struct node **wnode2; 786881f68fSopenharmony_ci int err; 796881f68fSopenharmony_ci bool done : 1; 806881f68fSopenharmony_ci}; 816881f68fSopenharmony_ci 826881f68fSopenharmony_cistruct node_table { 836881f68fSopenharmony_ci struct node **array; 846881f68fSopenharmony_ci size_t use; 856881f68fSopenharmony_ci size_t size; 866881f68fSopenharmony_ci size_t split; 876881f68fSopenharmony_ci}; 886881f68fSopenharmony_ci 896881f68fSopenharmony_ci#define container_of(ptr, type, member) ({ \ 906881f68fSopenharmony_ci const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 916881f68fSopenharmony_ci (type *)( (char *)__mptr - offsetof(type,member) );}) 926881f68fSopenharmony_ci 936881f68fSopenharmony_ci#define list_entry(ptr, type, member) \ 946881f68fSopenharmony_ci container_of(ptr, type, member) 956881f68fSopenharmony_ci 966881f68fSopenharmony_cistruct list_head { 976881f68fSopenharmony_ci struct list_head *next; 986881f68fSopenharmony_ci struct list_head *prev; 996881f68fSopenharmony_ci}; 1006881f68fSopenharmony_ci 1016881f68fSopenharmony_cistruct node_slab { 1026881f68fSopenharmony_ci struct list_head list; /* must be the first member */ 1036881f68fSopenharmony_ci struct list_head freelist; 1046881f68fSopenharmony_ci int used; 1056881f68fSopenharmony_ci}; 1066881f68fSopenharmony_ci 1076881f68fSopenharmony_cistruct fuse { 1086881f68fSopenharmony_ci struct fuse_session *se; 1096881f68fSopenharmony_ci struct node_table name_table; 1106881f68fSopenharmony_ci struct node_table id_table; 1116881f68fSopenharmony_ci struct list_head lru_table; 1126881f68fSopenharmony_ci fuse_ino_t ctr; 1136881f68fSopenharmony_ci unsigned int generation; 1146881f68fSopenharmony_ci unsigned int hidectr; 1156881f68fSopenharmony_ci pthread_mutex_t lock; 1166881f68fSopenharmony_ci struct fuse_config conf; 1176881f68fSopenharmony_ci int intr_installed; 1186881f68fSopenharmony_ci struct fuse_fs *fs; 1196881f68fSopenharmony_ci struct lock_queue_element *lockq; 1206881f68fSopenharmony_ci int pagesize; 1216881f68fSopenharmony_ci struct list_head partial_slabs; 1226881f68fSopenharmony_ci struct list_head full_slabs; 1236881f68fSopenharmony_ci pthread_t prune_thread; 1246881f68fSopenharmony_ci}; 1256881f68fSopenharmony_ci 1266881f68fSopenharmony_cistruct lock { 1276881f68fSopenharmony_ci int type; 1286881f68fSopenharmony_ci off_t start; 1296881f68fSopenharmony_ci off_t end; 1306881f68fSopenharmony_ci pid_t pid; 1316881f68fSopenharmony_ci uint64_t owner; 1326881f68fSopenharmony_ci struct lock *next; 1336881f68fSopenharmony_ci}; 1346881f68fSopenharmony_ci 1356881f68fSopenharmony_cistruct node { 1366881f68fSopenharmony_ci struct node *name_next; 1376881f68fSopenharmony_ci struct node *id_next; 1386881f68fSopenharmony_ci fuse_ino_t nodeid; 1396881f68fSopenharmony_ci unsigned int generation; 1406881f68fSopenharmony_ci int refctr; 1416881f68fSopenharmony_ci struct node *parent; 1426881f68fSopenharmony_ci char *name; 1436881f68fSopenharmony_ci uint64_t nlookup; 1446881f68fSopenharmony_ci int open_count; 1456881f68fSopenharmony_ci struct timespec stat_updated; 1466881f68fSopenharmony_ci struct timespec mtime; 1476881f68fSopenharmony_ci off_t size; 1486881f68fSopenharmony_ci struct lock *locks; 1496881f68fSopenharmony_ci unsigned int is_hidden : 1; 1506881f68fSopenharmony_ci unsigned int cache_valid : 1; 1516881f68fSopenharmony_ci int treelock; 1526881f68fSopenharmony_ci char inline_name[32]; 1536881f68fSopenharmony_ci}; 1546881f68fSopenharmony_ci 1556881f68fSopenharmony_ci#define TREELOCK_WRITE -1 1566881f68fSopenharmony_ci#define TREELOCK_WAIT_OFFSET INT_MIN 1576881f68fSopenharmony_ci 1586881f68fSopenharmony_cistruct node_lru { 1596881f68fSopenharmony_ci struct node node; 1606881f68fSopenharmony_ci struct list_head lru; 1616881f68fSopenharmony_ci struct timespec forget_time; 1626881f68fSopenharmony_ci}; 1636881f68fSopenharmony_ci 1646881f68fSopenharmony_cistruct fuse_direntry { 1656881f68fSopenharmony_ci struct stat stat; 1666881f68fSopenharmony_ci char *name; 1676881f68fSopenharmony_ci struct fuse_direntry *next; 1686881f68fSopenharmony_ci}; 1696881f68fSopenharmony_ci 1706881f68fSopenharmony_cistruct fuse_dh { 1716881f68fSopenharmony_ci pthread_mutex_t lock; 1726881f68fSopenharmony_ci struct fuse *fuse; 1736881f68fSopenharmony_ci fuse_req_t req; 1746881f68fSopenharmony_ci char *contents; 1756881f68fSopenharmony_ci struct fuse_direntry *first; 1766881f68fSopenharmony_ci struct fuse_direntry **last; 1776881f68fSopenharmony_ci unsigned len; 1786881f68fSopenharmony_ci unsigned size; 1796881f68fSopenharmony_ci unsigned needlen; 1806881f68fSopenharmony_ci int filled; 1816881f68fSopenharmony_ci uint64_t fh; 1826881f68fSopenharmony_ci int error; 1836881f68fSopenharmony_ci fuse_ino_t nodeid; 1846881f68fSopenharmony_ci}; 1856881f68fSopenharmony_ci 1866881f68fSopenharmony_cistruct fuse_context_i { 1876881f68fSopenharmony_ci struct fuse_context ctx; 1886881f68fSopenharmony_ci fuse_req_t req; 1896881f68fSopenharmony_ci}; 1906881f68fSopenharmony_ci 1916881f68fSopenharmony_ci/* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */ 1926881f68fSopenharmony_ciextern fuse_module_factory_t fuse_module_subdir_factory; 1936881f68fSopenharmony_ci#ifdef HAVE_ICONV 1946881f68fSopenharmony_ciextern fuse_module_factory_t fuse_module_iconv_factory; 1956881f68fSopenharmony_ci#endif 1966881f68fSopenharmony_ci 1976881f68fSopenharmony_cistatic pthread_key_t fuse_context_key; 1986881f68fSopenharmony_cistatic pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; 1996881f68fSopenharmony_cistatic int fuse_context_ref; 2006881f68fSopenharmony_cistatic struct fuse_module *fuse_modules = NULL; 2016881f68fSopenharmony_ci 2026881f68fSopenharmony_cistatic int fuse_register_module(const char *name, 2036881f68fSopenharmony_ci fuse_module_factory_t factory, 2046881f68fSopenharmony_ci struct fusemod_so *so) 2056881f68fSopenharmony_ci{ 2066881f68fSopenharmony_ci struct fuse_module *mod; 2076881f68fSopenharmony_ci 2086881f68fSopenharmony_ci mod = calloc(1, sizeof(struct fuse_module)); 2096881f68fSopenharmony_ci if (!mod) { 2106881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module\n"); 2116881f68fSopenharmony_ci return -1; 2126881f68fSopenharmony_ci } 2136881f68fSopenharmony_ci mod->name = strdup(name); 2146881f68fSopenharmony_ci if (!mod->name) { 2156881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module name\n"); 2166881f68fSopenharmony_ci free(mod); 2176881f68fSopenharmony_ci return -1; 2186881f68fSopenharmony_ci } 2196881f68fSopenharmony_ci mod->factory = factory; 2206881f68fSopenharmony_ci mod->ctr = 0; 2216881f68fSopenharmony_ci mod->so = so; 2226881f68fSopenharmony_ci if (mod->so) 2236881f68fSopenharmony_ci mod->so->ctr++; 2246881f68fSopenharmony_ci mod->next = fuse_modules; 2256881f68fSopenharmony_ci fuse_modules = mod; 2266881f68fSopenharmony_ci 2276881f68fSopenharmony_ci return 0; 2286881f68fSopenharmony_ci} 2296881f68fSopenharmony_ci 2306881f68fSopenharmony_cistatic void fuse_unregister_module(struct fuse_module *m) 2316881f68fSopenharmony_ci{ 2326881f68fSopenharmony_ci struct fuse_module **mp; 2336881f68fSopenharmony_ci for (mp = &fuse_modules; *mp; mp = &(*mp)->next) { 2346881f68fSopenharmony_ci if (*mp == m) { 2356881f68fSopenharmony_ci *mp = (*mp)->next; 2366881f68fSopenharmony_ci break; 2376881f68fSopenharmony_ci } 2386881f68fSopenharmony_ci } 2396881f68fSopenharmony_ci free(m->name); 2406881f68fSopenharmony_ci free(m); 2416881f68fSopenharmony_ci} 2426881f68fSopenharmony_ci 2436881f68fSopenharmony_cistatic int fuse_load_so_module(const char *module) 2446881f68fSopenharmony_ci{ 2456881f68fSopenharmony_ci int ret = -1; 2466881f68fSopenharmony_ci char *tmp; 2476881f68fSopenharmony_ci struct fusemod_so *so; 2486881f68fSopenharmony_ci fuse_module_factory_t *factory; 2496881f68fSopenharmony_ci 2506881f68fSopenharmony_ci tmp = malloc(strlen(module) + 64); 2516881f68fSopenharmony_ci if (!tmp) { 2526881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); 2536881f68fSopenharmony_ci return -1; 2546881f68fSopenharmony_ci } 2556881f68fSopenharmony_ci sprintf(tmp, "libfusemod_%s.so", module); 2566881f68fSopenharmony_ci so = calloc(1, sizeof(struct fusemod_so)); 2576881f68fSopenharmony_ci if (!so) { 2586881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module so\n"); 2596881f68fSopenharmony_ci goto out; 2606881f68fSopenharmony_ci } 2616881f68fSopenharmony_ci 2626881f68fSopenharmony_ci so->handle = dlopen(tmp, RTLD_NOW); 2636881f68fSopenharmony_ci if (so->handle == NULL) { 2646881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: dlopen(%s) failed: %s\n", 2656881f68fSopenharmony_ci tmp, dlerror()); 2666881f68fSopenharmony_ci goto out_free_so; 2676881f68fSopenharmony_ci } 2686881f68fSopenharmony_ci 2696881f68fSopenharmony_ci sprintf(tmp, "fuse_module_%s_factory", module); 2706881f68fSopenharmony_ci factory = (fuse_module_factory_t*)dlsym(so->handle, tmp); 2716881f68fSopenharmony_ci if (factory == NULL) { 2726881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: symbol <%s> not found in module: %s\n", 2736881f68fSopenharmony_ci tmp, dlerror()); 2746881f68fSopenharmony_ci goto out_dlclose; 2756881f68fSopenharmony_ci } 2766881f68fSopenharmony_ci ret = fuse_register_module(module, *factory, so); 2776881f68fSopenharmony_ci if (ret) 2786881f68fSopenharmony_ci goto out_dlclose; 2796881f68fSopenharmony_ci 2806881f68fSopenharmony_ciout: 2816881f68fSopenharmony_ci free(tmp); 2826881f68fSopenharmony_ci return ret; 2836881f68fSopenharmony_ci 2846881f68fSopenharmony_ciout_dlclose: 2856881f68fSopenharmony_ci dlclose(so->handle); 2866881f68fSopenharmony_ciout_free_so: 2876881f68fSopenharmony_ci free(so); 2886881f68fSopenharmony_ci goto out; 2896881f68fSopenharmony_ci} 2906881f68fSopenharmony_ci 2916881f68fSopenharmony_cistatic struct fuse_module *fuse_find_module(const char *module) 2926881f68fSopenharmony_ci{ 2936881f68fSopenharmony_ci struct fuse_module *m; 2946881f68fSopenharmony_ci for (m = fuse_modules; m; m = m->next) { 2956881f68fSopenharmony_ci if (strcmp(module, m->name) == 0) { 2966881f68fSopenharmony_ci m->ctr++; 2976881f68fSopenharmony_ci break; 2986881f68fSopenharmony_ci } 2996881f68fSopenharmony_ci } 3006881f68fSopenharmony_ci return m; 3016881f68fSopenharmony_ci} 3026881f68fSopenharmony_ci 3036881f68fSopenharmony_cistatic struct fuse_module *fuse_get_module(const char *module) 3046881f68fSopenharmony_ci{ 3056881f68fSopenharmony_ci struct fuse_module *m; 3066881f68fSopenharmony_ci 3076881f68fSopenharmony_ci pthread_mutex_lock(&fuse_context_lock); 3086881f68fSopenharmony_ci m = fuse_find_module(module); 3096881f68fSopenharmony_ci if (!m) { 3106881f68fSopenharmony_ci int err = fuse_load_so_module(module); 3116881f68fSopenharmony_ci if (!err) 3126881f68fSopenharmony_ci m = fuse_find_module(module); 3136881f68fSopenharmony_ci } 3146881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 3156881f68fSopenharmony_ci return m; 3166881f68fSopenharmony_ci} 3176881f68fSopenharmony_ci 3186881f68fSopenharmony_cistatic void fuse_put_module(struct fuse_module *m) 3196881f68fSopenharmony_ci{ 3206881f68fSopenharmony_ci pthread_mutex_lock(&fuse_context_lock); 3216881f68fSopenharmony_ci if (m->so) 3226881f68fSopenharmony_ci assert(m->ctr > 0); 3236881f68fSopenharmony_ci /* Builtin modules may already have m->ctr == 0 */ 3246881f68fSopenharmony_ci if (m->ctr > 0) 3256881f68fSopenharmony_ci m->ctr--; 3266881f68fSopenharmony_ci if (!m->ctr && m->so) { 3276881f68fSopenharmony_ci struct fusemod_so *so = m->so; 3286881f68fSopenharmony_ci assert(so->ctr > 0); 3296881f68fSopenharmony_ci so->ctr--; 3306881f68fSopenharmony_ci if (!so->ctr) { 3316881f68fSopenharmony_ci struct fuse_module **mp; 3326881f68fSopenharmony_ci for (mp = &fuse_modules; *mp;) { 3336881f68fSopenharmony_ci if ((*mp)->so == so) 3346881f68fSopenharmony_ci fuse_unregister_module(*mp); 3356881f68fSopenharmony_ci else 3366881f68fSopenharmony_ci mp = &(*mp)->next; 3376881f68fSopenharmony_ci } 3386881f68fSopenharmony_ci dlclose(so->handle); 3396881f68fSopenharmony_ci free(so); 3406881f68fSopenharmony_ci } 3416881f68fSopenharmony_ci } else if (!m->ctr) { 3426881f68fSopenharmony_ci fuse_unregister_module(m); 3436881f68fSopenharmony_ci } 3446881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 3456881f68fSopenharmony_ci} 3466881f68fSopenharmony_ci 3476881f68fSopenharmony_cistatic void init_list_head(struct list_head *list) 3486881f68fSopenharmony_ci{ 3496881f68fSopenharmony_ci list->next = list; 3506881f68fSopenharmony_ci list->prev = list; 3516881f68fSopenharmony_ci} 3526881f68fSopenharmony_ci 3536881f68fSopenharmony_cistatic int list_empty(const struct list_head *head) 3546881f68fSopenharmony_ci{ 3556881f68fSopenharmony_ci return head->next == head; 3566881f68fSopenharmony_ci} 3576881f68fSopenharmony_ci 3586881f68fSopenharmony_cistatic void list_add(struct list_head *new, struct list_head *prev, 3596881f68fSopenharmony_ci struct list_head *next) 3606881f68fSopenharmony_ci{ 3616881f68fSopenharmony_ci next->prev = new; 3626881f68fSopenharmony_ci new->next = next; 3636881f68fSopenharmony_ci new->prev = prev; 3646881f68fSopenharmony_ci prev->next = new; 3656881f68fSopenharmony_ci} 3666881f68fSopenharmony_ci 3676881f68fSopenharmony_cistatic inline void list_add_head(struct list_head *new, struct list_head *head) 3686881f68fSopenharmony_ci{ 3696881f68fSopenharmony_ci list_add(new, head, head->next); 3706881f68fSopenharmony_ci} 3716881f68fSopenharmony_ci 3726881f68fSopenharmony_cistatic inline void list_add_tail(struct list_head *new, struct list_head *head) 3736881f68fSopenharmony_ci{ 3746881f68fSopenharmony_ci list_add(new, head->prev, head); 3756881f68fSopenharmony_ci} 3766881f68fSopenharmony_ci 3776881f68fSopenharmony_cistatic inline void list_del(struct list_head *entry) 3786881f68fSopenharmony_ci{ 3796881f68fSopenharmony_ci struct list_head *prev = entry->prev; 3806881f68fSopenharmony_ci struct list_head *next = entry->next; 3816881f68fSopenharmony_ci 3826881f68fSopenharmony_ci next->prev = prev; 3836881f68fSopenharmony_ci prev->next = next; 3846881f68fSopenharmony_ci} 3856881f68fSopenharmony_ci 3866881f68fSopenharmony_cistatic inline int lru_enabled(struct fuse *f) 3876881f68fSopenharmony_ci{ 3886881f68fSopenharmony_ci return f->conf.remember > 0; 3896881f68fSopenharmony_ci} 3906881f68fSopenharmony_ci 3916881f68fSopenharmony_cistatic struct node_lru *node_lru(struct node *node) 3926881f68fSopenharmony_ci{ 3936881f68fSopenharmony_ci return (struct node_lru *) node; 3946881f68fSopenharmony_ci} 3956881f68fSopenharmony_ci 3966881f68fSopenharmony_cistatic size_t get_node_size(struct fuse *f) 3976881f68fSopenharmony_ci{ 3986881f68fSopenharmony_ci if (lru_enabled(f)) 3996881f68fSopenharmony_ci return sizeof(struct node_lru); 4006881f68fSopenharmony_ci else 4016881f68fSopenharmony_ci return sizeof(struct node); 4026881f68fSopenharmony_ci} 4036881f68fSopenharmony_ci 4046881f68fSopenharmony_ci#ifdef FUSE_NODE_SLAB 4056881f68fSopenharmony_cistatic struct node_slab *list_to_slab(struct list_head *head) 4066881f68fSopenharmony_ci{ 4076881f68fSopenharmony_ci return (struct node_slab *) head; 4086881f68fSopenharmony_ci} 4096881f68fSopenharmony_ci 4106881f68fSopenharmony_cistatic struct node_slab *node_to_slab(struct fuse *f, struct node *node) 4116881f68fSopenharmony_ci{ 4126881f68fSopenharmony_ci return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); 4136881f68fSopenharmony_ci} 4146881f68fSopenharmony_ci 4156881f68fSopenharmony_cistatic int alloc_slab(struct fuse *f) 4166881f68fSopenharmony_ci{ 4176881f68fSopenharmony_ci void *mem; 4186881f68fSopenharmony_ci struct node_slab *slab; 4196881f68fSopenharmony_ci char *start; 4206881f68fSopenharmony_ci size_t num; 4216881f68fSopenharmony_ci size_t i; 4226881f68fSopenharmony_ci size_t node_size = get_node_size(f); 4236881f68fSopenharmony_ci 4246881f68fSopenharmony_ci mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, 4256881f68fSopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 4266881f68fSopenharmony_ci 4276881f68fSopenharmony_ci if (mem == MAP_FAILED) 4286881f68fSopenharmony_ci return -1; 4296881f68fSopenharmony_ci 4306881f68fSopenharmony_ci slab = mem; 4316881f68fSopenharmony_ci init_list_head(&slab->freelist); 4326881f68fSopenharmony_ci slab->used = 0; 4336881f68fSopenharmony_ci num = (f->pagesize - sizeof(struct node_slab)) / node_size; 4346881f68fSopenharmony_ci 4356881f68fSopenharmony_ci start = (char *) mem + f->pagesize - num * node_size; 4366881f68fSopenharmony_ci for (i = 0; i < num; i++) { 4376881f68fSopenharmony_ci struct list_head *n; 4386881f68fSopenharmony_ci 4396881f68fSopenharmony_ci n = (struct list_head *) (start + i * node_size); 4406881f68fSopenharmony_ci list_add_tail(n, &slab->freelist); 4416881f68fSopenharmony_ci } 4426881f68fSopenharmony_ci list_add_tail(&slab->list, &f->partial_slabs); 4436881f68fSopenharmony_ci 4446881f68fSopenharmony_ci return 0; 4456881f68fSopenharmony_ci} 4466881f68fSopenharmony_ci 4476881f68fSopenharmony_cistatic struct node *alloc_node(struct fuse *f) 4486881f68fSopenharmony_ci{ 4496881f68fSopenharmony_ci struct node_slab *slab; 4506881f68fSopenharmony_ci struct list_head *node; 4516881f68fSopenharmony_ci 4526881f68fSopenharmony_ci if (list_empty(&f->partial_slabs)) { 4536881f68fSopenharmony_ci int res = alloc_slab(f); 4546881f68fSopenharmony_ci if (res != 0) 4556881f68fSopenharmony_ci return NULL; 4566881f68fSopenharmony_ci } 4576881f68fSopenharmony_ci slab = list_to_slab(f->partial_slabs.next); 4586881f68fSopenharmony_ci slab->used++; 4596881f68fSopenharmony_ci node = slab->freelist.next; 4606881f68fSopenharmony_ci list_del(node); 4616881f68fSopenharmony_ci if (list_empty(&slab->freelist)) { 4626881f68fSopenharmony_ci list_del(&slab->list); 4636881f68fSopenharmony_ci list_add_tail(&slab->list, &f->full_slabs); 4646881f68fSopenharmony_ci } 4656881f68fSopenharmony_ci memset(node, 0, sizeof(struct node)); 4666881f68fSopenharmony_ci 4676881f68fSopenharmony_ci return (struct node *) node; 4686881f68fSopenharmony_ci} 4696881f68fSopenharmony_ci 4706881f68fSopenharmony_cistatic void free_slab(struct fuse *f, struct node_slab *slab) 4716881f68fSopenharmony_ci{ 4726881f68fSopenharmony_ci int res; 4736881f68fSopenharmony_ci 4746881f68fSopenharmony_ci list_del(&slab->list); 4756881f68fSopenharmony_ci res = munmap(slab, f->pagesize); 4766881f68fSopenharmony_ci if (res == -1) 4776881f68fSopenharmony_ci fuse_log(FUSE_LOG_WARNING, "fuse warning: munmap(%p) failed\n", 4786881f68fSopenharmony_ci slab); 4796881f68fSopenharmony_ci} 4806881f68fSopenharmony_ci 4816881f68fSopenharmony_cistatic void free_node_mem(struct fuse *f, struct node *node) 4826881f68fSopenharmony_ci{ 4836881f68fSopenharmony_ci struct node_slab *slab = node_to_slab(f, node); 4846881f68fSopenharmony_ci struct list_head *n = (struct list_head *) node; 4856881f68fSopenharmony_ci 4866881f68fSopenharmony_ci slab->used--; 4876881f68fSopenharmony_ci if (slab->used) { 4886881f68fSopenharmony_ci if (list_empty(&slab->freelist)) { 4896881f68fSopenharmony_ci list_del(&slab->list); 4906881f68fSopenharmony_ci list_add_tail(&slab->list, &f->partial_slabs); 4916881f68fSopenharmony_ci } 4926881f68fSopenharmony_ci list_add_head(n, &slab->freelist); 4936881f68fSopenharmony_ci } else { 4946881f68fSopenharmony_ci free_slab(f, slab); 4956881f68fSopenharmony_ci } 4966881f68fSopenharmony_ci} 4976881f68fSopenharmony_ci#else 4986881f68fSopenharmony_cistatic struct node *alloc_node(struct fuse *f) 4996881f68fSopenharmony_ci{ 5006881f68fSopenharmony_ci return (struct node *) calloc(1, get_node_size(f)); 5016881f68fSopenharmony_ci} 5026881f68fSopenharmony_ci 5036881f68fSopenharmony_cistatic void free_node_mem(struct fuse *f, struct node *node) 5046881f68fSopenharmony_ci{ 5056881f68fSopenharmony_ci (void) f; 5066881f68fSopenharmony_ci free(node); 5076881f68fSopenharmony_ci} 5086881f68fSopenharmony_ci#endif 5096881f68fSopenharmony_ci 5106881f68fSopenharmony_cistatic size_t id_hash(struct fuse *f, fuse_ino_t ino) 5116881f68fSopenharmony_ci{ 5126881f68fSopenharmony_ci uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; 5136881f68fSopenharmony_ci uint64_t oldhash = hash % (f->id_table.size / 2); 5146881f68fSopenharmony_ci 5156881f68fSopenharmony_ci if (oldhash >= f->id_table.split) 5166881f68fSopenharmony_ci return oldhash; 5176881f68fSopenharmony_ci else 5186881f68fSopenharmony_ci return hash; 5196881f68fSopenharmony_ci} 5206881f68fSopenharmony_ci 5216881f68fSopenharmony_cistatic struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) 5226881f68fSopenharmony_ci{ 5236881f68fSopenharmony_ci size_t hash = id_hash(f, nodeid); 5246881f68fSopenharmony_ci struct node *node; 5256881f68fSopenharmony_ci 5266881f68fSopenharmony_ci for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) 5276881f68fSopenharmony_ci if (node->nodeid == nodeid) 5286881f68fSopenharmony_ci return node; 5296881f68fSopenharmony_ci 5306881f68fSopenharmony_ci return NULL; 5316881f68fSopenharmony_ci} 5326881f68fSopenharmony_ci 5336881f68fSopenharmony_cistatic struct node *get_node(struct fuse *f, fuse_ino_t nodeid) 5346881f68fSopenharmony_ci{ 5356881f68fSopenharmony_ci struct node *node = get_node_nocheck(f, nodeid); 5366881f68fSopenharmony_ci if (!node) { 5376881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse internal error: node %llu not found\n", 5386881f68fSopenharmony_ci (unsigned long long) nodeid); 5396881f68fSopenharmony_ci abort(); 5406881f68fSopenharmony_ci } 5416881f68fSopenharmony_ci return node; 5426881f68fSopenharmony_ci} 5436881f68fSopenharmony_ci 5446881f68fSopenharmony_cistatic void curr_time(struct timespec *now); 5456881f68fSopenharmony_cistatic double diff_timespec(const struct timespec *t1, 5466881f68fSopenharmony_ci const struct timespec *t2); 5476881f68fSopenharmony_ci 5486881f68fSopenharmony_cistatic void remove_node_lru(struct node *node) 5496881f68fSopenharmony_ci{ 5506881f68fSopenharmony_ci struct node_lru *lnode = node_lru(node); 5516881f68fSopenharmony_ci list_del(&lnode->lru); 5526881f68fSopenharmony_ci init_list_head(&lnode->lru); 5536881f68fSopenharmony_ci} 5546881f68fSopenharmony_ci 5556881f68fSopenharmony_cistatic void set_forget_time(struct fuse *f, struct node *node) 5566881f68fSopenharmony_ci{ 5576881f68fSopenharmony_ci struct node_lru *lnode = node_lru(node); 5586881f68fSopenharmony_ci 5596881f68fSopenharmony_ci list_del(&lnode->lru); 5606881f68fSopenharmony_ci list_add_tail(&lnode->lru, &f->lru_table); 5616881f68fSopenharmony_ci curr_time(&lnode->forget_time); 5626881f68fSopenharmony_ci} 5636881f68fSopenharmony_ci 5646881f68fSopenharmony_cistatic void free_node(struct fuse *f, struct node *node) 5656881f68fSopenharmony_ci{ 5666881f68fSopenharmony_ci if (node->name != node->inline_name) 5676881f68fSopenharmony_ci free(node->name); 5686881f68fSopenharmony_ci free_node_mem(f, node); 5696881f68fSopenharmony_ci} 5706881f68fSopenharmony_ci 5716881f68fSopenharmony_cistatic void node_table_reduce(struct node_table *t) 5726881f68fSopenharmony_ci{ 5736881f68fSopenharmony_ci size_t newsize = t->size / 2; 5746881f68fSopenharmony_ci void *newarray; 5756881f68fSopenharmony_ci 5766881f68fSopenharmony_ci if (newsize < NODE_TABLE_MIN_SIZE) 5776881f68fSopenharmony_ci return; 5786881f68fSopenharmony_ci 5796881f68fSopenharmony_ci newarray = realloc(t->array, sizeof(struct node *) * newsize); 5806881f68fSopenharmony_ci if (newarray != NULL) 5816881f68fSopenharmony_ci t->array = newarray; 5826881f68fSopenharmony_ci 5836881f68fSopenharmony_ci t->size = newsize; 5846881f68fSopenharmony_ci t->split = t->size / 2; 5856881f68fSopenharmony_ci} 5866881f68fSopenharmony_ci 5876881f68fSopenharmony_cistatic void remerge_id(struct fuse *f) 5886881f68fSopenharmony_ci{ 5896881f68fSopenharmony_ci struct node_table *t = &f->id_table; 5906881f68fSopenharmony_ci int iter; 5916881f68fSopenharmony_ci 5926881f68fSopenharmony_ci if (t->split == 0) 5936881f68fSopenharmony_ci node_table_reduce(t); 5946881f68fSopenharmony_ci 5956881f68fSopenharmony_ci for (iter = 8; t->split > 0 && iter; iter--) { 5966881f68fSopenharmony_ci struct node **upper; 5976881f68fSopenharmony_ci 5986881f68fSopenharmony_ci t->split--; 5996881f68fSopenharmony_ci upper = &t->array[t->split + t->size / 2]; 6006881f68fSopenharmony_ci if (*upper) { 6016881f68fSopenharmony_ci struct node **nodep; 6026881f68fSopenharmony_ci 6036881f68fSopenharmony_ci for (nodep = &t->array[t->split]; *nodep; 6046881f68fSopenharmony_ci nodep = &(*nodep)->id_next); 6056881f68fSopenharmony_ci 6066881f68fSopenharmony_ci *nodep = *upper; 6076881f68fSopenharmony_ci *upper = NULL; 6086881f68fSopenharmony_ci break; 6096881f68fSopenharmony_ci } 6106881f68fSopenharmony_ci } 6116881f68fSopenharmony_ci} 6126881f68fSopenharmony_ci 6136881f68fSopenharmony_cistatic void unhash_id(struct fuse *f, struct node *node) 6146881f68fSopenharmony_ci{ 6156881f68fSopenharmony_ci struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; 6166881f68fSopenharmony_ci 6176881f68fSopenharmony_ci for (; *nodep != NULL; nodep = &(*nodep)->id_next) 6186881f68fSopenharmony_ci if (*nodep == node) { 6196881f68fSopenharmony_ci *nodep = node->id_next; 6206881f68fSopenharmony_ci f->id_table.use--; 6216881f68fSopenharmony_ci 6226881f68fSopenharmony_ci if(f->id_table.use < f->id_table.size / 4) 6236881f68fSopenharmony_ci remerge_id(f); 6246881f68fSopenharmony_ci return; 6256881f68fSopenharmony_ci } 6266881f68fSopenharmony_ci} 6276881f68fSopenharmony_ci 6286881f68fSopenharmony_cistatic int node_table_resize(struct node_table *t) 6296881f68fSopenharmony_ci{ 6306881f68fSopenharmony_ci size_t newsize = t->size * 2; 6316881f68fSopenharmony_ci void *newarray; 6326881f68fSopenharmony_ci 6336881f68fSopenharmony_ci newarray = realloc(t->array, sizeof(struct node *) * newsize); 6346881f68fSopenharmony_ci if (newarray == NULL) 6356881f68fSopenharmony_ci return -1; 6366881f68fSopenharmony_ci 6376881f68fSopenharmony_ci t->array = newarray; 6386881f68fSopenharmony_ci memset(t->array + t->size, 0, t->size * sizeof(struct node *)); 6396881f68fSopenharmony_ci t->size = newsize; 6406881f68fSopenharmony_ci t->split = 0; 6416881f68fSopenharmony_ci 6426881f68fSopenharmony_ci return 0; 6436881f68fSopenharmony_ci} 6446881f68fSopenharmony_ci 6456881f68fSopenharmony_cistatic void rehash_id(struct fuse *f) 6466881f68fSopenharmony_ci{ 6476881f68fSopenharmony_ci struct node_table *t = &f->id_table; 6486881f68fSopenharmony_ci struct node **nodep; 6496881f68fSopenharmony_ci struct node **next; 6506881f68fSopenharmony_ci size_t hash; 6516881f68fSopenharmony_ci 6526881f68fSopenharmony_ci if (t->split == t->size / 2) 6536881f68fSopenharmony_ci return; 6546881f68fSopenharmony_ci 6556881f68fSopenharmony_ci hash = t->split; 6566881f68fSopenharmony_ci t->split++; 6576881f68fSopenharmony_ci for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { 6586881f68fSopenharmony_ci struct node *node = *nodep; 6596881f68fSopenharmony_ci size_t newhash = id_hash(f, node->nodeid); 6606881f68fSopenharmony_ci 6616881f68fSopenharmony_ci if (newhash != hash) { 6626881f68fSopenharmony_ci next = nodep; 6636881f68fSopenharmony_ci *nodep = node->id_next; 6646881f68fSopenharmony_ci node->id_next = t->array[newhash]; 6656881f68fSopenharmony_ci t->array[newhash] = node; 6666881f68fSopenharmony_ci } else { 6676881f68fSopenharmony_ci next = &node->id_next; 6686881f68fSopenharmony_ci } 6696881f68fSopenharmony_ci } 6706881f68fSopenharmony_ci if (t->split == t->size / 2) 6716881f68fSopenharmony_ci node_table_resize(t); 6726881f68fSopenharmony_ci} 6736881f68fSopenharmony_ci 6746881f68fSopenharmony_cistatic void hash_id(struct fuse *f, struct node *node) 6756881f68fSopenharmony_ci{ 6766881f68fSopenharmony_ci size_t hash = id_hash(f, node->nodeid); 6776881f68fSopenharmony_ci node->id_next = f->id_table.array[hash]; 6786881f68fSopenharmony_ci f->id_table.array[hash] = node; 6796881f68fSopenharmony_ci f->id_table.use++; 6806881f68fSopenharmony_ci 6816881f68fSopenharmony_ci if (f->id_table.use >= f->id_table.size / 2) 6826881f68fSopenharmony_ci rehash_id(f); 6836881f68fSopenharmony_ci} 6846881f68fSopenharmony_ci 6856881f68fSopenharmony_cistatic size_t name_hash(struct fuse *f, fuse_ino_t parent, 6866881f68fSopenharmony_ci const char *name) 6876881f68fSopenharmony_ci{ 6886881f68fSopenharmony_ci uint64_t hash = parent; 6896881f68fSopenharmony_ci uint64_t oldhash; 6906881f68fSopenharmony_ci 6916881f68fSopenharmony_ci for (; *name; name++) 6926881f68fSopenharmony_ci hash = hash * 31 + (unsigned char) *name; 6936881f68fSopenharmony_ci 6946881f68fSopenharmony_ci hash %= f->name_table.size; 6956881f68fSopenharmony_ci oldhash = hash % (f->name_table.size / 2); 6966881f68fSopenharmony_ci if (oldhash >= f->name_table.split) 6976881f68fSopenharmony_ci return oldhash; 6986881f68fSopenharmony_ci else 6996881f68fSopenharmony_ci return hash; 7006881f68fSopenharmony_ci} 7016881f68fSopenharmony_ci 7026881f68fSopenharmony_cistatic void unref_node(struct fuse *f, struct node *node); 7036881f68fSopenharmony_ci 7046881f68fSopenharmony_cistatic void remerge_name(struct fuse *f) 7056881f68fSopenharmony_ci{ 7066881f68fSopenharmony_ci struct node_table *t = &f->name_table; 7076881f68fSopenharmony_ci int iter; 7086881f68fSopenharmony_ci 7096881f68fSopenharmony_ci if (t->split == 0) 7106881f68fSopenharmony_ci node_table_reduce(t); 7116881f68fSopenharmony_ci 7126881f68fSopenharmony_ci for (iter = 8; t->split > 0 && iter; iter--) { 7136881f68fSopenharmony_ci struct node **upper; 7146881f68fSopenharmony_ci 7156881f68fSopenharmony_ci t->split--; 7166881f68fSopenharmony_ci upper = &t->array[t->split + t->size / 2]; 7176881f68fSopenharmony_ci if (*upper) { 7186881f68fSopenharmony_ci struct node **nodep; 7196881f68fSopenharmony_ci 7206881f68fSopenharmony_ci for (nodep = &t->array[t->split]; *nodep; 7216881f68fSopenharmony_ci nodep = &(*nodep)->name_next); 7226881f68fSopenharmony_ci 7236881f68fSopenharmony_ci *nodep = *upper; 7246881f68fSopenharmony_ci *upper = NULL; 7256881f68fSopenharmony_ci break; 7266881f68fSopenharmony_ci } 7276881f68fSopenharmony_ci } 7286881f68fSopenharmony_ci} 7296881f68fSopenharmony_ci 7306881f68fSopenharmony_cistatic void unhash_name(struct fuse *f, struct node *node) 7316881f68fSopenharmony_ci{ 7326881f68fSopenharmony_ci if (node->name) { 7336881f68fSopenharmony_ci size_t hash = name_hash(f, node->parent->nodeid, node->name); 7346881f68fSopenharmony_ci struct node **nodep = &f->name_table.array[hash]; 7356881f68fSopenharmony_ci 7366881f68fSopenharmony_ci for (; *nodep != NULL; nodep = &(*nodep)->name_next) 7376881f68fSopenharmony_ci if (*nodep == node) { 7386881f68fSopenharmony_ci *nodep = node->name_next; 7396881f68fSopenharmony_ci node->name_next = NULL; 7406881f68fSopenharmony_ci unref_node(f, node->parent); 7416881f68fSopenharmony_ci if (node->name != node->inline_name) 7426881f68fSopenharmony_ci free(node->name); 7436881f68fSopenharmony_ci node->name = NULL; 7446881f68fSopenharmony_ci node->parent = NULL; 7456881f68fSopenharmony_ci f->name_table.use--; 7466881f68fSopenharmony_ci 7476881f68fSopenharmony_ci if (f->name_table.use < f->name_table.size / 4) 7486881f68fSopenharmony_ci remerge_name(f); 7496881f68fSopenharmony_ci return; 7506881f68fSopenharmony_ci } 7516881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, 7526881f68fSopenharmony_ci "fuse internal error: unable to unhash node: %llu\n", 7536881f68fSopenharmony_ci (unsigned long long) node->nodeid); 7546881f68fSopenharmony_ci abort(); 7556881f68fSopenharmony_ci } 7566881f68fSopenharmony_ci} 7576881f68fSopenharmony_ci 7586881f68fSopenharmony_cistatic void rehash_name(struct fuse *f) 7596881f68fSopenharmony_ci{ 7606881f68fSopenharmony_ci struct node_table *t = &f->name_table; 7616881f68fSopenharmony_ci struct node **nodep; 7626881f68fSopenharmony_ci struct node **next; 7636881f68fSopenharmony_ci size_t hash; 7646881f68fSopenharmony_ci 7656881f68fSopenharmony_ci if (t->split == t->size / 2) 7666881f68fSopenharmony_ci return; 7676881f68fSopenharmony_ci 7686881f68fSopenharmony_ci hash = t->split; 7696881f68fSopenharmony_ci t->split++; 7706881f68fSopenharmony_ci for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { 7716881f68fSopenharmony_ci struct node *node = *nodep; 7726881f68fSopenharmony_ci size_t newhash = name_hash(f, node->parent->nodeid, node->name); 7736881f68fSopenharmony_ci 7746881f68fSopenharmony_ci if (newhash != hash) { 7756881f68fSopenharmony_ci next = nodep; 7766881f68fSopenharmony_ci *nodep = node->name_next; 7776881f68fSopenharmony_ci node->name_next = t->array[newhash]; 7786881f68fSopenharmony_ci t->array[newhash] = node; 7796881f68fSopenharmony_ci } else { 7806881f68fSopenharmony_ci next = &node->name_next; 7816881f68fSopenharmony_ci } 7826881f68fSopenharmony_ci } 7836881f68fSopenharmony_ci if (t->split == t->size / 2) 7846881f68fSopenharmony_ci node_table_resize(t); 7856881f68fSopenharmony_ci} 7866881f68fSopenharmony_ci 7876881f68fSopenharmony_cistatic int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, 7886881f68fSopenharmony_ci const char *name) 7896881f68fSopenharmony_ci{ 7906881f68fSopenharmony_ci size_t hash = name_hash(f, parentid, name); 7916881f68fSopenharmony_ci struct node *parent = get_node(f, parentid); 7926881f68fSopenharmony_ci if (strlen(name) < sizeof(node->inline_name)) { 7936881f68fSopenharmony_ci strcpy(node->inline_name, name); 7946881f68fSopenharmony_ci node->name = node->inline_name; 7956881f68fSopenharmony_ci } else { 7966881f68fSopenharmony_ci node->name = strdup(name); 7976881f68fSopenharmony_ci if (node->name == NULL) 7986881f68fSopenharmony_ci return -1; 7996881f68fSopenharmony_ci } 8006881f68fSopenharmony_ci 8016881f68fSopenharmony_ci parent->refctr ++; 8026881f68fSopenharmony_ci node->parent = parent; 8036881f68fSopenharmony_ci node->name_next = f->name_table.array[hash]; 8046881f68fSopenharmony_ci f->name_table.array[hash] = node; 8056881f68fSopenharmony_ci f->name_table.use++; 8066881f68fSopenharmony_ci 8076881f68fSopenharmony_ci if (f->name_table.use >= f->name_table.size / 2) 8086881f68fSopenharmony_ci rehash_name(f); 8096881f68fSopenharmony_ci 8106881f68fSopenharmony_ci return 0; 8116881f68fSopenharmony_ci} 8126881f68fSopenharmony_ci 8136881f68fSopenharmony_cistatic void delete_node(struct fuse *f, struct node *node) 8146881f68fSopenharmony_ci{ 8156881f68fSopenharmony_ci if (f->conf.debug) 8166881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "DELETE: %llu\n", 8176881f68fSopenharmony_ci (unsigned long long) node->nodeid); 8186881f68fSopenharmony_ci 8196881f68fSopenharmony_ci assert(node->treelock == 0); 8206881f68fSopenharmony_ci unhash_name(f, node); 8216881f68fSopenharmony_ci if (lru_enabled(f)) 8226881f68fSopenharmony_ci remove_node_lru(node); 8236881f68fSopenharmony_ci unhash_id(f, node); 8246881f68fSopenharmony_ci free_node(f, node); 8256881f68fSopenharmony_ci} 8266881f68fSopenharmony_ci 8276881f68fSopenharmony_cistatic void unref_node(struct fuse *f, struct node *node) 8286881f68fSopenharmony_ci{ 8296881f68fSopenharmony_ci assert(node->refctr > 0); 8306881f68fSopenharmony_ci node->refctr --; 8316881f68fSopenharmony_ci if (!node->refctr) 8326881f68fSopenharmony_ci delete_node(f, node); 8336881f68fSopenharmony_ci} 8346881f68fSopenharmony_ci 8356881f68fSopenharmony_cistatic fuse_ino_t next_id(struct fuse *f) 8366881f68fSopenharmony_ci{ 8376881f68fSopenharmony_ci do { 8386881f68fSopenharmony_ci f->ctr = (f->ctr + 1) & 0xffffffff; 8396881f68fSopenharmony_ci if (!f->ctr) 8406881f68fSopenharmony_ci f->generation ++; 8416881f68fSopenharmony_ci } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || 8426881f68fSopenharmony_ci get_node_nocheck(f, f->ctr) != NULL); 8436881f68fSopenharmony_ci return f->ctr; 8446881f68fSopenharmony_ci} 8456881f68fSopenharmony_ci 8466881f68fSopenharmony_cistatic struct node *lookup_node(struct fuse *f, fuse_ino_t parent, 8476881f68fSopenharmony_ci const char *name) 8486881f68fSopenharmony_ci{ 8496881f68fSopenharmony_ci size_t hash = name_hash(f, parent, name); 8506881f68fSopenharmony_ci struct node *node; 8516881f68fSopenharmony_ci 8526881f68fSopenharmony_ci for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) 8536881f68fSopenharmony_ci if (node->parent->nodeid == parent && 8546881f68fSopenharmony_ci strcmp(node->name, name) == 0) 8556881f68fSopenharmony_ci return node; 8566881f68fSopenharmony_ci 8576881f68fSopenharmony_ci return NULL; 8586881f68fSopenharmony_ci} 8596881f68fSopenharmony_ci 8606881f68fSopenharmony_cistatic void inc_nlookup(struct node *node) 8616881f68fSopenharmony_ci{ 8626881f68fSopenharmony_ci if (!node->nlookup) 8636881f68fSopenharmony_ci node->refctr++; 8646881f68fSopenharmony_ci node->nlookup++; 8656881f68fSopenharmony_ci} 8666881f68fSopenharmony_ci 8676881f68fSopenharmony_cistatic struct node *find_node(struct fuse *f, fuse_ino_t parent, 8686881f68fSopenharmony_ci const char *name) 8696881f68fSopenharmony_ci{ 8706881f68fSopenharmony_ci struct node *node; 8716881f68fSopenharmony_ci 8726881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 8736881f68fSopenharmony_ci if (!name) 8746881f68fSopenharmony_ci node = get_node(f, parent); 8756881f68fSopenharmony_ci else 8766881f68fSopenharmony_ci node = lookup_node(f, parent, name); 8776881f68fSopenharmony_ci if (node == NULL) { 8786881f68fSopenharmony_ci node = alloc_node(f); 8796881f68fSopenharmony_ci if (node == NULL) 8806881f68fSopenharmony_ci goto out_err; 8816881f68fSopenharmony_ci 8826881f68fSopenharmony_ci node->nodeid = next_id(f); 8836881f68fSopenharmony_ci node->generation = f->generation; 8846881f68fSopenharmony_ci if (f->conf.remember) 8856881f68fSopenharmony_ci inc_nlookup(node); 8866881f68fSopenharmony_ci 8876881f68fSopenharmony_ci if (hash_name(f, node, parent, name) == -1) { 8886881f68fSopenharmony_ci free_node(f, node); 8896881f68fSopenharmony_ci node = NULL; 8906881f68fSopenharmony_ci goto out_err; 8916881f68fSopenharmony_ci } 8926881f68fSopenharmony_ci hash_id(f, node); 8936881f68fSopenharmony_ci if (lru_enabled(f)) { 8946881f68fSopenharmony_ci struct node_lru *lnode = node_lru(node); 8956881f68fSopenharmony_ci init_list_head(&lnode->lru); 8966881f68fSopenharmony_ci } 8976881f68fSopenharmony_ci } else if (lru_enabled(f) && node->nlookup == 1) { 8986881f68fSopenharmony_ci remove_node_lru(node); 8996881f68fSopenharmony_ci } 9006881f68fSopenharmony_ci inc_nlookup(node); 9016881f68fSopenharmony_ciout_err: 9026881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 9036881f68fSopenharmony_ci return node; 9046881f68fSopenharmony_ci} 9056881f68fSopenharmony_ci 9066881f68fSopenharmony_cistatic int lookup_path_in_cache(struct fuse *f, 9076881f68fSopenharmony_ci const char *path, fuse_ino_t *inop) 9086881f68fSopenharmony_ci{ 9096881f68fSopenharmony_ci char *tmp = strdup(path); 9106881f68fSopenharmony_ci if (!tmp) 9116881f68fSopenharmony_ci return -ENOMEM; 9126881f68fSopenharmony_ci 9136881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 9146881f68fSopenharmony_ci fuse_ino_t ino = FUSE_ROOT_ID; 9156881f68fSopenharmony_ci 9166881f68fSopenharmony_ci int err = 0; 9176881f68fSopenharmony_ci char *save_ptr; 9186881f68fSopenharmony_ci char *path_element = strtok_r(tmp, "/", &save_ptr); 9196881f68fSopenharmony_ci while (path_element != NULL) { 9206881f68fSopenharmony_ci struct node *node = lookup_node(f, ino, path_element); 9216881f68fSopenharmony_ci if (node == NULL) { 9226881f68fSopenharmony_ci err = -ENOENT; 9236881f68fSopenharmony_ci break; 9246881f68fSopenharmony_ci } 9256881f68fSopenharmony_ci ino = node->nodeid; 9266881f68fSopenharmony_ci path_element = strtok_r(NULL, "/", &save_ptr); 9276881f68fSopenharmony_ci } 9286881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 9296881f68fSopenharmony_ci free(tmp); 9306881f68fSopenharmony_ci 9316881f68fSopenharmony_ci if (!err) 9326881f68fSopenharmony_ci *inop = ino; 9336881f68fSopenharmony_ci return err; 9346881f68fSopenharmony_ci} 9356881f68fSopenharmony_ci 9366881f68fSopenharmony_cistatic char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) 9376881f68fSopenharmony_ci{ 9386881f68fSopenharmony_ci size_t len = strlen(name); 9396881f68fSopenharmony_ci 9406881f68fSopenharmony_ci if (s - len <= *buf) { 9416881f68fSopenharmony_ci unsigned pathlen = *bufsize - (s - *buf); 9426881f68fSopenharmony_ci unsigned newbufsize = *bufsize; 9436881f68fSopenharmony_ci char *newbuf; 9446881f68fSopenharmony_ci 9456881f68fSopenharmony_ci while (newbufsize < pathlen + len + 1) { 9466881f68fSopenharmony_ci if (newbufsize >= 0x80000000) 9476881f68fSopenharmony_ci newbufsize = 0xffffffff; 9486881f68fSopenharmony_ci else 9496881f68fSopenharmony_ci newbufsize *= 2; 9506881f68fSopenharmony_ci } 9516881f68fSopenharmony_ci 9526881f68fSopenharmony_ci newbuf = realloc(*buf, newbufsize); 9536881f68fSopenharmony_ci if (newbuf == NULL) 9546881f68fSopenharmony_ci return NULL; 9556881f68fSopenharmony_ci 9566881f68fSopenharmony_ci *buf = newbuf; 9576881f68fSopenharmony_ci s = newbuf + newbufsize - pathlen; 9586881f68fSopenharmony_ci memmove(s, newbuf + *bufsize - pathlen, pathlen); 9596881f68fSopenharmony_ci *bufsize = newbufsize; 9606881f68fSopenharmony_ci } 9616881f68fSopenharmony_ci s -= len; 9626881f68fSopenharmony_ci memcpy(s, name, len); 9636881f68fSopenharmony_ci s--; 9646881f68fSopenharmony_ci *s = '/'; 9656881f68fSopenharmony_ci 9666881f68fSopenharmony_ci return s; 9676881f68fSopenharmony_ci} 9686881f68fSopenharmony_ci 9696881f68fSopenharmony_cistatic void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, 9706881f68fSopenharmony_ci struct node *end) 9716881f68fSopenharmony_ci{ 9726881f68fSopenharmony_ci struct node *node; 9736881f68fSopenharmony_ci 9746881f68fSopenharmony_ci if (wnode) { 9756881f68fSopenharmony_ci assert(wnode->treelock == TREELOCK_WRITE); 9766881f68fSopenharmony_ci wnode->treelock = 0; 9776881f68fSopenharmony_ci } 9786881f68fSopenharmony_ci 9796881f68fSopenharmony_ci for (node = get_node(f, nodeid); 9806881f68fSopenharmony_ci node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { 9816881f68fSopenharmony_ci assert(node->treelock != 0); 9826881f68fSopenharmony_ci assert(node->treelock != TREELOCK_WAIT_OFFSET); 9836881f68fSopenharmony_ci assert(node->treelock != TREELOCK_WRITE); 9846881f68fSopenharmony_ci node->treelock--; 9856881f68fSopenharmony_ci if (node->treelock == TREELOCK_WAIT_OFFSET) 9866881f68fSopenharmony_ci node->treelock = 0; 9876881f68fSopenharmony_ci } 9886881f68fSopenharmony_ci} 9896881f68fSopenharmony_ci 9906881f68fSopenharmony_cistatic int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, 9916881f68fSopenharmony_ci char **path, struct node **wnodep, bool need_lock) 9926881f68fSopenharmony_ci{ 9936881f68fSopenharmony_ci unsigned bufsize = 256; 9946881f68fSopenharmony_ci char *buf; 9956881f68fSopenharmony_ci char *s; 9966881f68fSopenharmony_ci struct node *node; 9976881f68fSopenharmony_ci struct node *wnode = NULL; 9986881f68fSopenharmony_ci int err; 9996881f68fSopenharmony_ci 10006881f68fSopenharmony_ci *path = NULL; 10016881f68fSopenharmony_ci 10026881f68fSopenharmony_ci err = -ENOMEM; 10036881f68fSopenharmony_ci buf = malloc(bufsize); 10046881f68fSopenharmony_ci if (buf == NULL) 10056881f68fSopenharmony_ci goto out_err; 10066881f68fSopenharmony_ci 10076881f68fSopenharmony_ci s = buf + bufsize - 1; 10086881f68fSopenharmony_ci *s = '\0'; 10096881f68fSopenharmony_ci 10106881f68fSopenharmony_ci if (name != NULL) { 10116881f68fSopenharmony_ci s = add_name(&buf, &bufsize, s, name); 10126881f68fSopenharmony_ci err = -ENOMEM; 10136881f68fSopenharmony_ci if (s == NULL) 10146881f68fSopenharmony_ci goto out_free; 10156881f68fSopenharmony_ci } 10166881f68fSopenharmony_ci 10176881f68fSopenharmony_ci if (wnodep) { 10186881f68fSopenharmony_ci assert(need_lock); 10196881f68fSopenharmony_ci wnode = lookup_node(f, nodeid, name); 10206881f68fSopenharmony_ci if (wnode) { 10216881f68fSopenharmony_ci if (wnode->treelock != 0) { 10226881f68fSopenharmony_ci if (wnode->treelock > 0) 10236881f68fSopenharmony_ci wnode->treelock += TREELOCK_WAIT_OFFSET; 10246881f68fSopenharmony_ci err = -EAGAIN; 10256881f68fSopenharmony_ci goto out_free; 10266881f68fSopenharmony_ci } 10276881f68fSopenharmony_ci wnode->treelock = TREELOCK_WRITE; 10286881f68fSopenharmony_ci } 10296881f68fSopenharmony_ci } 10306881f68fSopenharmony_ci 10316881f68fSopenharmony_ci for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; 10326881f68fSopenharmony_ci node = node->parent) { 10336881f68fSopenharmony_ci err = -ESTALE; 10346881f68fSopenharmony_ci if (node->name == NULL || node->parent == NULL) 10356881f68fSopenharmony_ci goto out_unlock; 10366881f68fSopenharmony_ci 10376881f68fSopenharmony_ci err = -ENOMEM; 10386881f68fSopenharmony_ci s = add_name(&buf, &bufsize, s, node->name); 10396881f68fSopenharmony_ci if (s == NULL) 10406881f68fSopenharmony_ci goto out_unlock; 10416881f68fSopenharmony_ci 10426881f68fSopenharmony_ci if (need_lock) { 10436881f68fSopenharmony_ci err = -EAGAIN; 10446881f68fSopenharmony_ci if (node->treelock < 0) 10456881f68fSopenharmony_ci goto out_unlock; 10466881f68fSopenharmony_ci 10476881f68fSopenharmony_ci node->treelock++; 10486881f68fSopenharmony_ci } 10496881f68fSopenharmony_ci } 10506881f68fSopenharmony_ci 10516881f68fSopenharmony_ci if (s[0]) 10526881f68fSopenharmony_ci memmove(buf, s, bufsize - (s - buf)); 10536881f68fSopenharmony_ci else 10546881f68fSopenharmony_ci strcpy(buf, "/"); 10556881f68fSopenharmony_ci 10566881f68fSopenharmony_ci *path = buf; 10576881f68fSopenharmony_ci if (wnodep) 10586881f68fSopenharmony_ci *wnodep = wnode; 10596881f68fSopenharmony_ci 10606881f68fSopenharmony_ci return 0; 10616881f68fSopenharmony_ci 10626881f68fSopenharmony_ci out_unlock: 10636881f68fSopenharmony_ci if (need_lock) 10646881f68fSopenharmony_ci unlock_path(f, nodeid, wnode, node); 10656881f68fSopenharmony_ci out_free: 10666881f68fSopenharmony_ci free(buf); 10676881f68fSopenharmony_ci 10686881f68fSopenharmony_ci out_err: 10696881f68fSopenharmony_ci return err; 10706881f68fSopenharmony_ci} 10716881f68fSopenharmony_ci 10726881f68fSopenharmony_cistatic int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, 10736881f68fSopenharmony_ci fuse_ino_t nodeid2, const char *name2, 10746881f68fSopenharmony_ci char **path1, char **path2, 10756881f68fSopenharmony_ci struct node **wnode1, struct node **wnode2) 10766881f68fSopenharmony_ci{ 10776881f68fSopenharmony_ci int err; 10786881f68fSopenharmony_ci 10796881f68fSopenharmony_ci /* FIXME: locking two paths needs deadlock checking */ 10806881f68fSopenharmony_ci err = try_get_path(f, nodeid1, name1, path1, wnode1, true); 10816881f68fSopenharmony_ci if (!err) { 10826881f68fSopenharmony_ci err = try_get_path(f, nodeid2, name2, path2, wnode2, true); 10836881f68fSopenharmony_ci if (err) { 10846881f68fSopenharmony_ci struct node *wn1 = wnode1 ? *wnode1 : NULL; 10856881f68fSopenharmony_ci 10866881f68fSopenharmony_ci unlock_path(f, nodeid1, wn1, NULL); 10876881f68fSopenharmony_ci free(*path1); 10886881f68fSopenharmony_ci } 10896881f68fSopenharmony_ci } 10906881f68fSopenharmony_ci return err; 10916881f68fSopenharmony_ci} 10926881f68fSopenharmony_ci 10936881f68fSopenharmony_cistatic void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe) 10946881f68fSopenharmony_ci{ 10956881f68fSopenharmony_ci int err; 10966881f68fSopenharmony_ci 10976881f68fSopenharmony_ci if (!qe->path1) { 10986881f68fSopenharmony_ci /* Just waiting for it to be unlocked */ 10996881f68fSopenharmony_ci if (get_node(f, qe->nodeid1)->treelock == 0) 11006881f68fSopenharmony_ci pthread_cond_signal(&qe->cond); 11016881f68fSopenharmony_ci 11026881f68fSopenharmony_ci return; 11036881f68fSopenharmony_ci } 11046881f68fSopenharmony_ci 11056881f68fSopenharmony_ci if (qe->done) 11066881f68fSopenharmony_ci return; // Don't try to double-lock the element 11076881f68fSopenharmony_ci 11086881f68fSopenharmony_ci if (!qe->path2) { 11096881f68fSopenharmony_ci err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, 11106881f68fSopenharmony_ci qe->wnode1, true); 11116881f68fSopenharmony_ci } else { 11126881f68fSopenharmony_ci err = try_get_path2(f, qe->nodeid1, qe->name1, qe->nodeid2, 11136881f68fSopenharmony_ci qe->name2, qe->path1, qe->path2, qe->wnode1, 11146881f68fSopenharmony_ci qe->wnode2); 11156881f68fSopenharmony_ci } 11166881f68fSopenharmony_ci 11176881f68fSopenharmony_ci if (err == -EAGAIN) 11186881f68fSopenharmony_ci return; /* keep trying */ 11196881f68fSopenharmony_ci 11206881f68fSopenharmony_ci qe->err = err; 11216881f68fSopenharmony_ci qe->done = true; 11226881f68fSopenharmony_ci pthread_cond_signal(&qe->cond); 11236881f68fSopenharmony_ci} 11246881f68fSopenharmony_ci 11256881f68fSopenharmony_cistatic void wake_up_queued(struct fuse *f) 11266881f68fSopenharmony_ci{ 11276881f68fSopenharmony_ci struct lock_queue_element *qe; 11286881f68fSopenharmony_ci 11296881f68fSopenharmony_ci for (qe = f->lockq; qe != NULL; qe = qe->next) 11306881f68fSopenharmony_ci queue_element_wakeup(f, qe); 11316881f68fSopenharmony_ci} 11326881f68fSopenharmony_ci 11336881f68fSopenharmony_cistatic void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid, 11346881f68fSopenharmony_ci const char *name, bool wr) 11356881f68fSopenharmony_ci{ 11366881f68fSopenharmony_ci if (f->conf.debug) { 11376881f68fSopenharmony_ci struct node *wnode = NULL; 11386881f68fSopenharmony_ci 11396881f68fSopenharmony_ci if (wr) 11406881f68fSopenharmony_ci wnode = lookup_node(f, nodeid, name); 11416881f68fSopenharmony_ci 11426881f68fSopenharmony_ci if (wnode) { 11436881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "%s %llu (w)\n", 11446881f68fSopenharmony_ci msg, (unsigned long long) wnode->nodeid); 11456881f68fSopenharmony_ci } else { 11466881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "%s %llu\n", 11476881f68fSopenharmony_ci msg, (unsigned long long) nodeid); 11486881f68fSopenharmony_ci } 11496881f68fSopenharmony_ci } 11506881f68fSopenharmony_ci} 11516881f68fSopenharmony_ci 11526881f68fSopenharmony_cistatic void queue_path(struct fuse *f, struct lock_queue_element *qe) 11536881f68fSopenharmony_ci{ 11546881f68fSopenharmony_ci struct lock_queue_element **qp; 11556881f68fSopenharmony_ci 11566881f68fSopenharmony_ci qe->done = false; 11576881f68fSopenharmony_ci pthread_cond_init(&qe->cond, NULL); 11586881f68fSopenharmony_ci qe->next = NULL; 11596881f68fSopenharmony_ci for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); 11606881f68fSopenharmony_ci *qp = qe; 11616881f68fSopenharmony_ci} 11626881f68fSopenharmony_ci 11636881f68fSopenharmony_cistatic void dequeue_path(struct fuse *f, struct lock_queue_element *qe) 11646881f68fSopenharmony_ci{ 11656881f68fSopenharmony_ci struct lock_queue_element **qp; 11666881f68fSopenharmony_ci 11676881f68fSopenharmony_ci pthread_cond_destroy(&qe->cond); 11686881f68fSopenharmony_ci for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); 11696881f68fSopenharmony_ci *qp = qe->next; 11706881f68fSopenharmony_ci} 11716881f68fSopenharmony_ci 11726881f68fSopenharmony_cistatic int wait_path(struct fuse *f, struct lock_queue_element *qe) 11736881f68fSopenharmony_ci{ 11746881f68fSopenharmony_ci queue_path(f, qe); 11756881f68fSopenharmony_ci 11766881f68fSopenharmony_ci do { 11776881f68fSopenharmony_ci pthread_cond_wait(&qe->cond, &f->lock); 11786881f68fSopenharmony_ci } while (!qe->done); 11796881f68fSopenharmony_ci 11806881f68fSopenharmony_ci dequeue_path(f, qe); 11816881f68fSopenharmony_ci 11826881f68fSopenharmony_ci return qe->err; 11836881f68fSopenharmony_ci} 11846881f68fSopenharmony_ci 11856881f68fSopenharmony_cistatic int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name, 11866881f68fSopenharmony_ci char **path, struct node **wnode) 11876881f68fSopenharmony_ci{ 11886881f68fSopenharmony_ci int err; 11896881f68fSopenharmony_ci 11906881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 11916881f68fSopenharmony_ci err = try_get_path(f, nodeid, name, path, wnode, true); 11926881f68fSopenharmony_ci if (err == -EAGAIN) { 11936881f68fSopenharmony_ci struct lock_queue_element qe = { 11946881f68fSopenharmony_ci .nodeid1 = nodeid, 11956881f68fSopenharmony_ci .name1 = name, 11966881f68fSopenharmony_ci .path1 = path, 11976881f68fSopenharmony_ci .wnode1 = wnode, 11986881f68fSopenharmony_ci }; 11996881f68fSopenharmony_ci debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); 12006881f68fSopenharmony_ci err = wait_path(f, &qe); 12016881f68fSopenharmony_ci debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); 12026881f68fSopenharmony_ci } 12036881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 12046881f68fSopenharmony_ci 12056881f68fSopenharmony_ci return err; 12066881f68fSopenharmony_ci} 12076881f68fSopenharmony_ci 12086881f68fSopenharmony_cistatic int get_path(struct fuse *f, fuse_ino_t nodeid, char **path) 12096881f68fSopenharmony_ci{ 12106881f68fSopenharmony_ci return get_path_common(f, nodeid, NULL, path, NULL); 12116881f68fSopenharmony_ci} 12126881f68fSopenharmony_ci 12136881f68fSopenharmony_cistatic int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path) 12146881f68fSopenharmony_ci{ 12156881f68fSopenharmony_ci int err = 0; 12166881f68fSopenharmony_ci 12176881f68fSopenharmony_ci if (f->conf.nullpath_ok) { 12186881f68fSopenharmony_ci *path = NULL; 12196881f68fSopenharmony_ci } else { 12206881f68fSopenharmony_ci err = get_path_common(f, nodeid, NULL, path, NULL); 12216881f68fSopenharmony_ci if (err == -ESTALE) 12226881f68fSopenharmony_ci err = 0; 12236881f68fSopenharmony_ci } 12246881f68fSopenharmony_ci 12256881f68fSopenharmony_ci return err; 12266881f68fSopenharmony_ci} 12276881f68fSopenharmony_ci 12286881f68fSopenharmony_cistatic int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name, 12296881f68fSopenharmony_ci char **path) 12306881f68fSopenharmony_ci{ 12316881f68fSopenharmony_ci return get_path_common(f, nodeid, name, path, NULL); 12326881f68fSopenharmony_ci} 12336881f68fSopenharmony_ci 12346881f68fSopenharmony_cistatic int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name, 12356881f68fSopenharmony_ci char **path, struct node **wnode) 12366881f68fSopenharmony_ci{ 12376881f68fSopenharmony_ci return get_path_common(f, nodeid, name, path, wnode); 12386881f68fSopenharmony_ci} 12396881f68fSopenharmony_ci 12406881f68fSopenharmony_ci#if defined(__FreeBSD__) 12416881f68fSopenharmony_ci#define CHECK_DIR_LOOP 12426881f68fSopenharmony_ci#endif 12436881f68fSopenharmony_ci 12446881f68fSopenharmony_ci#if defined(CHECK_DIR_LOOP) 12456881f68fSopenharmony_cistatic int check_dir_loop(struct fuse *f, 12466881f68fSopenharmony_ci fuse_ino_t nodeid1, const char *name1, 12476881f68fSopenharmony_ci fuse_ino_t nodeid2, const char *name2) 12486881f68fSopenharmony_ci{ 12496881f68fSopenharmony_ci struct node *node, *node1, *node2; 12506881f68fSopenharmony_ci fuse_ino_t id1, id2; 12516881f68fSopenharmony_ci 12526881f68fSopenharmony_ci node1 = lookup_node(f, nodeid1, name1); 12536881f68fSopenharmony_ci id1 = node1 ? node1->nodeid : nodeid1; 12546881f68fSopenharmony_ci 12556881f68fSopenharmony_ci node2 = lookup_node(f, nodeid2, name2); 12566881f68fSopenharmony_ci id2 = node2 ? node2->nodeid : nodeid2; 12576881f68fSopenharmony_ci 12586881f68fSopenharmony_ci for (node = get_node(f, id2); node->nodeid != FUSE_ROOT_ID; 12596881f68fSopenharmony_ci node = node->parent) { 12606881f68fSopenharmony_ci if (node->name == NULL || node->parent == NULL) 12616881f68fSopenharmony_ci break; 12626881f68fSopenharmony_ci 12636881f68fSopenharmony_ci if (node->nodeid != id2 && node->nodeid == id1) 12646881f68fSopenharmony_ci return -EINVAL; 12656881f68fSopenharmony_ci } 12666881f68fSopenharmony_ci 12676881f68fSopenharmony_ci if (node2) 12686881f68fSopenharmony_ci { 12696881f68fSopenharmony_ci for (node = get_node(f, id1); node->nodeid != FUSE_ROOT_ID; 12706881f68fSopenharmony_ci node = node->parent) { 12716881f68fSopenharmony_ci if (node->name == NULL || node->parent == NULL) 12726881f68fSopenharmony_ci break; 12736881f68fSopenharmony_ci 12746881f68fSopenharmony_ci if (node->nodeid != id1 && node->nodeid == id2) 12756881f68fSopenharmony_ci return -ENOTEMPTY; 12766881f68fSopenharmony_ci } 12776881f68fSopenharmony_ci } 12786881f68fSopenharmony_ci 12796881f68fSopenharmony_ci return 0; 12806881f68fSopenharmony_ci} 12816881f68fSopenharmony_ci#endif 12826881f68fSopenharmony_ci 12836881f68fSopenharmony_cistatic int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, 12846881f68fSopenharmony_ci fuse_ino_t nodeid2, const char *name2, 12856881f68fSopenharmony_ci char **path1, char **path2, 12866881f68fSopenharmony_ci struct node **wnode1, struct node **wnode2) 12876881f68fSopenharmony_ci{ 12886881f68fSopenharmony_ci int err; 12896881f68fSopenharmony_ci 12906881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 12916881f68fSopenharmony_ci 12926881f68fSopenharmony_ci#if defined(CHECK_DIR_LOOP) 12936881f68fSopenharmony_ci if (name1) 12946881f68fSopenharmony_ci { 12956881f68fSopenharmony_ci // called during rename; perform dir loop check 12966881f68fSopenharmony_ci err = check_dir_loop(f, nodeid1, name1, nodeid2, name2); 12976881f68fSopenharmony_ci if (err) 12986881f68fSopenharmony_ci goto out_unlock; 12996881f68fSopenharmony_ci } 13006881f68fSopenharmony_ci#endif 13016881f68fSopenharmony_ci 13026881f68fSopenharmony_ci err = try_get_path2(f, nodeid1, name1, nodeid2, name2, 13036881f68fSopenharmony_ci path1, path2, wnode1, wnode2); 13046881f68fSopenharmony_ci if (err == -EAGAIN) { 13056881f68fSopenharmony_ci struct lock_queue_element qe = { 13066881f68fSopenharmony_ci .nodeid1 = nodeid1, 13076881f68fSopenharmony_ci .name1 = name1, 13086881f68fSopenharmony_ci .path1 = path1, 13096881f68fSopenharmony_ci .wnode1 = wnode1, 13106881f68fSopenharmony_ci .nodeid2 = nodeid2, 13116881f68fSopenharmony_ci .name2 = name2, 13126881f68fSopenharmony_ci .path2 = path2, 13136881f68fSopenharmony_ci .wnode2 = wnode2, 13146881f68fSopenharmony_ci }; 13156881f68fSopenharmony_ci 13166881f68fSopenharmony_ci debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); 13176881f68fSopenharmony_ci debug_path(f, " PATH2", nodeid2, name2, !!wnode2); 13186881f68fSopenharmony_ci err = wait_path(f, &qe); 13196881f68fSopenharmony_ci debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); 13206881f68fSopenharmony_ci debug_path(f, " PATH2", nodeid2, name2, !!wnode2); 13216881f68fSopenharmony_ci } 13226881f68fSopenharmony_ci 13236881f68fSopenharmony_ci#if defined(CHECK_DIR_LOOP) 13246881f68fSopenharmony_ciout_unlock: 13256881f68fSopenharmony_ci#endif 13266881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 13276881f68fSopenharmony_ci 13286881f68fSopenharmony_ci return err; 13296881f68fSopenharmony_ci} 13306881f68fSopenharmony_ci 13316881f68fSopenharmony_cistatic void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid, 13326881f68fSopenharmony_ci struct node *wnode, char *path) 13336881f68fSopenharmony_ci{ 13346881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 13356881f68fSopenharmony_ci unlock_path(f, nodeid, wnode, NULL); 13366881f68fSopenharmony_ci if (f->lockq) 13376881f68fSopenharmony_ci wake_up_queued(f); 13386881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 13396881f68fSopenharmony_ci free(path); 13406881f68fSopenharmony_ci} 13416881f68fSopenharmony_ci 13426881f68fSopenharmony_cistatic void free_path(struct fuse *f, fuse_ino_t nodeid, char *path) 13436881f68fSopenharmony_ci{ 13446881f68fSopenharmony_ci if (path) 13456881f68fSopenharmony_ci free_path_wrlock(f, nodeid, NULL, path); 13466881f68fSopenharmony_ci} 13476881f68fSopenharmony_ci 13486881f68fSopenharmony_cistatic void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, 13496881f68fSopenharmony_ci struct node *wnode1, struct node *wnode2, 13506881f68fSopenharmony_ci char *path1, char *path2) 13516881f68fSopenharmony_ci{ 13526881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 13536881f68fSopenharmony_ci unlock_path(f, nodeid1, wnode1, NULL); 13546881f68fSopenharmony_ci unlock_path(f, nodeid2, wnode2, NULL); 13556881f68fSopenharmony_ci wake_up_queued(f); 13566881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 13576881f68fSopenharmony_ci free(path1); 13586881f68fSopenharmony_ci free(path2); 13596881f68fSopenharmony_ci} 13606881f68fSopenharmony_ci 13616881f68fSopenharmony_cistatic void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) 13626881f68fSopenharmony_ci{ 13636881f68fSopenharmony_ci struct node *node; 13646881f68fSopenharmony_ci if (nodeid == FUSE_ROOT_ID) 13656881f68fSopenharmony_ci return; 13666881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 13676881f68fSopenharmony_ci node = get_node(f, nodeid); 13686881f68fSopenharmony_ci 13696881f68fSopenharmony_ci /* 13706881f68fSopenharmony_ci * Node may still be locked due to interrupt idiocy in open, 13716881f68fSopenharmony_ci * create and opendir 13726881f68fSopenharmony_ci */ 13736881f68fSopenharmony_ci while (node->nlookup == nlookup && node->treelock) { 13746881f68fSopenharmony_ci struct lock_queue_element qe = { 13756881f68fSopenharmony_ci .nodeid1 = nodeid, 13766881f68fSopenharmony_ci }; 13776881f68fSopenharmony_ci 13786881f68fSopenharmony_ci debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false); 13796881f68fSopenharmony_ci queue_path(f, &qe); 13806881f68fSopenharmony_ci 13816881f68fSopenharmony_ci do { 13826881f68fSopenharmony_ci pthread_cond_wait(&qe.cond, &f->lock); 13836881f68fSopenharmony_ci } while (node->nlookup == nlookup && node->treelock); 13846881f68fSopenharmony_ci 13856881f68fSopenharmony_ci dequeue_path(f, &qe); 13866881f68fSopenharmony_ci debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false); 13876881f68fSopenharmony_ci } 13886881f68fSopenharmony_ci 13896881f68fSopenharmony_ci assert(node->nlookup >= nlookup); 13906881f68fSopenharmony_ci node->nlookup -= nlookup; 13916881f68fSopenharmony_ci if (!node->nlookup) { 13926881f68fSopenharmony_ci unref_node(f, node); 13936881f68fSopenharmony_ci } else if (lru_enabled(f) && node->nlookup == 1) { 13946881f68fSopenharmony_ci set_forget_time(f, node); 13956881f68fSopenharmony_ci } 13966881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 13976881f68fSopenharmony_ci} 13986881f68fSopenharmony_ci 13996881f68fSopenharmony_cistatic void unlink_node(struct fuse *f, struct node *node) 14006881f68fSopenharmony_ci{ 14016881f68fSopenharmony_ci if (f->conf.remember) { 14026881f68fSopenharmony_ci assert(node->nlookup > 1); 14036881f68fSopenharmony_ci node->nlookup--; 14046881f68fSopenharmony_ci } 14056881f68fSopenharmony_ci unhash_name(f, node); 14066881f68fSopenharmony_ci} 14076881f68fSopenharmony_ci 14086881f68fSopenharmony_cistatic void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) 14096881f68fSopenharmony_ci{ 14106881f68fSopenharmony_ci struct node *node; 14116881f68fSopenharmony_ci 14126881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 14136881f68fSopenharmony_ci node = lookup_node(f, dir, name); 14146881f68fSopenharmony_ci if (node != NULL) 14156881f68fSopenharmony_ci unlink_node(f, node); 14166881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 14176881f68fSopenharmony_ci} 14186881f68fSopenharmony_ci 14196881f68fSopenharmony_cistatic int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, 14206881f68fSopenharmony_ci fuse_ino_t newdir, const char *newname, int hide) 14216881f68fSopenharmony_ci{ 14226881f68fSopenharmony_ci struct node *node; 14236881f68fSopenharmony_ci struct node *newnode; 14246881f68fSopenharmony_ci int err = 0; 14256881f68fSopenharmony_ci 14266881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 14276881f68fSopenharmony_ci node = lookup_node(f, olddir, oldname); 14286881f68fSopenharmony_ci newnode = lookup_node(f, newdir, newname); 14296881f68fSopenharmony_ci if (node == NULL) 14306881f68fSopenharmony_ci goto out; 14316881f68fSopenharmony_ci 14326881f68fSopenharmony_ci if (newnode != NULL) { 14336881f68fSopenharmony_ci if (hide) { 14346881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: hidden file got created during hiding\n"); 14356881f68fSopenharmony_ci err = -EBUSY; 14366881f68fSopenharmony_ci goto out; 14376881f68fSopenharmony_ci } 14386881f68fSopenharmony_ci unlink_node(f, newnode); 14396881f68fSopenharmony_ci } 14406881f68fSopenharmony_ci 14416881f68fSopenharmony_ci unhash_name(f, node); 14426881f68fSopenharmony_ci if (hash_name(f, node, newdir, newname) == -1) { 14436881f68fSopenharmony_ci err = -ENOMEM; 14446881f68fSopenharmony_ci goto out; 14456881f68fSopenharmony_ci } 14466881f68fSopenharmony_ci 14476881f68fSopenharmony_ci if (hide) 14486881f68fSopenharmony_ci node->is_hidden = 1; 14496881f68fSopenharmony_ci 14506881f68fSopenharmony_ciout: 14516881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 14526881f68fSopenharmony_ci return err; 14536881f68fSopenharmony_ci} 14546881f68fSopenharmony_ci 14556881f68fSopenharmony_cistatic int exchange_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, 14566881f68fSopenharmony_ci fuse_ino_t newdir, const char *newname) 14576881f68fSopenharmony_ci{ 14586881f68fSopenharmony_ci struct node *oldnode; 14596881f68fSopenharmony_ci struct node *newnode; 14606881f68fSopenharmony_ci int err; 14616881f68fSopenharmony_ci 14626881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 14636881f68fSopenharmony_ci oldnode = lookup_node(f, olddir, oldname); 14646881f68fSopenharmony_ci newnode = lookup_node(f, newdir, newname); 14656881f68fSopenharmony_ci 14666881f68fSopenharmony_ci if (oldnode) 14676881f68fSopenharmony_ci unhash_name(f, oldnode); 14686881f68fSopenharmony_ci if (newnode) 14696881f68fSopenharmony_ci unhash_name(f, newnode); 14706881f68fSopenharmony_ci 14716881f68fSopenharmony_ci err = -ENOMEM; 14726881f68fSopenharmony_ci if (oldnode) { 14736881f68fSopenharmony_ci if (hash_name(f, oldnode, newdir, newname) == -1) 14746881f68fSopenharmony_ci goto out; 14756881f68fSopenharmony_ci } 14766881f68fSopenharmony_ci if (newnode) { 14776881f68fSopenharmony_ci if (hash_name(f, newnode, olddir, oldname) == -1) 14786881f68fSopenharmony_ci goto out; 14796881f68fSopenharmony_ci } 14806881f68fSopenharmony_ci err = 0; 14816881f68fSopenharmony_ciout: 14826881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 14836881f68fSopenharmony_ci return err; 14846881f68fSopenharmony_ci} 14856881f68fSopenharmony_ci 14866881f68fSopenharmony_cistatic void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) 14876881f68fSopenharmony_ci{ 14886881f68fSopenharmony_ci if (!f->conf.use_ino) 14896881f68fSopenharmony_ci stbuf->st_ino = nodeid; 14906881f68fSopenharmony_ci if (f->conf.set_mode) 14916881f68fSopenharmony_ci stbuf->st_mode = (stbuf->st_mode & S_IFMT) | 14926881f68fSopenharmony_ci (0777 & ~f->conf.umask); 14936881f68fSopenharmony_ci if (f->conf.set_uid) 14946881f68fSopenharmony_ci stbuf->st_uid = f->conf.uid; 14956881f68fSopenharmony_ci if (f->conf.set_gid) 14966881f68fSopenharmony_ci stbuf->st_gid = f->conf.gid; 14976881f68fSopenharmony_ci} 14986881f68fSopenharmony_ci 14996881f68fSopenharmony_cistatic struct fuse *req_fuse(fuse_req_t req) 15006881f68fSopenharmony_ci{ 15016881f68fSopenharmony_ci return (struct fuse *) fuse_req_userdata(req); 15026881f68fSopenharmony_ci} 15036881f68fSopenharmony_ci 15046881f68fSopenharmony_cistatic void fuse_intr_sighandler(int sig) 15056881f68fSopenharmony_ci{ 15066881f68fSopenharmony_ci (void) sig; 15076881f68fSopenharmony_ci /* Nothing to do */ 15086881f68fSopenharmony_ci} 15096881f68fSopenharmony_ci 15106881f68fSopenharmony_cistruct fuse_intr_data { 15116881f68fSopenharmony_ci pthread_t id; 15126881f68fSopenharmony_ci pthread_cond_t cond; 15136881f68fSopenharmony_ci int finished; 15146881f68fSopenharmony_ci}; 15156881f68fSopenharmony_ci 15166881f68fSopenharmony_cistatic void fuse_interrupt(fuse_req_t req, void *d_) 15176881f68fSopenharmony_ci{ 15186881f68fSopenharmony_ci struct fuse_intr_data *d = d_; 15196881f68fSopenharmony_ci struct fuse *f = req_fuse(req); 15206881f68fSopenharmony_ci 15216881f68fSopenharmony_ci if (d->id == pthread_self()) 15226881f68fSopenharmony_ci return; 15236881f68fSopenharmony_ci 15246881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 15256881f68fSopenharmony_ci while (!d->finished) { 15266881f68fSopenharmony_ci struct timeval now; 15276881f68fSopenharmony_ci struct timespec timeout; 15286881f68fSopenharmony_ci 15296881f68fSopenharmony_ci pthread_kill(d->id, f->conf.intr_signal); 15306881f68fSopenharmony_ci gettimeofday(&now, NULL); 15316881f68fSopenharmony_ci timeout.tv_sec = now.tv_sec + 1; 15326881f68fSopenharmony_ci timeout.tv_nsec = now.tv_usec * 1000; 15336881f68fSopenharmony_ci pthread_cond_timedwait(&d->cond, &f->lock, &timeout); 15346881f68fSopenharmony_ci } 15356881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 15366881f68fSopenharmony_ci} 15376881f68fSopenharmony_ci 15386881f68fSopenharmony_cistatic void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, 15396881f68fSopenharmony_ci struct fuse_intr_data *d) 15406881f68fSopenharmony_ci{ 15416881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 15426881f68fSopenharmony_ci d->finished = 1; 15436881f68fSopenharmony_ci pthread_cond_broadcast(&d->cond); 15446881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 15456881f68fSopenharmony_ci fuse_req_interrupt_func(req, NULL, NULL); 15466881f68fSopenharmony_ci pthread_cond_destroy(&d->cond); 15476881f68fSopenharmony_ci} 15486881f68fSopenharmony_ci 15496881f68fSopenharmony_cistatic void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) 15506881f68fSopenharmony_ci{ 15516881f68fSopenharmony_ci d->id = pthread_self(); 15526881f68fSopenharmony_ci pthread_cond_init(&d->cond, NULL); 15536881f68fSopenharmony_ci d->finished = 0; 15546881f68fSopenharmony_ci fuse_req_interrupt_func(req, fuse_interrupt, d); 15556881f68fSopenharmony_ci} 15566881f68fSopenharmony_ci 15576881f68fSopenharmony_cistatic inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, 15586881f68fSopenharmony_ci struct fuse_intr_data *d) 15596881f68fSopenharmony_ci{ 15606881f68fSopenharmony_ci if (f->conf.intr) 15616881f68fSopenharmony_ci fuse_do_finish_interrupt(f, req, d); 15626881f68fSopenharmony_ci} 15636881f68fSopenharmony_ci 15646881f68fSopenharmony_cistatic inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, 15656881f68fSopenharmony_ci struct fuse_intr_data *d) 15666881f68fSopenharmony_ci{ 15676881f68fSopenharmony_ci if (f->conf.intr) 15686881f68fSopenharmony_ci fuse_do_prepare_interrupt(req, d); 15696881f68fSopenharmony_ci} 15706881f68fSopenharmony_ci 15716881f68fSopenharmony_cistatic const char* file_info_string(struct fuse_file_info *fi, 15726881f68fSopenharmony_ci char* buf, size_t len) 15736881f68fSopenharmony_ci{ 15746881f68fSopenharmony_ci if(fi == NULL) 15756881f68fSopenharmony_ci return "NULL"; 15766881f68fSopenharmony_ci snprintf(buf, len, "%llu", (unsigned long long) fi->fh); 15776881f68fSopenharmony_ci return buf; 15786881f68fSopenharmony_ci} 15796881f68fSopenharmony_ci 15806881f68fSopenharmony_ciint fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf, 15816881f68fSopenharmony_ci struct fuse_file_info *fi) 15826881f68fSopenharmony_ci{ 15836881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 15846881f68fSopenharmony_ci if (fs->op.getattr) { 15856881f68fSopenharmony_ci if (fs->debug) { 15866881f68fSopenharmony_ci char buf[10]; 15876881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "getattr[%s] %s\n", 15886881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 15896881f68fSopenharmony_ci path); 15906881f68fSopenharmony_ci } 15916881f68fSopenharmony_ci return fs->op.getattr(path, buf, fi); 15926881f68fSopenharmony_ci } else { 15936881f68fSopenharmony_ci return -ENOSYS; 15946881f68fSopenharmony_ci } 15956881f68fSopenharmony_ci} 15966881f68fSopenharmony_ci 15976881f68fSopenharmony_ciint fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, 15986881f68fSopenharmony_ci const char *newpath, unsigned int flags) 15996881f68fSopenharmony_ci{ 16006881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16016881f68fSopenharmony_ci if (fs->op.rename) { 16026881f68fSopenharmony_ci if (fs->debug) 16036881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "rename %s %s 0x%x\n", oldpath, newpath, 16046881f68fSopenharmony_ci flags); 16056881f68fSopenharmony_ci 16066881f68fSopenharmony_ci return fs->op.rename(oldpath, newpath, flags); 16076881f68fSopenharmony_ci } else { 16086881f68fSopenharmony_ci return -ENOSYS; 16096881f68fSopenharmony_ci } 16106881f68fSopenharmony_ci} 16116881f68fSopenharmony_ci 16126881f68fSopenharmony_ciint fuse_fs_unlink(struct fuse_fs *fs, const char *path) 16136881f68fSopenharmony_ci{ 16146881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16156881f68fSopenharmony_ci if (fs->op.unlink) { 16166881f68fSopenharmony_ci if (fs->debug) 16176881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "unlink %s\n", path); 16186881f68fSopenharmony_ci 16196881f68fSopenharmony_ci return fs->op.unlink(path); 16206881f68fSopenharmony_ci } else { 16216881f68fSopenharmony_ci return -ENOSYS; 16226881f68fSopenharmony_ci } 16236881f68fSopenharmony_ci} 16246881f68fSopenharmony_ci 16256881f68fSopenharmony_ciint fuse_fs_rmdir(struct fuse_fs *fs, const char *path) 16266881f68fSopenharmony_ci{ 16276881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16286881f68fSopenharmony_ci if (fs->op.rmdir) { 16296881f68fSopenharmony_ci if (fs->debug) 16306881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "rmdir %s\n", path); 16316881f68fSopenharmony_ci 16326881f68fSopenharmony_ci return fs->op.rmdir(path); 16336881f68fSopenharmony_ci } else { 16346881f68fSopenharmony_ci return -ENOSYS; 16356881f68fSopenharmony_ci } 16366881f68fSopenharmony_ci} 16376881f68fSopenharmony_ci 16386881f68fSopenharmony_ciint fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) 16396881f68fSopenharmony_ci{ 16406881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16416881f68fSopenharmony_ci if (fs->op.symlink) { 16426881f68fSopenharmony_ci if (fs->debug) 16436881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "symlink %s %s\n", linkname, path); 16446881f68fSopenharmony_ci 16456881f68fSopenharmony_ci return fs->op.symlink(linkname, path); 16466881f68fSopenharmony_ci } else { 16476881f68fSopenharmony_ci return -ENOSYS; 16486881f68fSopenharmony_ci } 16496881f68fSopenharmony_ci} 16506881f68fSopenharmony_ci 16516881f68fSopenharmony_ciint fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) 16526881f68fSopenharmony_ci{ 16536881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16546881f68fSopenharmony_ci if (fs->op.link) { 16556881f68fSopenharmony_ci if (fs->debug) 16566881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "link %s %s\n", oldpath, newpath); 16576881f68fSopenharmony_ci 16586881f68fSopenharmony_ci return fs->op.link(oldpath, newpath); 16596881f68fSopenharmony_ci } else { 16606881f68fSopenharmony_ci return -ENOSYS; 16616881f68fSopenharmony_ci } 16626881f68fSopenharmony_ci} 16636881f68fSopenharmony_ci 16646881f68fSopenharmony_ciint fuse_fs_release(struct fuse_fs *fs, const char *path, 16656881f68fSopenharmony_ci struct fuse_file_info *fi) 16666881f68fSopenharmony_ci{ 16676881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16686881f68fSopenharmony_ci if (fs->op.release) { 16696881f68fSopenharmony_ci if (fs->debug) 16706881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "release%s[%llu] flags: 0x%x\n", 16716881f68fSopenharmony_ci fi->flush ? "+flush" : "", 16726881f68fSopenharmony_ci (unsigned long long) fi->fh, fi->flags); 16736881f68fSopenharmony_ci 16746881f68fSopenharmony_ci return fs->op.release(path, fi); 16756881f68fSopenharmony_ci } else { 16766881f68fSopenharmony_ci return 0; 16776881f68fSopenharmony_ci } 16786881f68fSopenharmony_ci} 16796881f68fSopenharmony_ci 16806881f68fSopenharmony_ciint fuse_fs_opendir(struct fuse_fs *fs, const char *path, 16816881f68fSopenharmony_ci struct fuse_file_info *fi) 16826881f68fSopenharmony_ci{ 16836881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 16846881f68fSopenharmony_ci if (fs->op.opendir) { 16856881f68fSopenharmony_ci int err; 16866881f68fSopenharmony_ci 16876881f68fSopenharmony_ci if (fs->debug) 16886881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "opendir flags: 0x%x %s\n", fi->flags, 16896881f68fSopenharmony_ci path); 16906881f68fSopenharmony_ci 16916881f68fSopenharmony_ci err = fs->op.opendir(path, fi); 16926881f68fSopenharmony_ci 16936881f68fSopenharmony_ci if (fs->debug && !err) 16946881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " opendir[%llu] flags: 0x%x %s\n", 16956881f68fSopenharmony_ci (unsigned long long) fi->fh, fi->flags, path); 16966881f68fSopenharmony_ci 16976881f68fSopenharmony_ci return err; 16986881f68fSopenharmony_ci } else { 16996881f68fSopenharmony_ci return 0; 17006881f68fSopenharmony_ci } 17016881f68fSopenharmony_ci} 17026881f68fSopenharmony_ci 17036881f68fSopenharmony_ciint fuse_fs_open(struct fuse_fs *fs, const char *path, 17046881f68fSopenharmony_ci struct fuse_file_info *fi) 17056881f68fSopenharmony_ci{ 17066881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 17076881f68fSopenharmony_ci if (fs->op.open) { 17086881f68fSopenharmony_ci int err; 17096881f68fSopenharmony_ci 17106881f68fSopenharmony_ci if (fs->debug) 17116881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "open flags: 0x%x %s\n", fi->flags, 17126881f68fSopenharmony_ci path); 17136881f68fSopenharmony_ci 17146881f68fSopenharmony_ci err = fs->op.open(path, fi); 17156881f68fSopenharmony_ci 17166881f68fSopenharmony_ci if (fs->debug && !err) 17176881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " open[%llu] flags: 0x%x %s\n", 17186881f68fSopenharmony_ci (unsigned long long) fi->fh, fi->flags, path); 17196881f68fSopenharmony_ci 17206881f68fSopenharmony_ci return err; 17216881f68fSopenharmony_ci } else { 17226881f68fSopenharmony_ci return 0; 17236881f68fSopenharmony_ci } 17246881f68fSopenharmony_ci} 17256881f68fSopenharmony_ci 17266881f68fSopenharmony_cistatic void fuse_free_buf(struct fuse_bufvec *buf) 17276881f68fSopenharmony_ci{ 17286881f68fSopenharmony_ci if (buf != NULL) { 17296881f68fSopenharmony_ci size_t i; 17306881f68fSopenharmony_ci 17316881f68fSopenharmony_ci for (i = 0; i < buf->count; i++) 17326881f68fSopenharmony_ci if (!(buf->buf[i].flags & FUSE_BUF_IS_FD)) 17336881f68fSopenharmony_ci free(buf->buf[i].mem); 17346881f68fSopenharmony_ci free(buf); 17356881f68fSopenharmony_ci } 17366881f68fSopenharmony_ci} 17376881f68fSopenharmony_ci 17386881f68fSopenharmony_ciint fuse_fs_read_buf(struct fuse_fs *fs, const char *path, 17396881f68fSopenharmony_ci struct fuse_bufvec **bufp, size_t size, off_t off, 17406881f68fSopenharmony_ci struct fuse_file_info *fi) 17416881f68fSopenharmony_ci{ 17426881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 17436881f68fSopenharmony_ci if (fs->op.read || fs->op.read_buf) { 17446881f68fSopenharmony_ci int res; 17456881f68fSopenharmony_ci 17466881f68fSopenharmony_ci if (fs->debug) 17476881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, 17486881f68fSopenharmony_ci "read[%llu] %zu bytes from %llu flags: 0x%x\n", 17496881f68fSopenharmony_ci (unsigned long long) fi->fh, 17506881f68fSopenharmony_ci size, (unsigned long long) off, fi->flags); 17516881f68fSopenharmony_ci 17526881f68fSopenharmony_ci if (fs->op.read_buf) { 17536881f68fSopenharmony_ci res = fs->op.read_buf(path, bufp, size, off, fi); 17546881f68fSopenharmony_ci } else { 17556881f68fSopenharmony_ci struct fuse_bufvec *buf; 17566881f68fSopenharmony_ci void *mem; 17576881f68fSopenharmony_ci 17586881f68fSopenharmony_ci buf = malloc(sizeof(struct fuse_bufvec)); 17596881f68fSopenharmony_ci if (buf == NULL) 17606881f68fSopenharmony_ci return -ENOMEM; 17616881f68fSopenharmony_ci 17626881f68fSopenharmony_ci mem = malloc(size); 17636881f68fSopenharmony_ci if (mem == NULL) { 17646881f68fSopenharmony_ci free(buf); 17656881f68fSopenharmony_ci return -ENOMEM; 17666881f68fSopenharmony_ci } 17676881f68fSopenharmony_ci *buf = FUSE_BUFVEC_INIT(size); 17686881f68fSopenharmony_ci buf->buf[0].mem = mem; 17696881f68fSopenharmony_ci *bufp = buf; 17706881f68fSopenharmony_ci 17716881f68fSopenharmony_ci res = fs->op.read(path, mem, size, off, fi); 17726881f68fSopenharmony_ci if (res >= 0) 17736881f68fSopenharmony_ci buf->buf[0].size = res; 17746881f68fSopenharmony_ci } 17756881f68fSopenharmony_ci 17766881f68fSopenharmony_ci if (fs->debug && res >= 0) 17776881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " read[%llu] %zu bytes from %llu\n", 17786881f68fSopenharmony_ci (unsigned long long) fi->fh, 17796881f68fSopenharmony_ci fuse_buf_size(*bufp), 17806881f68fSopenharmony_ci (unsigned long long) off); 17816881f68fSopenharmony_ci if (res >= 0 && fuse_buf_size(*bufp) > size) 17826881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n"); 17836881f68fSopenharmony_ci 17846881f68fSopenharmony_ci if (res < 0) 17856881f68fSopenharmony_ci return res; 17866881f68fSopenharmony_ci 17876881f68fSopenharmony_ci return 0; 17886881f68fSopenharmony_ci } else { 17896881f68fSopenharmony_ci return -ENOSYS; 17906881f68fSopenharmony_ci } 17916881f68fSopenharmony_ci} 17926881f68fSopenharmony_ci 17936881f68fSopenharmony_ciint fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size, 17946881f68fSopenharmony_ci off_t off, struct fuse_file_info *fi) 17956881f68fSopenharmony_ci{ 17966881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 17976881f68fSopenharmony_ci if (fs->op.read || fs->op.read_buf) { 17986881f68fSopenharmony_ci int res; 17996881f68fSopenharmony_ci 18006881f68fSopenharmony_ci if (fs->debug) 18016881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, 18026881f68fSopenharmony_ci "read[%llu] %zu bytes from %llu flags: 0x%x\n", 18036881f68fSopenharmony_ci (unsigned long long) fi->fh, 18046881f68fSopenharmony_ci size, (unsigned long long) off, fi->flags); 18056881f68fSopenharmony_ci 18066881f68fSopenharmony_ci if (fs->op.read_buf) { 18076881f68fSopenharmony_ci struct fuse_bufvec *buf = NULL; 18086881f68fSopenharmony_ci 18096881f68fSopenharmony_ci res = fs->op.read_buf(path, &buf, size, off, fi); 18106881f68fSopenharmony_ci if (res == 0) { 18116881f68fSopenharmony_ci struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); 18126881f68fSopenharmony_ci 18136881f68fSopenharmony_ci dst.buf[0].mem = mem; 18146881f68fSopenharmony_ci res = fuse_buf_copy(&dst, buf, 0); 18156881f68fSopenharmony_ci } 18166881f68fSopenharmony_ci fuse_free_buf(buf); 18176881f68fSopenharmony_ci } else { 18186881f68fSopenharmony_ci res = fs->op.read(path, mem, size, off, fi); 18196881f68fSopenharmony_ci } 18206881f68fSopenharmony_ci 18216881f68fSopenharmony_ci if (fs->debug && res >= 0) 18226881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " read[%llu] %u bytes from %llu\n", 18236881f68fSopenharmony_ci (unsigned long long) fi->fh, 18246881f68fSopenharmony_ci res, 18256881f68fSopenharmony_ci (unsigned long long) off); 18266881f68fSopenharmony_ci if (res >= 0 && res > (int) size) 18276881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n"); 18286881f68fSopenharmony_ci 18296881f68fSopenharmony_ci return res; 18306881f68fSopenharmony_ci } else { 18316881f68fSopenharmony_ci return -ENOSYS; 18326881f68fSopenharmony_ci } 18336881f68fSopenharmony_ci} 18346881f68fSopenharmony_ci 18356881f68fSopenharmony_ciint fuse_fs_write_buf(struct fuse_fs *fs, const char *path, 18366881f68fSopenharmony_ci struct fuse_bufvec *buf, off_t off, 18376881f68fSopenharmony_ci struct fuse_file_info *fi) 18386881f68fSopenharmony_ci{ 18396881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 18406881f68fSopenharmony_ci if (fs->op.write_buf || fs->op.write) { 18416881f68fSopenharmony_ci int res; 18426881f68fSopenharmony_ci size_t size = fuse_buf_size(buf); 18436881f68fSopenharmony_ci 18446881f68fSopenharmony_ci assert(buf->idx == 0 && buf->off == 0); 18456881f68fSopenharmony_ci if (fs->debug) 18466881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, 18476881f68fSopenharmony_ci "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", 18486881f68fSopenharmony_ci fi->writepage ? "page" : "", 18496881f68fSopenharmony_ci (unsigned long long) fi->fh, 18506881f68fSopenharmony_ci size, 18516881f68fSopenharmony_ci (unsigned long long) off, 18526881f68fSopenharmony_ci fi->flags); 18536881f68fSopenharmony_ci 18546881f68fSopenharmony_ci if (fs->op.write_buf) { 18556881f68fSopenharmony_ci res = fs->op.write_buf(path, buf, off, fi); 18566881f68fSopenharmony_ci } else { 18576881f68fSopenharmony_ci void *mem = NULL; 18586881f68fSopenharmony_ci struct fuse_buf *flatbuf; 18596881f68fSopenharmony_ci struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); 18606881f68fSopenharmony_ci 18616881f68fSopenharmony_ci if (buf->count == 1 && 18626881f68fSopenharmony_ci !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { 18636881f68fSopenharmony_ci flatbuf = &buf->buf[0]; 18646881f68fSopenharmony_ci } else { 18656881f68fSopenharmony_ci res = -ENOMEM; 18666881f68fSopenharmony_ci mem = malloc(size); 18676881f68fSopenharmony_ci if (mem == NULL) 18686881f68fSopenharmony_ci goto out; 18696881f68fSopenharmony_ci 18706881f68fSopenharmony_ci tmp.buf[0].mem = mem; 18716881f68fSopenharmony_ci res = fuse_buf_copy(&tmp, buf, 0); 18726881f68fSopenharmony_ci if (res <= 0) 18736881f68fSopenharmony_ci goto out_free; 18746881f68fSopenharmony_ci 18756881f68fSopenharmony_ci tmp.buf[0].size = res; 18766881f68fSopenharmony_ci flatbuf = &tmp.buf[0]; 18776881f68fSopenharmony_ci } 18786881f68fSopenharmony_ci 18796881f68fSopenharmony_ci res = fs->op.write(path, flatbuf->mem, flatbuf->size, 18806881f68fSopenharmony_ci off, fi); 18816881f68fSopenharmony_ciout_free: 18826881f68fSopenharmony_ci free(mem); 18836881f68fSopenharmony_ci } 18846881f68fSopenharmony_ciout: 18856881f68fSopenharmony_ci if (fs->debug && res >= 0) 18866881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " write%s[%llu] %u bytes to %llu\n", 18876881f68fSopenharmony_ci fi->writepage ? "page" : "", 18886881f68fSopenharmony_ci (unsigned long long) fi->fh, res, 18896881f68fSopenharmony_ci (unsigned long long) off); 18906881f68fSopenharmony_ci if (res > (int) size) 18916881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: wrote too many bytes\n"); 18926881f68fSopenharmony_ci 18936881f68fSopenharmony_ci return res; 18946881f68fSopenharmony_ci } else { 18956881f68fSopenharmony_ci return -ENOSYS; 18966881f68fSopenharmony_ci } 18976881f68fSopenharmony_ci} 18986881f68fSopenharmony_ci 18996881f68fSopenharmony_ciint fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem, 19006881f68fSopenharmony_ci size_t size, off_t off, struct fuse_file_info *fi) 19016881f68fSopenharmony_ci{ 19026881f68fSopenharmony_ci struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); 19036881f68fSopenharmony_ci 19046881f68fSopenharmony_ci bufv.buf[0].mem = (void *) mem; 19056881f68fSopenharmony_ci 19066881f68fSopenharmony_ci return fuse_fs_write_buf(fs, path, &bufv, off, fi); 19076881f68fSopenharmony_ci} 19086881f68fSopenharmony_ci 19096881f68fSopenharmony_ciint fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, 19106881f68fSopenharmony_ci struct fuse_file_info *fi) 19116881f68fSopenharmony_ci{ 19126881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19136881f68fSopenharmony_ci if (fs->op.fsync) { 19146881f68fSopenharmony_ci if (fs->debug) 19156881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "fsync[%llu] datasync: %i\n", 19166881f68fSopenharmony_ci (unsigned long long) fi->fh, datasync); 19176881f68fSopenharmony_ci 19186881f68fSopenharmony_ci return fs->op.fsync(path, datasync, fi); 19196881f68fSopenharmony_ci } else { 19206881f68fSopenharmony_ci return -ENOSYS; 19216881f68fSopenharmony_ci } 19226881f68fSopenharmony_ci} 19236881f68fSopenharmony_ci 19246881f68fSopenharmony_ciint fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, 19256881f68fSopenharmony_ci struct fuse_file_info *fi) 19266881f68fSopenharmony_ci{ 19276881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19286881f68fSopenharmony_ci if (fs->op.fsyncdir) { 19296881f68fSopenharmony_ci if (fs->debug) 19306881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "fsyncdir[%llu] datasync: %i\n", 19316881f68fSopenharmony_ci (unsigned long long) fi->fh, datasync); 19326881f68fSopenharmony_ci 19336881f68fSopenharmony_ci return fs->op.fsyncdir(path, datasync, fi); 19346881f68fSopenharmony_ci } else { 19356881f68fSopenharmony_ci return -ENOSYS; 19366881f68fSopenharmony_ci } 19376881f68fSopenharmony_ci} 19386881f68fSopenharmony_ci 19396881f68fSopenharmony_ciint fuse_fs_flush(struct fuse_fs *fs, const char *path, 19406881f68fSopenharmony_ci struct fuse_file_info *fi) 19416881f68fSopenharmony_ci{ 19426881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19436881f68fSopenharmony_ci if (fs->op.flush) { 19446881f68fSopenharmony_ci if (fs->debug) 19456881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "flush[%llu]\n", 19466881f68fSopenharmony_ci (unsigned long long) fi->fh); 19476881f68fSopenharmony_ci 19486881f68fSopenharmony_ci return fs->op.flush(path, fi); 19496881f68fSopenharmony_ci } else { 19506881f68fSopenharmony_ci return -ENOSYS; 19516881f68fSopenharmony_ci } 19526881f68fSopenharmony_ci} 19536881f68fSopenharmony_ci 19546881f68fSopenharmony_ciint fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) 19556881f68fSopenharmony_ci{ 19566881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19576881f68fSopenharmony_ci if (fs->op.statfs) { 19586881f68fSopenharmony_ci if (fs->debug) 19596881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "statfs %s\n", path); 19606881f68fSopenharmony_ci 19616881f68fSopenharmony_ci return fs->op.statfs(path, buf); 19626881f68fSopenharmony_ci } else { 19636881f68fSopenharmony_ci buf->f_namemax = 255; 19646881f68fSopenharmony_ci buf->f_bsize = 512; 19656881f68fSopenharmony_ci return 0; 19666881f68fSopenharmony_ci } 19676881f68fSopenharmony_ci} 19686881f68fSopenharmony_ci 19696881f68fSopenharmony_ciint fuse_fs_releasedir(struct fuse_fs *fs, const char *path, 19706881f68fSopenharmony_ci struct fuse_file_info *fi) 19716881f68fSopenharmony_ci{ 19726881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19736881f68fSopenharmony_ci if (fs->op.releasedir) { 19746881f68fSopenharmony_ci if (fs->debug) 19756881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "releasedir[%llu] flags: 0x%x\n", 19766881f68fSopenharmony_ci (unsigned long long) fi->fh, fi->flags); 19776881f68fSopenharmony_ci 19786881f68fSopenharmony_ci return fs->op.releasedir(path, fi); 19796881f68fSopenharmony_ci } else { 19806881f68fSopenharmony_ci return 0; 19816881f68fSopenharmony_ci } 19826881f68fSopenharmony_ci} 19836881f68fSopenharmony_ci 19846881f68fSopenharmony_ciint fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf, 19856881f68fSopenharmony_ci fuse_fill_dir_t filler, off_t off, 19866881f68fSopenharmony_ci struct fuse_file_info *fi, 19876881f68fSopenharmony_ci enum fuse_readdir_flags flags) 19886881f68fSopenharmony_ci{ 19896881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 19906881f68fSopenharmony_ci if (fs->op.readdir) { 19916881f68fSopenharmony_ci if (fs->debug) { 19926881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "readdir%s[%llu] from %llu\n", 19936881f68fSopenharmony_ci (flags & FUSE_READDIR_PLUS) ? "plus" : "", 19946881f68fSopenharmony_ci (unsigned long long) fi->fh, 19956881f68fSopenharmony_ci (unsigned long long) off); 19966881f68fSopenharmony_ci } 19976881f68fSopenharmony_ci 19986881f68fSopenharmony_ci return fs->op.readdir(path, buf, filler, off, fi, flags); 19996881f68fSopenharmony_ci } else { 20006881f68fSopenharmony_ci return -ENOSYS; 20016881f68fSopenharmony_ci } 20026881f68fSopenharmony_ci} 20036881f68fSopenharmony_ci 20046881f68fSopenharmony_ciint fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, 20056881f68fSopenharmony_ci struct fuse_file_info *fi) 20066881f68fSopenharmony_ci{ 20076881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 20086881f68fSopenharmony_ci if (fs->op.create) { 20096881f68fSopenharmony_ci int err; 20106881f68fSopenharmony_ci 20116881f68fSopenharmony_ci if (fs->debug) 20126881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, 20136881f68fSopenharmony_ci "create flags: 0x%x %s 0%o umask=0%03o\n", 20146881f68fSopenharmony_ci fi->flags, path, mode, 20156881f68fSopenharmony_ci fuse_get_context()->umask); 20166881f68fSopenharmony_ci 20176881f68fSopenharmony_ci err = fs->op.create(path, mode, fi); 20186881f68fSopenharmony_ci 20196881f68fSopenharmony_ci if (fs->debug && !err) 20206881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " create[%llu] flags: 0x%x %s\n", 20216881f68fSopenharmony_ci (unsigned long long) fi->fh, fi->flags, path); 20226881f68fSopenharmony_ci 20236881f68fSopenharmony_ci return err; 20246881f68fSopenharmony_ci } else { 20256881f68fSopenharmony_ci return -ENOSYS; 20266881f68fSopenharmony_ci } 20276881f68fSopenharmony_ci} 20286881f68fSopenharmony_ci 20296881f68fSopenharmony_ciint fuse_fs_lock(struct fuse_fs *fs, const char *path, 20306881f68fSopenharmony_ci struct fuse_file_info *fi, int cmd, struct flock *lock) 20316881f68fSopenharmony_ci{ 20326881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 20336881f68fSopenharmony_ci if (fs->op.lock) { 20346881f68fSopenharmony_ci if (fs->debug) 20356881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", 20366881f68fSopenharmony_ci (unsigned long long) fi->fh, 20376881f68fSopenharmony_ci (cmd == F_GETLK ? "F_GETLK" : 20386881f68fSopenharmony_ci (cmd == F_SETLK ? "F_SETLK" : 20396881f68fSopenharmony_ci (cmd == F_SETLKW ? "F_SETLKW" : "???"))), 20406881f68fSopenharmony_ci (lock->l_type == F_RDLCK ? "F_RDLCK" : 20416881f68fSopenharmony_ci (lock->l_type == F_WRLCK ? "F_WRLCK" : 20426881f68fSopenharmony_ci (lock->l_type == F_UNLCK ? "F_UNLCK" : 20436881f68fSopenharmony_ci "???"))), 20446881f68fSopenharmony_ci (unsigned long long) lock->l_start, 20456881f68fSopenharmony_ci (unsigned long long) lock->l_len, 20466881f68fSopenharmony_ci (unsigned long long) lock->l_pid); 20476881f68fSopenharmony_ci 20486881f68fSopenharmony_ci return fs->op.lock(path, fi, cmd, lock); 20496881f68fSopenharmony_ci } else { 20506881f68fSopenharmony_ci return -ENOSYS; 20516881f68fSopenharmony_ci } 20526881f68fSopenharmony_ci} 20536881f68fSopenharmony_ci 20546881f68fSopenharmony_ciint fuse_fs_flock(struct fuse_fs *fs, const char *path, 20556881f68fSopenharmony_ci struct fuse_file_info *fi, int op) 20566881f68fSopenharmony_ci{ 20576881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 20586881f68fSopenharmony_ci if (fs->op.flock) { 20596881f68fSopenharmony_ci if (fs->debug) { 20606881f68fSopenharmony_ci int xop = op & ~LOCK_NB; 20616881f68fSopenharmony_ci 20626881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s%s\n", 20636881f68fSopenharmony_ci (unsigned long long) fi->fh, 20646881f68fSopenharmony_ci xop == LOCK_SH ? "LOCK_SH" : 20656881f68fSopenharmony_ci (xop == LOCK_EX ? "LOCK_EX" : 20666881f68fSopenharmony_ci (xop == LOCK_UN ? "LOCK_UN" : "???")), 20676881f68fSopenharmony_ci (op & LOCK_NB) ? "|LOCK_NB" : ""); 20686881f68fSopenharmony_ci } 20696881f68fSopenharmony_ci return fs->op.flock(path, fi, op); 20706881f68fSopenharmony_ci } else { 20716881f68fSopenharmony_ci return -ENOSYS; 20726881f68fSopenharmony_ci } 20736881f68fSopenharmony_ci} 20746881f68fSopenharmony_ci 20756881f68fSopenharmony_ciint fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, 20766881f68fSopenharmony_ci gid_t gid, struct fuse_file_info *fi) 20776881f68fSopenharmony_ci{ 20786881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 20796881f68fSopenharmony_ci if (fs->op.chown) { 20806881f68fSopenharmony_ci if (fs->debug) { 20816881f68fSopenharmony_ci char buf[10]; 20826881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "chown[%s] %s %lu %lu\n", 20836881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 20846881f68fSopenharmony_ci path, (unsigned long) uid, (unsigned long) gid); 20856881f68fSopenharmony_ci } 20866881f68fSopenharmony_ci return fs->op.chown(path, uid, gid, fi); 20876881f68fSopenharmony_ci } else { 20886881f68fSopenharmony_ci return -ENOSYS; 20896881f68fSopenharmony_ci } 20906881f68fSopenharmony_ci} 20916881f68fSopenharmony_ci 20926881f68fSopenharmony_ciint fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size, 20936881f68fSopenharmony_ci struct fuse_file_info *fi) 20946881f68fSopenharmony_ci{ 20956881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 20966881f68fSopenharmony_ci if (fs->op.truncate) { 20976881f68fSopenharmony_ci if (fs->debug) { 20986881f68fSopenharmony_ci char buf[10]; 20996881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "truncate[%s] %llu\n", 21006881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 21016881f68fSopenharmony_ci (unsigned long long) size); 21026881f68fSopenharmony_ci } 21036881f68fSopenharmony_ci return fs->op.truncate(path, size, fi); 21046881f68fSopenharmony_ci } else { 21056881f68fSopenharmony_ci return -ENOSYS; 21066881f68fSopenharmony_ci } 21076881f68fSopenharmony_ci} 21086881f68fSopenharmony_ci 21096881f68fSopenharmony_ciint fuse_fs_utimens(struct fuse_fs *fs, const char *path, 21106881f68fSopenharmony_ci const struct timespec tv[2], struct fuse_file_info *fi) 21116881f68fSopenharmony_ci{ 21126881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21136881f68fSopenharmony_ci if (fs->op.utimens) { 21146881f68fSopenharmony_ci if (fs->debug) { 21156881f68fSopenharmony_ci char buf[10]; 21166881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "utimens[%s] %s %li.%09lu %li.%09lu\n", 21176881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 21186881f68fSopenharmony_ci path, tv[0].tv_sec, tv[0].tv_nsec, 21196881f68fSopenharmony_ci tv[1].tv_sec, tv[1].tv_nsec); 21206881f68fSopenharmony_ci } 21216881f68fSopenharmony_ci return fs->op.utimens(path, tv, fi); 21226881f68fSopenharmony_ci } else { 21236881f68fSopenharmony_ci return -ENOSYS; 21246881f68fSopenharmony_ci } 21256881f68fSopenharmony_ci} 21266881f68fSopenharmony_ci 21276881f68fSopenharmony_ciint fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) 21286881f68fSopenharmony_ci{ 21296881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21306881f68fSopenharmony_ci if (fs->op.access) { 21316881f68fSopenharmony_ci if (fs->debug) 21326881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "access %s 0%o\n", path, mask); 21336881f68fSopenharmony_ci 21346881f68fSopenharmony_ci return fs->op.access(path, mask); 21356881f68fSopenharmony_ci } else { 21366881f68fSopenharmony_ci return -ENOSYS; 21376881f68fSopenharmony_ci } 21386881f68fSopenharmony_ci} 21396881f68fSopenharmony_ci 21406881f68fSopenharmony_ciint fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, 21416881f68fSopenharmony_ci size_t len) 21426881f68fSopenharmony_ci{ 21436881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21446881f68fSopenharmony_ci if (fs->op.readlink) { 21456881f68fSopenharmony_ci if (fs->debug) 21466881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "readlink %s %lu\n", path, 21476881f68fSopenharmony_ci (unsigned long) len); 21486881f68fSopenharmony_ci 21496881f68fSopenharmony_ci return fs->op.readlink(path, buf, len); 21506881f68fSopenharmony_ci } else { 21516881f68fSopenharmony_ci return -ENOSYS; 21526881f68fSopenharmony_ci } 21536881f68fSopenharmony_ci} 21546881f68fSopenharmony_ci 21556881f68fSopenharmony_ciint fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, 21566881f68fSopenharmony_ci dev_t rdev) 21576881f68fSopenharmony_ci{ 21586881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21596881f68fSopenharmony_ci if (fs->op.mknod) { 21606881f68fSopenharmony_ci if (fs->debug) 21616881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "mknod %s 0%o 0x%llx umask=0%03o\n", 21626881f68fSopenharmony_ci path, mode, (unsigned long long) rdev, 21636881f68fSopenharmony_ci fuse_get_context()->umask); 21646881f68fSopenharmony_ci 21656881f68fSopenharmony_ci return fs->op.mknod(path, mode, rdev); 21666881f68fSopenharmony_ci } else { 21676881f68fSopenharmony_ci return -ENOSYS; 21686881f68fSopenharmony_ci } 21696881f68fSopenharmony_ci} 21706881f68fSopenharmony_ci 21716881f68fSopenharmony_ciint fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) 21726881f68fSopenharmony_ci{ 21736881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21746881f68fSopenharmony_ci if (fs->op.mkdir) { 21756881f68fSopenharmony_ci if (fs->debug) 21766881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "mkdir %s 0%o umask=0%03o\n", 21776881f68fSopenharmony_ci path, mode, fuse_get_context()->umask); 21786881f68fSopenharmony_ci 21796881f68fSopenharmony_ci return fs->op.mkdir(path, mode); 21806881f68fSopenharmony_ci } else { 21816881f68fSopenharmony_ci return -ENOSYS; 21826881f68fSopenharmony_ci } 21836881f68fSopenharmony_ci} 21846881f68fSopenharmony_ci 21856881f68fSopenharmony_ciint fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, 21866881f68fSopenharmony_ci const char *value, size_t size, int flags) 21876881f68fSopenharmony_ci{ 21886881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 21896881f68fSopenharmony_ci if (fs->op.setxattr) { 21906881f68fSopenharmony_ci if (fs->debug) 21916881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "setxattr %s %s %lu 0x%x\n", 21926881f68fSopenharmony_ci path, name, (unsigned long) size, flags); 21936881f68fSopenharmony_ci 21946881f68fSopenharmony_ci return fs->op.setxattr(path, name, value, size, flags); 21956881f68fSopenharmony_ci } else { 21966881f68fSopenharmony_ci return -ENOSYS; 21976881f68fSopenharmony_ci } 21986881f68fSopenharmony_ci} 21996881f68fSopenharmony_ci 22006881f68fSopenharmony_ciint fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, 22016881f68fSopenharmony_ci char *value, size_t size) 22026881f68fSopenharmony_ci{ 22036881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22046881f68fSopenharmony_ci if (fs->op.getxattr) { 22056881f68fSopenharmony_ci if (fs->debug) 22066881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "getxattr %s %s %lu\n", 22076881f68fSopenharmony_ci path, name, (unsigned long) size); 22086881f68fSopenharmony_ci 22096881f68fSopenharmony_ci return fs->op.getxattr(path, name, value, size); 22106881f68fSopenharmony_ci } else { 22116881f68fSopenharmony_ci return -ENOSYS; 22126881f68fSopenharmony_ci } 22136881f68fSopenharmony_ci} 22146881f68fSopenharmony_ci 22156881f68fSopenharmony_ciint fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, 22166881f68fSopenharmony_ci size_t size) 22176881f68fSopenharmony_ci{ 22186881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22196881f68fSopenharmony_ci if (fs->op.listxattr) { 22206881f68fSopenharmony_ci if (fs->debug) 22216881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "listxattr %s %lu\n", 22226881f68fSopenharmony_ci path, (unsigned long) size); 22236881f68fSopenharmony_ci 22246881f68fSopenharmony_ci return fs->op.listxattr(path, list, size); 22256881f68fSopenharmony_ci } else { 22266881f68fSopenharmony_ci return -ENOSYS; 22276881f68fSopenharmony_ci } 22286881f68fSopenharmony_ci} 22296881f68fSopenharmony_ci 22306881f68fSopenharmony_ciint fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, 22316881f68fSopenharmony_ci uint64_t *idx) 22326881f68fSopenharmony_ci{ 22336881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22346881f68fSopenharmony_ci if (fs->op.bmap) { 22356881f68fSopenharmony_ci if (fs->debug) 22366881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "bmap %s blocksize: %lu index: %llu\n", 22376881f68fSopenharmony_ci path, (unsigned long) blocksize, 22386881f68fSopenharmony_ci (unsigned long long) *idx); 22396881f68fSopenharmony_ci 22406881f68fSopenharmony_ci return fs->op.bmap(path, blocksize, idx); 22416881f68fSopenharmony_ci } else { 22426881f68fSopenharmony_ci return -ENOSYS; 22436881f68fSopenharmony_ci } 22446881f68fSopenharmony_ci} 22456881f68fSopenharmony_ci 22466881f68fSopenharmony_ciint fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) 22476881f68fSopenharmony_ci{ 22486881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22496881f68fSopenharmony_ci if (fs->op.removexattr) { 22506881f68fSopenharmony_ci if (fs->debug) 22516881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "removexattr %s %s\n", path, name); 22526881f68fSopenharmony_ci 22536881f68fSopenharmony_ci return fs->op.removexattr(path, name); 22546881f68fSopenharmony_ci } else { 22556881f68fSopenharmony_ci return -ENOSYS; 22566881f68fSopenharmony_ci } 22576881f68fSopenharmony_ci} 22586881f68fSopenharmony_ci 22596881f68fSopenharmony_ciint fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd, 22606881f68fSopenharmony_ci void *arg, struct fuse_file_info *fi, unsigned int flags, 22616881f68fSopenharmony_ci void *data) 22626881f68fSopenharmony_ci{ 22636881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22646881f68fSopenharmony_ci if (fs->op.ioctl) { 22656881f68fSopenharmony_ci if (fs->debug) 22666881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "ioctl[%llu] 0x%x flags: 0x%x\n", 22676881f68fSopenharmony_ci (unsigned long long) fi->fh, cmd, flags); 22686881f68fSopenharmony_ci 22696881f68fSopenharmony_ci return fs->op.ioctl(path, cmd, arg, fi, flags, data); 22706881f68fSopenharmony_ci } else 22716881f68fSopenharmony_ci return -ENOSYS; 22726881f68fSopenharmony_ci} 22736881f68fSopenharmony_ci 22746881f68fSopenharmony_ciint fuse_fs_poll(struct fuse_fs *fs, const char *path, 22756881f68fSopenharmony_ci struct fuse_file_info *fi, struct fuse_pollhandle *ph, 22766881f68fSopenharmony_ci unsigned *reventsp) 22776881f68fSopenharmony_ci{ 22786881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 22796881f68fSopenharmony_ci if (fs->op.poll) { 22806881f68fSopenharmony_ci int res; 22816881f68fSopenharmony_ci 22826881f68fSopenharmony_ci if (fs->debug) 22836881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "poll[%llu] ph: %p, events 0x%x\n", 22846881f68fSopenharmony_ci (unsigned long long) fi->fh, ph, 22856881f68fSopenharmony_ci fi->poll_events); 22866881f68fSopenharmony_ci 22876881f68fSopenharmony_ci res = fs->op.poll(path, fi, ph, reventsp); 22886881f68fSopenharmony_ci 22896881f68fSopenharmony_ci if (fs->debug && !res) 22906881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " poll[%llu] revents: 0x%x\n", 22916881f68fSopenharmony_ci (unsigned long long) fi->fh, *reventsp); 22926881f68fSopenharmony_ci 22936881f68fSopenharmony_ci return res; 22946881f68fSopenharmony_ci } else 22956881f68fSopenharmony_ci return -ENOSYS; 22966881f68fSopenharmony_ci} 22976881f68fSopenharmony_ci 22986881f68fSopenharmony_ciint fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode, 22996881f68fSopenharmony_ci off_t offset, off_t length, struct fuse_file_info *fi) 23006881f68fSopenharmony_ci{ 23016881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 23026881f68fSopenharmony_ci if (fs->op.fallocate) { 23036881f68fSopenharmony_ci if (fs->debug) 23046881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "fallocate %s mode %x, offset: %llu, length: %llu\n", 23056881f68fSopenharmony_ci path, 23066881f68fSopenharmony_ci mode, 23076881f68fSopenharmony_ci (unsigned long long) offset, 23086881f68fSopenharmony_ci (unsigned long long) length); 23096881f68fSopenharmony_ci 23106881f68fSopenharmony_ci return fs->op.fallocate(path, mode, offset, length, fi); 23116881f68fSopenharmony_ci } else 23126881f68fSopenharmony_ci return -ENOSYS; 23136881f68fSopenharmony_ci} 23146881f68fSopenharmony_ci 23156881f68fSopenharmony_cissize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in, 23166881f68fSopenharmony_ci struct fuse_file_info *fi_in, off_t off_in, 23176881f68fSopenharmony_ci const char *path_out, 23186881f68fSopenharmony_ci struct fuse_file_info *fi_out, off_t off_out, 23196881f68fSopenharmony_ci size_t len, int flags) 23206881f68fSopenharmony_ci{ 23216881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 23226881f68fSopenharmony_ci if (fs->op.copy_file_range) { 23236881f68fSopenharmony_ci if (fs->debug) 23246881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "copy_file_range from %s:%llu to " 23256881f68fSopenharmony_ci "%s:%llu, length: %llu\n", 23266881f68fSopenharmony_ci path_in, 23276881f68fSopenharmony_ci (unsigned long long) off_in, 23286881f68fSopenharmony_ci path_out, 23296881f68fSopenharmony_ci (unsigned long long) off_out, 23306881f68fSopenharmony_ci (unsigned long long) len); 23316881f68fSopenharmony_ci 23326881f68fSopenharmony_ci return fs->op.copy_file_range(path_in, fi_in, off_in, path_out, 23336881f68fSopenharmony_ci fi_out, off_out, len, flags); 23346881f68fSopenharmony_ci } else 23356881f68fSopenharmony_ci return -ENOSYS; 23366881f68fSopenharmony_ci} 23376881f68fSopenharmony_ci 23386881f68fSopenharmony_cioff_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence, 23396881f68fSopenharmony_ci struct fuse_file_info *fi) 23406881f68fSopenharmony_ci{ 23416881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 23426881f68fSopenharmony_ci if (fs->op.lseek) { 23436881f68fSopenharmony_ci if (fs->debug) { 23446881f68fSopenharmony_ci char buf[10]; 23456881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lseek[%s] %llu %d\n", 23466881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 23476881f68fSopenharmony_ci (unsigned long long) off, whence); 23486881f68fSopenharmony_ci } 23496881f68fSopenharmony_ci return fs->op.lseek(path, off, whence, fi); 23506881f68fSopenharmony_ci } else { 23516881f68fSopenharmony_ci return -ENOSYS; 23526881f68fSopenharmony_ci } 23536881f68fSopenharmony_ci} 23546881f68fSopenharmony_ci 23556881f68fSopenharmony_cistatic int is_open(struct fuse *f, fuse_ino_t dir, const char *name) 23566881f68fSopenharmony_ci{ 23576881f68fSopenharmony_ci struct node *node; 23586881f68fSopenharmony_ci int isopen = 0; 23596881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 23606881f68fSopenharmony_ci node = lookup_node(f, dir, name); 23616881f68fSopenharmony_ci if (node && node->open_count > 0) 23626881f68fSopenharmony_ci isopen = 1; 23636881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 23646881f68fSopenharmony_ci return isopen; 23656881f68fSopenharmony_ci} 23666881f68fSopenharmony_ci 23676881f68fSopenharmony_cistatic char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname, 23686881f68fSopenharmony_ci char *newname, size_t bufsize) 23696881f68fSopenharmony_ci{ 23706881f68fSopenharmony_ci struct stat buf; 23716881f68fSopenharmony_ci struct node *node; 23726881f68fSopenharmony_ci struct node *newnode; 23736881f68fSopenharmony_ci char *newpath; 23746881f68fSopenharmony_ci int res; 23756881f68fSopenharmony_ci int failctr = 10; 23766881f68fSopenharmony_ci 23776881f68fSopenharmony_ci do { 23786881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 23796881f68fSopenharmony_ci node = lookup_node(f, dir, oldname); 23806881f68fSopenharmony_ci if (node == NULL) { 23816881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 23826881f68fSopenharmony_ci return NULL; 23836881f68fSopenharmony_ci } 23846881f68fSopenharmony_ci do { 23856881f68fSopenharmony_ci f->hidectr ++; 23866881f68fSopenharmony_ci snprintf(newname, bufsize, ".fuse_hidden%08x%08x", 23876881f68fSopenharmony_ci (unsigned int) node->nodeid, f->hidectr); 23886881f68fSopenharmony_ci newnode = lookup_node(f, dir, newname); 23896881f68fSopenharmony_ci } while(newnode); 23906881f68fSopenharmony_ci 23916881f68fSopenharmony_ci res = try_get_path(f, dir, newname, &newpath, NULL, false); 23926881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 23936881f68fSopenharmony_ci if (res) 23946881f68fSopenharmony_ci break; 23956881f68fSopenharmony_ci 23966881f68fSopenharmony_ci memset(&buf, 0, sizeof(buf)); 23976881f68fSopenharmony_ci res = fuse_fs_getattr(f->fs, newpath, &buf, NULL); 23986881f68fSopenharmony_ci if (res == -ENOENT) 23996881f68fSopenharmony_ci break; 24006881f68fSopenharmony_ci free(newpath); 24016881f68fSopenharmony_ci newpath = NULL; 24026881f68fSopenharmony_ci } while(res == 0 && --failctr); 24036881f68fSopenharmony_ci 24046881f68fSopenharmony_ci return newpath; 24056881f68fSopenharmony_ci} 24066881f68fSopenharmony_ci 24076881f68fSopenharmony_cistatic int hide_node(struct fuse *f, const char *oldpath, 24086881f68fSopenharmony_ci fuse_ino_t dir, const char *oldname) 24096881f68fSopenharmony_ci{ 24106881f68fSopenharmony_ci char newname[64]; 24116881f68fSopenharmony_ci char *newpath; 24126881f68fSopenharmony_ci int err = -EBUSY; 24136881f68fSopenharmony_ci 24146881f68fSopenharmony_ci newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); 24156881f68fSopenharmony_ci if (newpath) { 24166881f68fSopenharmony_ci err = fuse_fs_rename(f->fs, oldpath, newpath, 0); 24176881f68fSopenharmony_ci if (!err) 24186881f68fSopenharmony_ci err = rename_node(f, dir, oldname, dir, newname, 1); 24196881f68fSopenharmony_ci free(newpath); 24206881f68fSopenharmony_ci } 24216881f68fSopenharmony_ci return err; 24226881f68fSopenharmony_ci} 24236881f68fSopenharmony_ci 24246881f68fSopenharmony_cistatic int mtime_eq(const struct stat *stbuf, const struct timespec *ts) 24256881f68fSopenharmony_ci{ 24266881f68fSopenharmony_ci return stbuf->st_mtime == ts->tv_sec && 24276881f68fSopenharmony_ci ST_MTIM_NSEC(stbuf) == ts->tv_nsec; 24286881f68fSopenharmony_ci} 24296881f68fSopenharmony_ci 24306881f68fSopenharmony_ci#ifndef CLOCK_MONOTONIC 24316881f68fSopenharmony_ci#define CLOCK_MONOTONIC CLOCK_REALTIME 24326881f68fSopenharmony_ci#endif 24336881f68fSopenharmony_ci 24346881f68fSopenharmony_cistatic void curr_time(struct timespec *now) 24356881f68fSopenharmony_ci{ 24366881f68fSopenharmony_ci static clockid_t clockid = CLOCK_MONOTONIC; 24376881f68fSopenharmony_ci int res = clock_gettime(clockid, now); 24386881f68fSopenharmony_ci if (res == -1 && errno == EINVAL) { 24396881f68fSopenharmony_ci clockid = CLOCK_REALTIME; 24406881f68fSopenharmony_ci res = clock_gettime(clockid, now); 24416881f68fSopenharmony_ci } 24426881f68fSopenharmony_ci if (res == -1) { 24436881f68fSopenharmony_ci perror("fuse: clock_gettime"); 24446881f68fSopenharmony_ci abort(); 24456881f68fSopenharmony_ci } 24466881f68fSopenharmony_ci} 24476881f68fSopenharmony_ci 24486881f68fSopenharmony_cistatic void update_stat(struct node *node, const struct stat *stbuf) 24496881f68fSopenharmony_ci{ 24506881f68fSopenharmony_ci if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || 24516881f68fSopenharmony_ci stbuf->st_size != node->size)) 24526881f68fSopenharmony_ci node->cache_valid = 0; 24536881f68fSopenharmony_ci node->mtime.tv_sec = stbuf->st_mtime; 24546881f68fSopenharmony_ci node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); 24556881f68fSopenharmony_ci node->size = stbuf->st_size; 24566881f68fSopenharmony_ci curr_time(&node->stat_updated); 24576881f68fSopenharmony_ci} 24586881f68fSopenharmony_ci 24596881f68fSopenharmony_cistatic int do_lookup(struct fuse *f, fuse_ino_t nodeid, const char *name, 24606881f68fSopenharmony_ci struct fuse_entry_param *e) 24616881f68fSopenharmony_ci{ 24626881f68fSopenharmony_ci struct node *node; 24636881f68fSopenharmony_ci 24646881f68fSopenharmony_ci node = find_node(f, nodeid, name); 24656881f68fSopenharmony_ci if (node == NULL) 24666881f68fSopenharmony_ci return -ENOMEM; 24676881f68fSopenharmony_ci 24686881f68fSopenharmony_ci e->ino = node->nodeid; 24696881f68fSopenharmony_ci e->generation = node->generation; 24706881f68fSopenharmony_ci e->entry_timeout = f->conf.entry_timeout; 24716881f68fSopenharmony_ci e->attr_timeout = f->conf.attr_timeout; 24726881f68fSopenharmony_ci if (f->conf.auto_cache) { 24736881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 24746881f68fSopenharmony_ci update_stat(node, &e->attr); 24756881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 24766881f68fSopenharmony_ci } 24776881f68fSopenharmony_ci set_stat(f, e->ino, &e->attr); 24786881f68fSopenharmony_ci return 0; 24796881f68fSopenharmony_ci} 24806881f68fSopenharmony_ci 24816881f68fSopenharmony_cistatic int lookup_path(struct fuse *f, fuse_ino_t nodeid, 24826881f68fSopenharmony_ci const char *name, const char *path, 24836881f68fSopenharmony_ci struct fuse_entry_param *e, struct fuse_file_info *fi) 24846881f68fSopenharmony_ci{ 24856881f68fSopenharmony_ci int res; 24866881f68fSopenharmony_ci 24876881f68fSopenharmony_ci memset(e, 0, sizeof(struct fuse_entry_param)); 24886881f68fSopenharmony_ci res = fuse_fs_getattr(f->fs, path, &e->attr, fi); 24896881f68fSopenharmony_ci if (res == 0) { 24906881f68fSopenharmony_ci res = do_lookup(f, nodeid, name, e); 24916881f68fSopenharmony_ci if (res == 0 && f->conf.debug) { 24926881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " NODEID: %llu\n", 24936881f68fSopenharmony_ci (unsigned long long) e->ino); 24946881f68fSopenharmony_ci } 24956881f68fSopenharmony_ci } 24966881f68fSopenharmony_ci return res; 24976881f68fSopenharmony_ci} 24986881f68fSopenharmony_ci 24996881f68fSopenharmony_cistatic struct fuse_context_i *fuse_get_context_internal(void) 25006881f68fSopenharmony_ci{ 25016881f68fSopenharmony_ci return (struct fuse_context_i *) pthread_getspecific(fuse_context_key); 25026881f68fSopenharmony_ci} 25036881f68fSopenharmony_ci 25046881f68fSopenharmony_cistatic struct fuse_context_i *fuse_create_context(struct fuse *f) 25056881f68fSopenharmony_ci{ 25066881f68fSopenharmony_ci struct fuse_context_i *c = fuse_get_context_internal(); 25076881f68fSopenharmony_ci if (c == NULL) { 25086881f68fSopenharmony_ci c = (struct fuse_context_i *) 25096881f68fSopenharmony_ci calloc(1, sizeof(struct fuse_context_i)); 25106881f68fSopenharmony_ci if (c == NULL) { 25116881f68fSopenharmony_ci /* This is hard to deal with properly, so just 25126881f68fSopenharmony_ci abort. If memory is so low that the 25136881f68fSopenharmony_ci context cannot be allocated, there's not 25146881f68fSopenharmony_ci much hope for the filesystem anyway */ 25156881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate thread specific data\n"); 25166881f68fSopenharmony_ci abort(); 25176881f68fSopenharmony_ci } 25186881f68fSopenharmony_ci pthread_setspecific(fuse_context_key, c); 25196881f68fSopenharmony_ci } else { 25206881f68fSopenharmony_ci memset(c, 0, sizeof(*c)); 25216881f68fSopenharmony_ci } 25226881f68fSopenharmony_ci c->ctx.fuse = f; 25236881f68fSopenharmony_ci 25246881f68fSopenharmony_ci return c; 25256881f68fSopenharmony_ci} 25266881f68fSopenharmony_ci 25276881f68fSopenharmony_cistatic void fuse_freecontext(void *data) 25286881f68fSopenharmony_ci{ 25296881f68fSopenharmony_ci free(data); 25306881f68fSopenharmony_ci} 25316881f68fSopenharmony_ci 25326881f68fSopenharmony_cistatic int fuse_create_context_key(void) 25336881f68fSopenharmony_ci{ 25346881f68fSopenharmony_ci int err = 0; 25356881f68fSopenharmony_ci pthread_mutex_lock(&fuse_context_lock); 25366881f68fSopenharmony_ci if (!fuse_context_ref) { 25376881f68fSopenharmony_ci err = pthread_key_create(&fuse_context_key, fuse_freecontext); 25386881f68fSopenharmony_ci if (err) { 25396881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n", 25406881f68fSopenharmony_ci strerror(err)); 25416881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 25426881f68fSopenharmony_ci return -1; 25436881f68fSopenharmony_ci } 25446881f68fSopenharmony_ci } 25456881f68fSopenharmony_ci fuse_context_ref++; 25466881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 25476881f68fSopenharmony_ci return 0; 25486881f68fSopenharmony_ci} 25496881f68fSopenharmony_ci 25506881f68fSopenharmony_cistatic void fuse_delete_context_key(void) 25516881f68fSopenharmony_ci{ 25526881f68fSopenharmony_ci pthread_mutex_lock(&fuse_context_lock); 25536881f68fSopenharmony_ci fuse_context_ref--; 25546881f68fSopenharmony_ci if (!fuse_context_ref) { 25556881f68fSopenharmony_ci free(pthread_getspecific(fuse_context_key)); 25566881f68fSopenharmony_ci pthread_key_delete(fuse_context_key); 25576881f68fSopenharmony_ci } 25586881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 25596881f68fSopenharmony_ci} 25606881f68fSopenharmony_ci 25616881f68fSopenharmony_cistatic struct fuse *req_fuse_prepare(fuse_req_t req) 25626881f68fSopenharmony_ci{ 25636881f68fSopenharmony_ci struct fuse_context_i *c = fuse_create_context(req_fuse(req)); 25646881f68fSopenharmony_ci const struct fuse_ctx *ctx = fuse_req_ctx(req); 25656881f68fSopenharmony_ci c->req = req; 25666881f68fSopenharmony_ci c->ctx.uid = ctx->uid; 25676881f68fSopenharmony_ci c->ctx.gid = ctx->gid; 25686881f68fSopenharmony_ci c->ctx.pid = ctx->pid; 25696881f68fSopenharmony_ci c->ctx.umask = ctx->umask; 25706881f68fSopenharmony_ci return c->ctx.fuse; 25716881f68fSopenharmony_ci} 25726881f68fSopenharmony_ci 25736881f68fSopenharmony_cistatic inline void reply_err(fuse_req_t req, int err) 25746881f68fSopenharmony_ci{ 25756881f68fSopenharmony_ci /* fuse_reply_err() uses non-negated errno values */ 25766881f68fSopenharmony_ci fuse_reply_err(req, -err); 25776881f68fSopenharmony_ci} 25786881f68fSopenharmony_ci 25796881f68fSopenharmony_cistatic void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, 25806881f68fSopenharmony_ci int err) 25816881f68fSopenharmony_ci{ 25826881f68fSopenharmony_ci if (!err) { 25836881f68fSopenharmony_ci struct fuse *f = req_fuse(req); 25846881f68fSopenharmony_ci if (fuse_reply_entry(req, e) == -ENOENT) { 25856881f68fSopenharmony_ci /* Skip forget for negative result */ 25866881f68fSopenharmony_ci if (e->ino != 0) 25876881f68fSopenharmony_ci forget_node(f, e->ino, 1); 25886881f68fSopenharmony_ci } 25896881f68fSopenharmony_ci } else 25906881f68fSopenharmony_ci reply_err(req, err); 25916881f68fSopenharmony_ci} 25926881f68fSopenharmony_ci 25936881f68fSopenharmony_civoid fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn, 25946881f68fSopenharmony_ci struct fuse_config *cfg) 25956881f68fSopenharmony_ci{ 25966881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 25976881f68fSopenharmony_ci if (!fs->op.write_buf) 25986881f68fSopenharmony_ci conn->want &= ~FUSE_CAP_SPLICE_READ; 25996881f68fSopenharmony_ci if (!fs->op.lock) 26006881f68fSopenharmony_ci conn->want &= ~FUSE_CAP_POSIX_LOCKS; 26016881f68fSopenharmony_ci if (!fs->op.flock) 26026881f68fSopenharmony_ci conn->want &= ~FUSE_CAP_FLOCK_LOCKS; 26036881f68fSopenharmony_ci if (fs->op.init) 26046881f68fSopenharmony_ci fs->user_data = fs->op.init(conn, cfg); 26056881f68fSopenharmony_ci} 26066881f68fSopenharmony_ci 26076881f68fSopenharmony_cistatic void fuse_lib_init(void *data, struct fuse_conn_info *conn) 26086881f68fSopenharmony_ci{ 26096881f68fSopenharmony_ci struct fuse *f = (struct fuse *) data; 26106881f68fSopenharmony_ci 26116881f68fSopenharmony_ci fuse_create_context(f); 26126881f68fSopenharmony_ci if(conn->capable & FUSE_CAP_EXPORT_SUPPORT) 26136881f68fSopenharmony_ci conn->want |= FUSE_CAP_EXPORT_SUPPORT; 26146881f68fSopenharmony_ci fuse_fs_init(f->fs, conn, &f->conf); 26156881f68fSopenharmony_ci} 26166881f68fSopenharmony_ci 26176881f68fSopenharmony_civoid fuse_fs_destroy(struct fuse_fs *fs) 26186881f68fSopenharmony_ci{ 26196881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 26206881f68fSopenharmony_ci if (fs->op.destroy) 26216881f68fSopenharmony_ci fs->op.destroy(fs->user_data); 26226881f68fSopenharmony_ci} 26236881f68fSopenharmony_ci 26246881f68fSopenharmony_cistatic void fuse_lib_destroy(void *data) 26256881f68fSopenharmony_ci{ 26266881f68fSopenharmony_ci struct fuse *f = (struct fuse *) data; 26276881f68fSopenharmony_ci 26286881f68fSopenharmony_ci fuse_create_context(f); 26296881f68fSopenharmony_ci fuse_fs_destroy(f->fs); 26306881f68fSopenharmony_ci} 26316881f68fSopenharmony_ci 26326881f68fSopenharmony_cistatic void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, 26336881f68fSopenharmony_ci const char *name) 26346881f68fSopenharmony_ci{ 26356881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 26366881f68fSopenharmony_ci struct fuse_entry_param e; 26376881f68fSopenharmony_ci char *path; 26386881f68fSopenharmony_ci int err; 26396881f68fSopenharmony_ci struct node *dot = NULL; 26406881f68fSopenharmony_ci 26416881f68fSopenharmony_ci if (name[0] == '.') { 26426881f68fSopenharmony_ci int len = strlen(name); 26436881f68fSopenharmony_ci 26446881f68fSopenharmony_ci if (len == 1 || (name[1] == '.' && len == 2)) { 26456881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 26466881f68fSopenharmony_ci if (len == 1) { 26476881f68fSopenharmony_ci if (f->conf.debug) 26486881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOT\n"); 26496881f68fSopenharmony_ci dot = get_node_nocheck(f, parent); 26506881f68fSopenharmony_ci if (dot == NULL) { 26516881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 26526881f68fSopenharmony_ci reply_entry(req, &e, -ESTALE); 26536881f68fSopenharmony_ci return; 26546881f68fSopenharmony_ci } 26556881f68fSopenharmony_ci dot->refctr++; 26566881f68fSopenharmony_ci } else { 26576881f68fSopenharmony_ci if (f->conf.debug) 26586881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOTDOT\n"); 26596881f68fSopenharmony_ci parent = get_node(f, parent)->parent->nodeid; 26606881f68fSopenharmony_ci } 26616881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 26626881f68fSopenharmony_ci name = NULL; 26636881f68fSopenharmony_ci } 26646881f68fSopenharmony_ci } 26656881f68fSopenharmony_ci 26666881f68fSopenharmony_ci err = get_path_name(f, parent, name, &path); 26676881f68fSopenharmony_ci if (!err) { 26686881f68fSopenharmony_ci struct fuse_intr_data d; 26696881f68fSopenharmony_ci if (f->conf.debug) 26706881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "LOOKUP %s\n", path); 26716881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 26726881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, NULL); 26736881f68fSopenharmony_ci if (err == -ENOENT && f->conf.negative_timeout != 0.0) { 26746881f68fSopenharmony_ci e.ino = 0; 26756881f68fSopenharmony_ci e.entry_timeout = f->conf.negative_timeout; 26766881f68fSopenharmony_ci err = 0; 26776881f68fSopenharmony_ci } 26786881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 26796881f68fSopenharmony_ci free_path(f, parent, path); 26806881f68fSopenharmony_ci } 26816881f68fSopenharmony_ci if (dot) { 26826881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 26836881f68fSopenharmony_ci unref_node(f, dot); 26846881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 26856881f68fSopenharmony_ci } 26866881f68fSopenharmony_ci reply_entry(req, &e, err); 26876881f68fSopenharmony_ci} 26886881f68fSopenharmony_ci 26896881f68fSopenharmony_cistatic void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup) 26906881f68fSopenharmony_ci{ 26916881f68fSopenharmony_ci if (f->conf.debug) 26926881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "FORGET %llu/%llu\n", (unsigned long long)ino, 26936881f68fSopenharmony_ci (unsigned long long) nlookup); 26946881f68fSopenharmony_ci forget_node(f, ino, nlookup); 26956881f68fSopenharmony_ci} 26966881f68fSopenharmony_ci 26976881f68fSopenharmony_cistatic void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) 26986881f68fSopenharmony_ci{ 26996881f68fSopenharmony_ci do_forget(req_fuse(req), ino, nlookup); 27006881f68fSopenharmony_ci fuse_reply_none(req); 27016881f68fSopenharmony_ci} 27026881f68fSopenharmony_ci 27036881f68fSopenharmony_cistatic void fuse_lib_forget_multi(fuse_req_t req, size_t count, 27046881f68fSopenharmony_ci struct fuse_forget_data *forgets) 27056881f68fSopenharmony_ci{ 27066881f68fSopenharmony_ci struct fuse *f = req_fuse(req); 27076881f68fSopenharmony_ci size_t i; 27086881f68fSopenharmony_ci 27096881f68fSopenharmony_ci for (i = 0; i < count; i++) 27106881f68fSopenharmony_ci do_forget(f, forgets[i].ino, forgets[i].nlookup); 27116881f68fSopenharmony_ci 27126881f68fSopenharmony_ci fuse_reply_none(req); 27136881f68fSopenharmony_ci} 27146881f68fSopenharmony_ci 27156881f68fSopenharmony_ci 27166881f68fSopenharmony_cistatic void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, 27176881f68fSopenharmony_ci struct fuse_file_info *fi) 27186881f68fSopenharmony_ci{ 27196881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 27206881f68fSopenharmony_ci struct stat buf; 27216881f68fSopenharmony_ci char *path; 27226881f68fSopenharmony_ci int err; 27236881f68fSopenharmony_ci 27246881f68fSopenharmony_ci memset(&buf, 0, sizeof(buf)); 27256881f68fSopenharmony_ci 27266881f68fSopenharmony_ci if (fi != NULL) 27276881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 27286881f68fSopenharmony_ci else 27296881f68fSopenharmony_ci err = get_path(f, ino, &path); 27306881f68fSopenharmony_ci if (!err) { 27316881f68fSopenharmony_ci struct fuse_intr_data d; 27326881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 27336881f68fSopenharmony_ci err = fuse_fs_getattr(f->fs, path, &buf, fi); 27346881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 27356881f68fSopenharmony_ci free_path(f, ino, path); 27366881f68fSopenharmony_ci } 27376881f68fSopenharmony_ci if (!err) { 27386881f68fSopenharmony_ci struct node *node; 27396881f68fSopenharmony_ci 27406881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 27416881f68fSopenharmony_ci node = get_node(f, ino); 27426881f68fSopenharmony_ci if (node->is_hidden && buf.st_nlink > 0) 27436881f68fSopenharmony_ci buf.st_nlink--; 27446881f68fSopenharmony_ci if (f->conf.auto_cache) 27456881f68fSopenharmony_ci update_stat(node, &buf); 27466881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 27476881f68fSopenharmony_ci set_stat(f, ino, &buf); 27486881f68fSopenharmony_ci fuse_reply_attr(req, &buf, f->conf.attr_timeout); 27496881f68fSopenharmony_ci } else 27506881f68fSopenharmony_ci reply_err(req, err); 27516881f68fSopenharmony_ci} 27526881f68fSopenharmony_ci 27536881f68fSopenharmony_ciint fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode, 27546881f68fSopenharmony_ci struct fuse_file_info *fi) 27556881f68fSopenharmony_ci{ 27566881f68fSopenharmony_ci fuse_get_context()->private_data = fs->user_data; 27576881f68fSopenharmony_ci if (fs->op.chmod) { 27586881f68fSopenharmony_ci if (fs->debug) { 27596881f68fSopenharmony_ci char buf[10]; 27606881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "chmod[%s] %s %llo\n", 27616881f68fSopenharmony_ci file_info_string(fi, buf, sizeof(buf)), 27626881f68fSopenharmony_ci path, (unsigned long long) mode); 27636881f68fSopenharmony_ci } 27646881f68fSopenharmony_ci return fs->op.chmod(path, mode, fi); 27656881f68fSopenharmony_ci } 27666881f68fSopenharmony_ci else 27676881f68fSopenharmony_ci return -ENOSYS; 27686881f68fSopenharmony_ci} 27696881f68fSopenharmony_ci 27706881f68fSopenharmony_cistatic void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, 27716881f68fSopenharmony_ci int valid, struct fuse_file_info *fi) 27726881f68fSopenharmony_ci{ 27736881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 27746881f68fSopenharmony_ci struct stat buf; 27756881f68fSopenharmony_ci char *path; 27766881f68fSopenharmony_ci int err; 27776881f68fSopenharmony_ci 27786881f68fSopenharmony_ci memset(&buf, 0, sizeof(buf)); 27796881f68fSopenharmony_ci if (fi != NULL) 27806881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 27816881f68fSopenharmony_ci else 27826881f68fSopenharmony_ci err = get_path(f, ino, &path); 27836881f68fSopenharmony_ci if (!err) { 27846881f68fSopenharmony_ci struct fuse_intr_data d; 27856881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 27866881f68fSopenharmony_ci err = 0; 27876881f68fSopenharmony_ci if (!err && (valid & FUSE_SET_ATTR_MODE)) 27886881f68fSopenharmony_ci err = fuse_fs_chmod(f->fs, path, attr->st_mode, fi); 27896881f68fSopenharmony_ci if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { 27906881f68fSopenharmony_ci uid_t uid = (valid & FUSE_SET_ATTR_UID) ? 27916881f68fSopenharmony_ci attr->st_uid : (uid_t) -1; 27926881f68fSopenharmony_ci gid_t gid = (valid & FUSE_SET_ATTR_GID) ? 27936881f68fSopenharmony_ci attr->st_gid : (gid_t) -1; 27946881f68fSopenharmony_ci err = fuse_fs_chown(f->fs, path, uid, gid, fi); 27956881f68fSopenharmony_ci } 27966881f68fSopenharmony_ci if (!err && (valid & FUSE_SET_ATTR_SIZE)) { 27976881f68fSopenharmony_ci err = fuse_fs_truncate(f->fs, path, 27986881f68fSopenharmony_ci attr->st_size, fi); 27996881f68fSopenharmony_ci } 28006881f68fSopenharmony_ci#ifdef HAVE_UTIMENSAT 28016881f68fSopenharmony_ci if (!err && 28026881f68fSopenharmony_ci (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) { 28036881f68fSopenharmony_ci struct timespec tv[2]; 28046881f68fSopenharmony_ci 28056881f68fSopenharmony_ci tv[0].tv_sec = 0; 28066881f68fSopenharmony_ci tv[1].tv_sec = 0; 28076881f68fSopenharmony_ci tv[0].tv_nsec = UTIME_OMIT; 28086881f68fSopenharmony_ci tv[1].tv_nsec = UTIME_OMIT; 28096881f68fSopenharmony_ci 28106881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_ATIME_NOW) 28116881f68fSopenharmony_ci tv[0].tv_nsec = UTIME_NOW; 28126881f68fSopenharmony_ci else if (valid & FUSE_SET_ATTR_ATIME) 28136881f68fSopenharmony_ci tv[0] = attr->st_atim; 28146881f68fSopenharmony_ci 28156881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_MTIME_NOW) 28166881f68fSopenharmony_ci tv[1].tv_nsec = UTIME_NOW; 28176881f68fSopenharmony_ci else if (valid & FUSE_SET_ATTR_MTIME) 28186881f68fSopenharmony_ci tv[1] = attr->st_mtim; 28196881f68fSopenharmony_ci 28206881f68fSopenharmony_ci err = fuse_fs_utimens(f->fs, path, tv, fi); 28216881f68fSopenharmony_ci } else 28226881f68fSopenharmony_ci#endif 28236881f68fSopenharmony_ci if (!err && 28246881f68fSopenharmony_ci (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == 28256881f68fSopenharmony_ci (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { 28266881f68fSopenharmony_ci struct timespec tv[2]; 28276881f68fSopenharmony_ci tv[0].tv_sec = attr->st_atime; 28286881f68fSopenharmony_ci tv[0].tv_nsec = ST_ATIM_NSEC(attr); 28296881f68fSopenharmony_ci tv[1].tv_sec = attr->st_mtime; 28306881f68fSopenharmony_ci tv[1].tv_nsec = ST_MTIM_NSEC(attr); 28316881f68fSopenharmony_ci err = fuse_fs_utimens(f->fs, path, tv, fi); 28326881f68fSopenharmony_ci } 28336881f68fSopenharmony_ci if (!err) { 28346881f68fSopenharmony_ci err = fuse_fs_getattr(f->fs, path, &buf, fi); 28356881f68fSopenharmony_ci } 28366881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 28376881f68fSopenharmony_ci free_path(f, ino, path); 28386881f68fSopenharmony_ci } 28396881f68fSopenharmony_ci if (!err) { 28406881f68fSopenharmony_ci if (f->conf.auto_cache) { 28416881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 28426881f68fSopenharmony_ci update_stat(get_node(f, ino), &buf); 28436881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 28446881f68fSopenharmony_ci } 28456881f68fSopenharmony_ci set_stat(f, ino, &buf); 28466881f68fSopenharmony_ci fuse_reply_attr(req, &buf, f->conf.attr_timeout); 28476881f68fSopenharmony_ci } else 28486881f68fSopenharmony_ci reply_err(req, err); 28496881f68fSopenharmony_ci} 28506881f68fSopenharmony_ci 28516881f68fSopenharmony_cistatic void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) 28526881f68fSopenharmony_ci{ 28536881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 28546881f68fSopenharmony_ci char *path; 28556881f68fSopenharmony_ci int err; 28566881f68fSopenharmony_ci 28576881f68fSopenharmony_ci err = get_path(f, ino, &path); 28586881f68fSopenharmony_ci if (!err) { 28596881f68fSopenharmony_ci struct fuse_intr_data d; 28606881f68fSopenharmony_ci 28616881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 28626881f68fSopenharmony_ci err = fuse_fs_access(f->fs, path, mask); 28636881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 28646881f68fSopenharmony_ci free_path(f, ino, path); 28656881f68fSopenharmony_ci } 28666881f68fSopenharmony_ci reply_err(req, err); 28676881f68fSopenharmony_ci} 28686881f68fSopenharmony_ci 28696881f68fSopenharmony_cistatic void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) 28706881f68fSopenharmony_ci{ 28716881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 28726881f68fSopenharmony_ci char linkname[PATH_MAX + 1]; 28736881f68fSopenharmony_ci char *path; 28746881f68fSopenharmony_ci int err; 28756881f68fSopenharmony_ci 28766881f68fSopenharmony_ci err = get_path(f, ino, &path); 28776881f68fSopenharmony_ci if (!err) { 28786881f68fSopenharmony_ci struct fuse_intr_data d; 28796881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 28806881f68fSopenharmony_ci err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); 28816881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 28826881f68fSopenharmony_ci free_path(f, ino, path); 28836881f68fSopenharmony_ci } 28846881f68fSopenharmony_ci if (!err) { 28856881f68fSopenharmony_ci linkname[PATH_MAX] = '\0'; 28866881f68fSopenharmony_ci fuse_reply_readlink(req, linkname); 28876881f68fSopenharmony_ci } else 28886881f68fSopenharmony_ci reply_err(req, err); 28896881f68fSopenharmony_ci} 28906881f68fSopenharmony_ci 28916881f68fSopenharmony_cistatic void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, 28926881f68fSopenharmony_ci mode_t mode, dev_t rdev) 28936881f68fSopenharmony_ci{ 28946881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 28956881f68fSopenharmony_ci struct fuse_entry_param e; 28966881f68fSopenharmony_ci char *path; 28976881f68fSopenharmony_ci int err; 28986881f68fSopenharmony_ci 28996881f68fSopenharmony_ci err = get_path_name(f, parent, name, &path); 29006881f68fSopenharmony_ci if (!err) { 29016881f68fSopenharmony_ci struct fuse_intr_data d; 29026881f68fSopenharmony_ci 29036881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 29046881f68fSopenharmony_ci err = -ENOSYS; 29056881f68fSopenharmony_ci if (S_ISREG(mode)) { 29066881f68fSopenharmony_ci struct fuse_file_info fi; 29076881f68fSopenharmony_ci 29086881f68fSopenharmony_ci memset(&fi, 0, sizeof(fi)); 29096881f68fSopenharmony_ci fi.flags = O_CREAT | O_EXCL | O_WRONLY; 29106881f68fSopenharmony_ci err = fuse_fs_create(f->fs, path, mode, &fi); 29116881f68fSopenharmony_ci if (!err) { 29126881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, 29136881f68fSopenharmony_ci &fi); 29146881f68fSopenharmony_ci fuse_fs_release(f->fs, path, &fi); 29156881f68fSopenharmony_ci } 29166881f68fSopenharmony_ci } 29176881f68fSopenharmony_ci if (err == -ENOSYS) { 29186881f68fSopenharmony_ci err = fuse_fs_mknod(f->fs, path, mode, rdev); 29196881f68fSopenharmony_ci if (!err) 29206881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, 29216881f68fSopenharmony_ci NULL); 29226881f68fSopenharmony_ci } 29236881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 29246881f68fSopenharmony_ci free_path(f, parent, path); 29256881f68fSopenharmony_ci } 29266881f68fSopenharmony_ci reply_entry(req, &e, err); 29276881f68fSopenharmony_ci} 29286881f68fSopenharmony_ci 29296881f68fSopenharmony_cistatic void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, 29306881f68fSopenharmony_ci mode_t mode) 29316881f68fSopenharmony_ci{ 29326881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 29336881f68fSopenharmony_ci struct fuse_entry_param e; 29346881f68fSopenharmony_ci char *path; 29356881f68fSopenharmony_ci int err; 29366881f68fSopenharmony_ci 29376881f68fSopenharmony_ci err = get_path_name(f, parent, name, &path); 29386881f68fSopenharmony_ci if (!err) { 29396881f68fSopenharmony_ci struct fuse_intr_data d; 29406881f68fSopenharmony_ci 29416881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 29426881f68fSopenharmony_ci err = fuse_fs_mkdir(f->fs, path, mode); 29436881f68fSopenharmony_ci if (!err) 29446881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, NULL); 29456881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 29466881f68fSopenharmony_ci free_path(f, parent, path); 29476881f68fSopenharmony_ci } 29486881f68fSopenharmony_ci reply_entry(req, &e, err); 29496881f68fSopenharmony_ci} 29506881f68fSopenharmony_ci 29516881f68fSopenharmony_cistatic void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent, 29526881f68fSopenharmony_ci const char *name) 29536881f68fSopenharmony_ci{ 29546881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 29556881f68fSopenharmony_ci struct node *wnode; 29566881f68fSopenharmony_ci char *path; 29576881f68fSopenharmony_ci int err; 29586881f68fSopenharmony_ci 29596881f68fSopenharmony_ci err = get_path_wrlock(f, parent, name, &path, &wnode); 29606881f68fSopenharmony_ci if (!err) { 29616881f68fSopenharmony_ci struct fuse_intr_data d; 29626881f68fSopenharmony_ci 29636881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 29646881f68fSopenharmony_ci if (!f->conf.hard_remove && is_open(f, parent, name)) { 29656881f68fSopenharmony_ci err = hide_node(f, path, parent, name); 29666881f68fSopenharmony_ci if (!err) { 29676881f68fSopenharmony_ci /* we have hidden the node so now check again under a lock in case it is not used any more */ 29686881f68fSopenharmony_ci if (!is_open(f, parent, wnode->name)) { 29696881f68fSopenharmony_ci char *unlinkpath; 29706881f68fSopenharmony_ci 29716881f68fSopenharmony_ci /* get the hidden file path, to unlink it */ 29726881f68fSopenharmony_ci if (try_get_path(f, wnode->nodeid, NULL, &unlinkpath, NULL, false) == 0) { 29736881f68fSopenharmony_ci err = fuse_fs_unlink(f->fs, unlinkpath); 29746881f68fSopenharmony_ci if (!err) 29756881f68fSopenharmony_ci remove_node(f, parent, wnode->name); 29766881f68fSopenharmony_ci free(unlinkpath); 29776881f68fSopenharmony_ci } 29786881f68fSopenharmony_ci } 29796881f68fSopenharmony_ci } 29806881f68fSopenharmony_ci } else { 29816881f68fSopenharmony_ci err = fuse_fs_unlink(f->fs, path); 29826881f68fSopenharmony_ci if (!err) 29836881f68fSopenharmony_ci remove_node(f, parent, name); 29846881f68fSopenharmony_ci } 29856881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 29866881f68fSopenharmony_ci free_path_wrlock(f, parent, wnode, path); 29876881f68fSopenharmony_ci } 29886881f68fSopenharmony_ci reply_err(req, err); 29896881f68fSopenharmony_ci} 29906881f68fSopenharmony_ci 29916881f68fSopenharmony_cistatic void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) 29926881f68fSopenharmony_ci{ 29936881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 29946881f68fSopenharmony_ci struct node *wnode; 29956881f68fSopenharmony_ci char *path; 29966881f68fSopenharmony_ci int err; 29976881f68fSopenharmony_ci 29986881f68fSopenharmony_ci err = get_path_wrlock(f, parent, name, &path, &wnode); 29996881f68fSopenharmony_ci if (!err) { 30006881f68fSopenharmony_ci struct fuse_intr_data d; 30016881f68fSopenharmony_ci 30026881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 30036881f68fSopenharmony_ci err = fuse_fs_rmdir(f->fs, path); 30046881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 30056881f68fSopenharmony_ci if (!err) 30066881f68fSopenharmony_ci remove_node(f, parent, name); 30076881f68fSopenharmony_ci free_path_wrlock(f, parent, wnode, path); 30086881f68fSopenharmony_ci } 30096881f68fSopenharmony_ci reply_err(req, err); 30106881f68fSopenharmony_ci} 30116881f68fSopenharmony_ci 30126881f68fSopenharmony_cistatic void fuse_lib_symlink(fuse_req_t req, const char *linkname, 30136881f68fSopenharmony_ci fuse_ino_t parent, const char *name) 30146881f68fSopenharmony_ci{ 30156881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 30166881f68fSopenharmony_ci struct fuse_entry_param e; 30176881f68fSopenharmony_ci char *path; 30186881f68fSopenharmony_ci int err; 30196881f68fSopenharmony_ci 30206881f68fSopenharmony_ci err = get_path_name(f, parent, name, &path); 30216881f68fSopenharmony_ci if (!err) { 30226881f68fSopenharmony_ci struct fuse_intr_data d; 30236881f68fSopenharmony_ci 30246881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 30256881f68fSopenharmony_ci err = fuse_fs_symlink(f->fs, linkname, path); 30266881f68fSopenharmony_ci if (!err) 30276881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, NULL); 30286881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 30296881f68fSopenharmony_ci free_path(f, parent, path); 30306881f68fSopenharmony_ci } 30316881f68fSopenharmony_ci reply_entry(req, &e, err); 30326881f68fSopenharmony_ci} 30336881f68fSopenharmony_ci 30346881f68fSopenharmony_cistatic void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir, 30356881f68fSopenharmony_ci const char *oldname, fuse_ino_t newdir, 30366881f68fSopenharmony_ci const char *newname, unsigned int flags) 30376881f68fSopenharmony_ci{ 30386881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 30396881f68fSopenharmony_ci char *oldpath; 30406881f68fSopenharmony_ci char *newpath; 30416881f68fSopenharmony_ci struct node *wnode1; 30426881f68fSopenharmony_ci struct node *wnode2; 30436881f68fSopenharmony_ci int err; 30446881f68fSopenharmony_ci 30456881f68fSopenharmony_ci err = get_path2(f, olddir, oldname, newdir, newname, 30466881f68fSopenharmony_ci &oldpath, &newpath, &wnode1, &wnode2); 30476881f68fSopenharmony_ci if (!err) { 30486881f68fSopenharmony_ci struct fuse_intr_data d; 30496881f68fSopenharmony_ci err = 0; 30506881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 30516881f68fSopenharmony_ci if (!f->conf.hard_remove && !(flags & RENAME_EXCHANGE) && 30526881f68fSopenharmony_ci is_open(f, newdir, newname)) 30536881f68fSopenharmony_ci err = hide_node(f, newpath, newdir, newname); 30546881f68fSopenharmony_ci if (!err) { 30556881f68fSopenharmony_ci err = fuse_fs_rename(f->fs, oldpath, newpath, flags); 30566881f68fSopenharmony_ci if (!err) { 30576881f68fSopenharmony_ci if (flags & RENAME_EXCHANGE) { 30586881f68fSopenharmony_ci err = exchange_node(f, olddir, oldname, 30596881f68fSopenharmony_ci newdir, newname); 30606881f68fSopenharmony_ci } else { 30616881f68fSopenharmony_ci err = rename_node(f, olddir, oldname, 30626881f68fSopenharmony_ci newdir, newname, 0); 30636881f68fSopenharmony_ci } 30646881f68fSopenharmony_ci } 30656881f68fSopenharmony_ci } 30666881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 30676881f68fSopenharmony_ci free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath); 30686881f68fSopenharmony_ci } 30696881f68fSopenharmony_ci reply_err(req, err); 30706881f68fSopenharmony_ci} 30716881f68fSopenharmony_ci 30726881f68fSopenharmony_cistatic void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, 30736881f68fSopenharmony_ci const char *newname) 30746881f68fSopenharmony_ci{ 30756881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 30766881f68fSopenharmony_ci struct fuse_entry_param e; 30776881f68fSopenharmony_ci char *oldpath; 30786881f68fSopenharmony_ci char *newpath; 30796881f68fSopenharmony_ci int err; 30806881f68fSopenharmony_ci 30816881f68fSopenharmony_ci err = get_path2(f, ino, NULL, newparent, newname, 30826881f68fSopenharmony_ci &oldpath, &newpath, NULL, NULL); 30836881f68fSopenharmony_ci if (!err) { 30846881f68fSopenharmony_ci struct fuse_intr_data d; 30856881f68fSopenharmony_ci 30866881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 30876881f68fSopenharmony_ci err = fuse_fs_link(f->fs, oldpath, newpath); 30886881f68fSopenharmony_ci if (!err) 30896881f68fSopenharmony_ci err = lookup_path(f, newparent, newname, newpath, 30906881f68fSopenharmony_ci &e, NULL); 30916881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 30926881f68fSopenharmony_ci free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); 30936881f68fSopenharmony_ci } 30946881f68fSopenharmony_ci reply_entry(req, &e, err); 30956881f68fSopenharmony_ci} 30966881f68fSopenharmony_ci 30976881f68fSopenharmony_cistatic void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, 30986881f68fSopenharmony_ci struct fuse_file_info *fi) 30996881f68fSopenharmony_ci{ 31006881f68fSopenharmony_ci struct node *node; 31016881f68fSopenharmony_ci int unlink_hidden = 0; 31026881f68fSopenharmony_ci 31036881f68fSopenharmony_ci fuse_fs_release(f->fs, path, fi); 31046881f68fSopenharmony_ci 31056881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 31066881f68fSopenharmony_ci node = get_node(f, ino); 31076881f68fSopenharmony_ci assert(node->open_count > 0); 31086881f68fSopenharmony_ci --node->open_count; 31096881f68fSopenharmony_ci if (node->is_hidden && !node->open_count) { 31106881f68fSopenharmony_ci unlink_hidden = 1; 31116881f68fSopenharmony_ci node->is_hidden = 0; 31126881f68fSopenharmony_ci } 31136881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 31146881f68fSopenharmony_ci 31156881f68fSopenharmony_ci if(unlink_hidden) { 31166881f68fSopenharmony_ci if (path) { 31176881f68fSopenharmony_ci fuse_fs_unlink(f->fs, path); 31186881f68fSopenharmony_ci } else if (f->conf.nullpath_ok) { 31196881f68fSopenharmony_ci char *unlinkpath; 31206881f68fSopenharmony_ci 31216881f68fSopenharmony_ci if (get_path(f, ino, &unlinkpath) == 0) 31226881f68fSopenharmony_ci fuse_fs_unlink(f->fs, unlinkpath); 31236881f68fSopenharmony_ci 31246881f68fSopenharmony_ci free_path(f, ino, unlinkpath); 31256881f68fSopenharmony_ci } 31266881f68fSopenharmony_ci } 31276881f68fSopenharmony_ci} 31286881f68fSopenharmony_ci 31296881f68fSopenharmony_cistatic void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, 31306881f68fSopenharmony_ci const char *name, mode_t mode, 31316881f68fSopenharmony_ci struct fuse_file_info *fi) 31326881f68fSopenharmony_ci{ 31336881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 31346881f68fSopenharmony_ci struct fuse_intr_data d; 31356881f68fSopenharmony_ci struct fuse_entry_param e; 31366881f68fSopenharmony_ci char *path; 31376881f68fSopenharmony_ci int err; 31386881f68fSopenharmony_ci 31396881f68fSopenharmony_ci err = get_path_name(f, parent, name, &path); 31406881f68fSopenharmony_ci if (!err) { 31416881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 31426881f68fSopenharmony_ci err = fuse_fs_create(f->fs, path, mode, fi); 31436881f68fSopenharmony_ci if (!err) { 31446881f68fSopenharmony_ci err = lookup_path(f, parent, name, path, &e, fi); 31456881f68fSopenharmony_ci if (err) 31466881f68fSopenharmony_ci fuse_fs_release(f->fs, path, fi); 31476881f68fSopenharmony_ci else if (!S_ISREG(e.attr.st_mode)) { 31486881f68fSopenharmony_ci err = -EIO; 31496881f68fSopenharmony_ci fuse_fs_release(f->fs, path, fi); 31506881f68fSopenharmony_ci forget_node(f, e.ino, 1); 31516881f68fSopenharmony_ci } else { 31526881f68fSopenharmony_ci if (f->conf.direct_io) 31536881f68fSopenharmony_ci fi->direct_io = 1; 31546881f68fSopenharmony_ci if (f->conf.kernel_cache) 31556881f68fSopenharmony_ci fi->keep_cache = 1; 31566881f68fSopenharmony_ci if (fi->direct_io && 31576881f68fSopenharmony_ci f->conf.parallel_direct_writes) 31586881f68fSopenharmony_ci fi->parallel_direct_writes = 1; 31596881f68fSopenharmony_ci } 31606881f68fSopenharmony_ci } 31616881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 31626881f68fSopenharmony_ci } 31636881f68fSopenharmony_ci if (!err) { 31646881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 31656881f68fSopenharmony_ci get_node(f, e.ino)->open_count++; 31666881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 31676881f68fSopenharmony_ci if (fuse_reply_create(req, &e, fi) == -ENOENT) { 31686881f68fSopenharmony_ci /* The open syscall was interrupted, so it 31696881f68fSopenharmony_ci must be cancelled */ 31706881f68fSopenharmony_ci fuse_do_release(f, e.ino, path, fi); 31716881f68fSopenharmony_ci forget_node(f, e.ino, 1); 31726881f68fSopenharmony_ci } 31736881f68fSopenharmony_ci } else { 31746881f68fSopenharmony_ci reply_err(req, err); 31756881f68fSopenharmony_ci } 31766881f68fSopenharmony_ci 31776881f68fSopenharmony_ci free_path(f, parent, path); 31786881f68fSopenharmony_ci} 31796881f68fSopenharmony_ci 31806881f68fSopenharmony_cistatic double diff_timespec(const struct timespec *t1, 31816881f68fSopenharmony_ci const struct timespec *t2) 31826881f68fSopenharmony_ci{ 31836881f68fSopenharmony_ci return (t1->tv_sec - t2->tv_sec) + 31846881f68fSopenharmony_ci ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; 31856881f68fSopenharmony_ci} 31866881f68fSopenharmony_ci 31876881f68fSopenharmony_cistatic void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path, 31886881f68fSopenharmony_ci struct fuse_file_info *fi) 31896881f68fSopenharmony_ci{ 31906881f68fSopenharmony_ci struct node *node; 31916881f68fSopenharmony_ci 31926881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 31936881f68fSopenharmony_ci node = get_node(f, ino); 31946881f68fSopenharmony_ci if (node->cache_valid) { 31956881f68fSopenharmony_ci struct timespec now; 31966881f68fSopenharmony_ci 31976881f68fSopenharmony_ci curr_time(&now); 31986881f68fSopenharmony_ci if (diff_timespec(&now, &node->stat_updated) > 31996881f68fSopenharmony_ci f->conf.ac_attr_timeout) { 32006881f68fSopenharmony_ci struct stat stbuf; 32016881f68fSopenharmony_ci int err; 32026881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 32036881f68fSopenharmony_ci err = fuse_fs_getattr(f->fs, path, &stbuf, fi); 32046881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 32056881f68fSopenharmony_ci if (!err) 32066881f68fSopenharmony_ci update_stat(node, &stbuf); 32076881f68fSopenharmony_ci else 32086881f68fSopenharmony_ci node->cache_valid = 0; 32096881f68fSopenharmony_ci } 32106881f68fSopenharmony_ci } 32116881f68fSopenharmony_ci if (node->cache_valid) 32126881f68fSopenharmony_ci fi->keep_cache = 1; 32136881f68fSopenharmony_ci 32146881f68fSopenharmony_ci node->cache_valid = 1; 32156881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 32166881f68fSopenharmony_ci} 32176881f68fSopenharmony_ci 32186881f68fSopenharmony_cistatic void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, 32196881f68fSopenharmony_ci struct fuse_file_info *fi) 32206881f68fSopenharmony_ci{ 32216881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 32226881f68fSopenharmony_ci struct fuse_intr_data d; 32236881f68fSopenharmony_ci char *path; 32246881f68fSopenharmony_ci int err; 32256881f68fSopenharmony_ci 32266881f68fSopenharmony_ci err = get_path(f, ino, &path); 32276881f68fSopenharmony_ci if (!err) { 32286881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 32296881f68fSopenharmony_ci err = fuse_fs_open(f->fs, path, fi); 32306881f68fSopenharmony_ci if (!err) { 32316881f68fSopenharmony_ci if (f->conf.direct_io) 32326881f68fSopenharmony_ci fi->direct_io = 1; 32336881f68fSopenharmony_ci if (f->conf.kernel_cache) 32346881f68fSopenharmony_ci fi->keep_cache = 1; 32356881f68fSopenharmony_ci 32366881f68fSopenharmony_ci if (f->conf.auto_cache) 32376881f68fSopenharmony_ci open_auto_cache(f, ino, path, fi); 32386881f68fSopenharmony_ci 32396881f68fSopenharmony_ci if (f->conf.no_rofd_flush && 32406881f68fSopenharmony_ci (fi->flags & O_ACCMODE) == O_RDONLY) 32416881f68fSopenharmony_ci fi->noflush = 1; 32426881f68fSopenharmony_ci 32436881f68fSopenharmony_ci if (fi->direct_io && f->conf.parallel_direct_writes) 32446881f68fSopenharmony_ci fi->parallel_direct_writes = 1; 32456881f68fSopenharmony_ci 32466881f68fSopenharmony_ci } 32476881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 32486881f68fSopenharmony_ci } 32496881f68fSopenharmony_ci if (!err) { 32506881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 32516881f68fSopenharmony_ci get_node(f, ino)->open_count++; 32526881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 32536881f68fSopenharmony_ci if (fuse_reply_open(req, fi) == -ENOENT) { 32546881f68fSopenharmony_ci /* The open syscall was interrupted, so it 32556881f68fSopenharmony_ci must be cancelled */ 32566881f68fSopenharmony_ci fuse_do_release(f, ino, path, fi); 32576881f68fSopenharmony_ci } 32586881f68fSopenharmony_ci } else 32596881f68fSopenharmony_ci reply_err(req, err); 32606881f68fSopenharmony_ci 32616881f68fSopenharmony_ci free_path(f, ino, path); 32626881f68fSopenharmony_ci} 32636881f68fSopenharmony_ci 32646881f68fSopenharmony_cistatic void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, 32656881f68fSopenharmony_ci off_t off, struct fuse_file_info *fi) 32666881f68fSopenharmony_ci{ 32676881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 32686881f68fSopenharmony_ci struct fuse_bufvec *buf = NULL; 32696881f68fSopenharmony_ci char *path; 32706881f68fSopenharmony_ci int res; 32716881f68fSopenharmony_ci 32726881f68fSopenharmony_ci res = get_path_nullok(f, ino, &path); 32736881f68fSopenharmony_ci if (res == 0) { 32746881f68fSopenharmony_ci struct fuse_intr_data d; 32756881f68fSopenharmony_ci 32766881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 32776881f68fSopenharmony_ci res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi); 32786881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 32796881f68fSopenharmony_ci free_path(f, ino, path); 32806881f68fSopenharmony_ci } 32816881f68fSopenharmony_ci 32826881f68fSopenharmony_ci if (res == 0) 32836881f68fSopenharmony_ci fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); 32846881f68fSopenharmony_ci else 32856881f68fSopenharmony_ci reply_err(req, res); 32866881f68fSopenharmony_ci 32876881f68fSopenharmony_ci fuse_free_buf(buf); 32886881f68fSopenharmony_ci} 32896881f68fSopenharmony_ci 32906881f68fSopenharmony_cistatic void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino, 32916881f68fSopenharmony_ci struct fuse_bufvec *buf, off_t off, 32926881f68fSopenharmony_ci struct fuse_file_info *fi) 32936881f68fSopenharmony_ci{ 32946881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 32956881f68fSopenharmony_ci char *path; 32966881f68fSopenharmony_ci int res; 32976881f68fSopenharmony_ci 32986881f68fSopenharmony_ci res = get_path_nullok(f, ino, &path); 32996881f68fSopenharmony_ci if (res == 0) { 33006881f68fSopenharmony_ci struct fuse_intr_data d; 33016881f68fSopenharmony_ci 33026881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 33036881f68fSopenharmony_ci res = fuse_fs_write_buf(f->fs, path, buf, off, fi); 33046881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 33056881f68fSopenharmony_ci free_path(f, ino, path); 33066881f68fSopenharmony_ci } 33076881f68fSopenharmony_ci 33086881f68fSopenharmony_ci if (res >= 0) 33096881f68fSopenharmony_ci fuse_reply_write(req, res); 33106881f68fSopenharmony_ci else 33116881f68fSopenharmony_ci reply_err(req, res); 33126881f68fSopenharmony_ci} 33136881f68fSopenharmony_ci 33146881f68fSopenharmony_cistatic void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, 33156881f68fSopenharmony_ci struct fuse_file_info *fi) 33166881f68fSopenharmony_ci{ 33176881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 33186881f68fSopenharmony_ci char *path; 33196881f68fSopenharmony_ci int err; 33206881f68fSopenharmony_ci 33216881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 33226881f68fSopenharmony_ci if (!err) { 33236881f68fSopenharmony_ci struct fuse_intr_data d; 33246881f68fSopenharmony_ci 33256881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 33266881f68fSopenharmony_ci err = fuse_fs_fsync(f->fs, path, datasync, fi); 33276881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 33286881f68fSopenharmony_ci free_path(f, ino, path); 33296881f68fSopenharmony_ci } 33306881f68fSopenharmony_ci reply_err(req, err); 33316881f68fSopenharmony_ci} 33326881f68fSopenharmony_ci 33336881f68fSopenharmony_cistatic struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, 33346881f68fSopenharmony_ci struct fuse_file_info *fi) 33356881f68fSopenharmony_ci{ 33366881f68fSopenharmony_ci struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; 33376881f68fSopenharmony_ci memset(fi, 0, sizeof(struct fuse_file_info)); 33386881f68fSopenharmony_ci fi->fh = dh->fh; 33396881f68fSopenharmony_ci return dh; 33406881f68fSopenharmony_ci} 33416881f68fSopenharmony_ci 33426881f68fSopenharmony_cistatic void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, 33436881f68fSopenharmony_ci struct fuse_file_info *llfi) 33446881f68fSopenharmony_ci{ 33456881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 33466881f68fSopenharmony_ci struct fuse_intr_data d; 33476881f68fSopenharmony_ci struct fuse_dh *dh; 33486881f68fSopenharmony_ci struct fuse_file_info fi; 33496881f68fSopenharmony_ci char *path; 33506881f68fSopenharmony_ci int err; 33516881f68fSopenharmony_ci 33526881f68fSopenharmony_ci dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); 33536881f68fSopenharmony_ci if (dh == NULL) { 33546881f68fSopenharmony_ci reply_err(req, -ENOMEM); 33556881f68fSopenharmony_ci return; 33566881f68fSopenharmony_ci } 33576881f68fSopenharmony_ci memset(dh, 0, sizeof(struct fuse_dh)); 33586881f68fSopenharmony_ci dh->fuse = f; 33596881f68fSopenharmony_ci dh->contents = NULL; 33606881f68fSopenharmony_ci dh->first = NULL; 33616881f68fSopenharmony_ci dh->len = 0; 33626881f68fSopenharmony_ci dh->filled = 0; 33636881f68fSopenharmony_ci dh->nodeid = ino; 33646881f68fSopenharmony_ci pthread_mutex_init(&dh->lock, NULL); 33656881f68fSopenharmony_ci 33666881f68fSopenharmony_ci llfi->fh = (uintptr_t) dh; 33676881f68fSopenharmony_ci 33686881f68fSopenharmony_ci memset(&fi, 0, sizeof(fi)); 33696881f68fSopenharmony_ci fi.flags = llfi->flags; 33706881f68fSopenharmony_ci 33716881f68fSopenharmony_ci err = get_path(f, ino, &path); 33726881f68fSopenharmony_ci if (!err) { 33736881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 33746881f68fSopenharmony_ci err = fuse_fs_opendir(f->fs, path, &fi); 33756881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 33766881f68fSopenharmony_ci dh->fh = fi.fh; 33776881f68fSopenharmony_ci llfi->cache_readdir = fi.cache_readdir; 33786881f68fSopenharmony_ci llfi->keep_cache = fi.keep_cache; 33796881f68fSopenharmony_ci } 33806881f68fSopenharmony_ci if (!err) { 33816881f68fSopenharmony_ci if (fuse_reply_open(req, llfi) == -ENOENT) { 33826881f68fSopenharmony_ci /* The opendir syscall was interrupted, so it 33836881f68fSopenharmony_ci must be cancelled */ 33846881f68fSopenharmony_ci fuse_fs_releasedir(f->fs, path, &fi); 33856881f68fSopenharmony_ci pthread_mutex_destroy(&dh->lock); 33866881f68fSopenharmony_ci free(dh); 33876881f68fSopenharmony_ci } 33886881f68fSopenharmony_ci } else { 33896881f68fSopenharmony_ci reply_err(req, err); 33906881f68fSopenharmony_ci pthread_mutex_destroy(&dh->lock); 33916881f68fSopenharmony_ci free(dh); 33926881f68fSopenharmony_ci } 33936881f68fSopenharmony_ci free_path(f, ino, path); 33946881f68fSopenharmony_ci} 33956881f68fSopenharmony_ci 33966881f68fSopenharmony_cistatic int extend_contents(struct fuse_dh *dh, unsigned minsize) 33976881f68fSopenharmony_ci{ 33986881f68fSopenharmony_ci if (minsize > dh->size) { 33996881f68fSopenharmony_ci char *newptr; 34006881f68fSopenharmony_ci unsigned newsize = dh->size; 34016881f68fSopenharmony_ci if (!newsize) 34026881f68fSopenharmony_ci newsize = 1024; 34036881f68fSopenharmony_ci while (newsize < minsize) { 34046881f68fSopenharmony_ci if (newsize >= 0x80000000) 34056881f68fSopenharmony_ci newsize = 0xffffffff; 34066881f68fSopenharmony_ci else 34076881f68fSopenharmony_ci newsize *= 2; 34086881f68fSopenharmony_ci } 34096881f68fSopenharmony_ci 34106881f68fSopenharmony_ci newptr = (char *) realloc(dh->contents, newsize); 34116881f68fSopenharmony_ci if (!newptr) { 34126881f68fSopenharmony_ci dh->error = -ENOMEM; 34136881f68fSopenharmony_ci return -1; 34146881f68fSopenharmony_ci } 34156881f68fSopenharmony_ci dh->contents = newptr; 34166881f68fSopenharmony_ci dh->size = newsize; 34176881f68fSopenharmony_ci } 34186881f68fSopenharmony_ci return 0; 34196881f68fSopenharmony_ci} 34206881f68fSopenharmony_ci 34216881f68fSopenharmony_cistatic int fuse_add_direntry_to_dh(struct fuse_dh *dh, const char *name, 34226881f68fSopenharmony_ci struct stat *st) 34236881f68fSopenharmony_ci{ 34246881f68fSopenharmony_ci struct fuse_direntry *de; 34256881f68fSopenharmony_ci 34266881f68fSopenharmony_ci de = malloc(sizeof(struct fuse_direntry)); 34276881f68fSopenharmony_ci if (!de) { 34286881f68fSopenharmony_ci dh->error = -ENOMEM; 34296881f68fSopenharmony_ci return -1; 34306881f68fSopenharmony_ci } 34316881f68fSopenharmony_ci de->name = strdup(name); 34326881f68fSopenharmony_ci if (!de->name) { 34336881f68fSopenharmony_ci dh->error = -ENOMEM; 34346881f68fSopenharmony_ci free(de); 34356881f68fSopenharmony_ci return -1; 34366881f68fSopenharmony_ci } 34376881f68fSopenharmony_ci de->stat = *st; 34386881f68fSopenharmony_ci de->next = NULL; 34396881f68fSopenharmony_ci 34406881f68fSopenharmony_ci *dh->last = de; 34416881f68fSopenharmony_ci dh->last = &de->next; 34426881f68fSopenharmony_ci 34436881f68fSopenharmony_ci return 0; 34446881f68fSopenharmony_ci} 34456881f68fSopenharmony_ci 34466881f68fSopenharmony_cistatic fuse_ino_t lookup_nodeid(struct fuse *f, fuse_ino_t parent, 34476881f68fSopenharmony_ci const char *name) 34486881f68fSopenharmony_ci{ 34496881f68fSopenharmony_ci struct node *node; 34506881f68fSopenharmony_ci fuse_ino_t res = FUSE_UNKNOWN_INO; 34516881f68fSopenharmony_ci 34526881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 34536881f68fSopenharmony_ci node = lookup_node(f, parent, name); 34546881f68fSopenharmony_ci if (node) 34556881f68fSopenharmony_ci res = node->nodeid; 34566881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 34576881f68fSopenharmony_ci 34586881f68fSopenharmony_ci return res; 34596881f68fSopenharmony_ci} 34606881f68fSopenharmony_ci 34616881f68fSopenharmony_cistatic int fill_dir(void *dh_, const char *name, const struct stat *statp, 34626881f68fSopenharmony_ci off_t off, enum fuse_fill_dir_flags flags) 34636881f68fSopenharmony_ci{ 34646881f68fSopenharmony_ci struct fuse_dh *dh = (struct fuse_dh *) dh_; 34656881f68fSopenharmony_ci struct stat stbuf; 34666881f68fSopenharmony_ci 34676881f68fSopenharmony_ci if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) { 34686881f68fSopenharmony_ci dh->error = -EIO; 34696881f68fSopenharmony_ci return 1; 34706881f68fSopenharmony_ci } 34716881f68fSopenharmony_ci 34726881f68fSopenharmony_ci if (statp) 34736881f68fSopenharmony_ci stbuf = *statp; 34746881f68fSopenharmony_ci else { 34756881f68fSopenharmony_ci memset(&stbuf, 0, sizeof(stbuf)); 34766881f68fSopenharmony_ci stbuf.st_ino = FUSE_UNKNOWN_INO; 34776881f68fSopenharmony_ci } 34786881f68fSopenharmony_ci 34796881f68fSopenharmony_ci if (!dh->fuse->conf.use_ino) { 34806881f68fSopenharmony_ci stbuf.st_ino = FUSE_UNKNOWN_INO; 34816881f68fSopenharmony_ci if (dh->fuse->conf.readdir_ino) { 34826881f68fSopenharmony_ci stbuf.st_ino = (ino_t) 34836881f68fSopenharmony_ci lookup_nodeid(dh->fuse, dh->nodeid, name); 34846881f68fSopenharmony_ci } 34856881f68fSopenharmony_ci } 34866881f68fSopenharmony_ci 34876881f68fSopenharmony_ci if (off) { 34886881f68fSopenharmony_ci size_t newlen; 34896881f68fSopenharmony_ci 34906881f68fSopenharmony_ci if (dh->filled) { 34916881f68fSopenharmony_ci dh->error = -EIO; 34926881f68fSopenharmony_ci return 1; 34936881f68fSopenharmony_ci } 34946881f68fSopenharmony_ci 34956881f68fSopenharmony_ci if (dh->first) { 34966881f68fSopenharmony_ci dh->error = -EIO; 34976881f68fSopenharmony_ci return 1; 34986881f68fSopenharmony_ci } 34996881f68fSopenharmony_ci 35006881f68fSopenharmony_ci if (extend_contents(dh, dh->needlen) == -1) 35016881f68fSopenharmony_ci return 1; 35026881f68fSopenharmony_ci 35036881f68fSopenharmony_ci newlen = dh->len + 35046881f68fSopenharmony_ci fuse_add_direntry(dh->req, dh->contents + dh->len, 35056881f68fSopenharmony_ci dh->needlen - dh->len, name, 35066881f68fSopenharmony_ci &stbuf, off); 35076881f68fSopenharmony_ci if (newlen > dh->needlen) 35086881f68fSopenharmony_ci return 1; 35096881f68fSopenharmony_ci 35106881f68fSopenharmony_ci dh->len = newlen; 35116881f68fSopenharmony_ci } else { 35126881f68fSopenharmony_ci dh->filled = 1; 35136881f68fSopenharmony_ci 35146881f68fSopenharmony_ci if (fuse_add_direntry_to_dh(dh, name, &stbuf) == -1) 35156881f68fSopenharmony_ci return 1; 35166881f68fSopenharmony_ci } 35176881f68fSopenharmony_ci return 0; 35186881f68fSopenharmony_ci} 35196881f68fSopenharmony_ci 35206881f68fSopenharmony_cistatic int is_dot_or_dotdot(const char *name) 35216881f68fSopenharmony_ci{ 35226881f68fSopenharmony_ci return name[0] == '.' && (name[1] == '\0' || 35236881f68fSopenharmony_ci (name[1] == '.' && name[2] == '\0')); 35246881f68fSopenharmony_ci} 35256881f68fSopenharmony_ci 35266881f68fSopenharmony_cistatic int fill_dir_plus(void *dh_, const char *name, const struct stat *statp, 35276881f68fSopenharmony_ci off_t off, enum fuse_fill_dir_flags flags) 35286881f68fSopenharmony_ci{ 35296881f68fSopenharmony_ci struct fuse_dh *dh = (struct fuse_dh *) dh_; 35306881f68fSopenharmony_ci struct fuse_entry_param e = { 35316881f68fSopenharmony_ci /* ino=0 tells the kernel to ignore readdirplus stat info */ 35326881f68fSopenharmony_ci .ino = 0, 35336881f68fSopenharmony_ci }; 35346881f68fSopenharmony_ci struct fuse *f = dh->fuse; 35356881f68fSopenharmony_ci int res; 35366881f68fSopenharmony_ci 35376881f68fSopenharmony_ci if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) { 35386881f68fSopenharmony_ci dh->error = -EIO; 35396881f68fSopenharmony_ci return 1; 35406881f68fSopenharmony_ci } 35416881f68fSopenharmony_ci 35426881f68fSopenharmony_ci if (statp && (flags & FUSE_FILL_DIR_PLUS)) { 35436881f68fSopenharmony_ci e.attr = *statp; 35446881f68fSopenharmony_ci 35456881f68fSopenharmony_ci if (!is_dot_or_dotdot(name)) { 35466881f68fSopenharmony_ci res = do_lookup(f, dh->nodeid, name, &e); 35476881f68fSopenharmony_ci if (res) { 35486881f68fSopenharmony_ci dh->error = res; 35496881f68fSopenharmony_ci return 1; 35506881f68fSopenharmony_ci } 35516881f68fSopenharmony_ci } 35526881f68fSopenharmony_ci } else { 35536881f68fSopenharmony_ci e.attr.st_ino = FUSE_UNKNOWN_INO; 35546881f68fSopenharmony_ci if (statp) { 35556881f68fSopenharmony_ci e.attr.st_mode = statp->st_mode; 35566881f68fSopenharmony_ci if (f->conf.use_ino) 35576881f68fSopenharmony_ci e.attr.st_ino = statp->st_ino; 35586881f68fSopenharmony_ci } 35596881f68fSopenharmony_ci if (!f->conf.use_ino && f->conf.readdir_ino) { 35606881f68fSopenharmony_ci e.attr.st_ino = (ino_t) 35616881f68fSopenharmony_ci lookup_nodeid(f, dh->nodeid, name); 35626881f68fSopenharmony_ci } 35636881f68fSopenharmony_ci } 35646881f68fSopenharmony_ci 35656881f68fSopenharmony_ci if (off) { 35666881f68fSopenharmony_ci size_t newlen; 35676881f68fSopenharmony_ci 35686881f68fSopenharmony_ci if (dh->filled) { 35696881f68fSopenharmony_ci dh->error = -EIO; 35706881f68fSopenharmony_ci return 1; 35716881f68fSopenharmony_ci } 35726881f68fSopenharmony_ci 35736881f68fSopenharmony_ci if (dh->first) { 35746881f68fSopenharmony_ci dh->error = -EIO; 35756881f68fSopenharmony_ci return 1; 35766881f68fSopenharmony_ci } 35776881f68fSopenharmony_ci if (extend_contents(dh, dh->needlen) == -1) 35786881f68fSopenharmony_ci return 1; 35796881f68fSopenharmony_ci 35806881f68fSopenharmony_ci newlen = dh->len + 35816881f68fSopenharmony_ci fuse_add_direntry_plus(dh->req, dh->contents + dh->len, 35826881f68fSopenharmony_ci dh->needlen - dh->len, name, 35836881f68fSopenharmony_ci &e, off); 35846881f68fSopenharmony_ci if (newlen > dh->needlen) 35856881f68fSopenharmony_ci return 1; 35866881f68fSopenharmony_ci dh->len = newlen; 35876881f68fSopenharmony_ci } else { 35886881f68fSopenharmony_ci dh->filled = 1; 35896881f68fSopenharmony_ci 35906881f68fSopenharmony_ci if (fuse_add_direntry_to_dh(dh, name, &e.attr) == -1) 35916881f68fSopenharmony_ci return 1; 35926881f68fSopenharmony_ci } 35936881f68fSopenharmony_ci 35946881f68fSopenharmony_ci return 0; 35956881f68fSopenharmony_ci} 35966881f68fSopenharmony_ci 35976881f68fSopenharmony_cistatic void free_direntries(struct fuse_direntry *de) 35986881f68fSopenharmony_ci{ 35996881f68fSopenharmony_ci while (de) { 36006881f68fSopenharmony_ci struct fuse_direntry *next = de->next; 36016881f68fSopenharmony_ci free(de->name); 36026881f68fSopenharmony_ci free(de); 36036881f68fSopenharmony_ci de = next; 36046881f68fSopenharmony_ci } 36056881f68fSopenharmony_ci} 36066881f68fSopenharmony_ci 36076881f68fSopenharmony_cistatic int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino, 36086881f68fSopenharmony_ci size_t size, off_t off, struct fuse_dh *dh, 36096881f68fSopenharmony_ci struct fuse_file_info *fi, 36106881f68fSopenharmony_ci enum fuse_readdir_flags flags) 36116881f68fSopenharmony_ci{ 36126881f68fSopenharmony_ci char *path; 36136881f68fSopenharmony_ci int err; 36146881f68fSopenharmony_ci 36156881f68fSopenharmony_ci if (f->fs->op.readdir) 36166881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 36176881f68fSopenharmony_ci else 36186881f68fSopenharmony_ci err = get_path(f, ino, &path); 36196881f68fSopenharmony_ci if (!err) { 36206881f68fSopenharmony_ci struct fuse_intr_data d; 36216881f68fSopenharmony_ci fuse_fill_dir_t filler = fill_dir; 36226881f68fSopenharmony_ci 36236881f68fSopenharmony_ci if (flags & FUSE_READDIR_PLUS) 36246881f68fSopenharmony_ci filler = fill_dir_plus; 36256881f68fSopenharmony_ci 36266881f68fSopenharmony_ci free_direntries(dh->first); 36276881f68fSopenharmony_ci dh->first = NULL; 36286881f68fSopenharmony_ci dh->last = &dh->first; 36296881f68fSopenharmony_ci dh->len = 0; 36306881f68fSopenharmony_ci dh->error = 0; 36316881f68fSopenharmony_ci dh->needlen = size; 36326881f68fSopenharmony_ci dh->filled = 0; 36336881f68fSopenharmony_ci dh->req = req; 36346881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 36356881f68fSopenharmony_ci err = fuse_fs_readdir(f->fs, path, dh, filler, off, fi, flags); 36366881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 36376881f68fSopenharmony_ci dh->req = NULL; 36386881f68fSopenharmony_ci if (!err) 36396881f68fSopenharmony_ci err = dh->error; 36406881f68fSopenharmony_ci if (err) 36416881f68fSopenharmony_ci dh->filled = 0; 36426881f68fSopenharmony_ci free_path(f, ino, path); 36436881f68fSopenharmony_ci } 36446881f68fSopenharmony_ci return err; 36456881f68fSopenharmony_ci} 36466881f68fSopenharmony_ci 36476881f68fSopenharmony_cistatic int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh, 36486881f68fSopenharmony_ci off_t off, enum fuse_readdir_flags flags) 36496881f68fSopenharmony_ci{ 36506881f68fSopenharmony_ci off_t pos; 36516881f68fSopenharmony_ci struct fuse_direntry *de = dh->first; 36526881f68fSopenharmony_ci 36536881f68fSopenharmony_ci dh->len = 0; 36546881f68fSopenharmony_ci 36556881f68fSopenharmony_ci if (extend_contents(dh, dh->needlen) == -1) 36566881f68fSopenharmony_ci return dh->error; 36576881f68fSopenharmony_ci 36586881f68fSopenharmony_ci for (pos = 0; pos < off; pos++) { 36596881f68fSopenharmony_ci if (!de) 36606881f68fSopenharmony_ci break; 36616881f68fSopenharmony_ci 36626881f68fSopenharmony_ci de = de->next; 36636881f68fSopenharmony_ci } 36646881f68fSopenharmony_ci while (de) { 36656881f68fSopenharmony_ci char *p = dh->contents + dh->len; 36666881f68fSopenharmony_ci unsigned rem = dh->needlen - dh->len; 36676881f68fSopenharmony_ci unsigned thislen; 36686881f68fSopenharmony_ci unsigned newlen; 36696881f68fSopenharmony_ci pos++; 36706881f68fSopenharmony_ci 36716881f68fSopenharmony_ci if (flags & FUSE_READDIR_PLUS) { 36726881f68fSopenharmony_ci struct fuse_entry_param e = { 36736881f68fSopenharmony_ci .ino = 0, 36746881f68fSopenharmony_ci .attr = de->stat, 36756881f68fSopenharmony_ci }; 36766881f68fSopenharmony_ci thislen = fuse_add_direntry_plus(req, p, rem, 36776881f68fSopenharmony_ci de->name, &e, pos); 36786881f68fSopenharmony_ci } else { 36796881f68fSopenharmony_ci thislen = fuse_add_direntry(req, p, rem, 36806881f68fSopenharmony_ci de->name, &de->stat, pos); 36816881f68fSopenharmony_ci } 36826881f68fSopenharmony_ci newlen = dh->len + thislen; 36836881f68fSopenharmony_ci if (newlen > dh->needlen) 36846881f68fSopenharmony_ci break; 36856881f68fSopenharmony_ci dh->len = newlen; 36866881f68fSopenharmony_ci de = de->next; 36876881f68fSopenharmony_ci } 36886881f68fSopenharmony_ci return 0; 36896881f68fSopenharmony_ci} 36906881f68fSopenharmony_ci 36916881f68fSopenharmony_cistatic void fuse_readdir_common(fuse_req_t req, fuse_ino_t ino, size_t size, 36926881f68fSopenharmony_ci off_t off, struct fuse_file_info *llfi, 36936881f68fSopenharmony_ci enum fuse_readdir_flags flags) 36946881f68fSopenharmony_ci{ 36956881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 36966881f68fSopenharmony_ci struct fuse_file_info fi; 36976881f68fSopenharmony_ci struct fuse_dh *dh = get_dirhandle(llfi, &fi); 36986881f68fSopenharmony_ci int err; 36996881f68fSopenharmony_ci 37006881f68fSopenharmony_ci pthread_mutex_lock(&dh->lock); 37016881f68fSopenharmony_ci /* According to SUS, directory contents need to be refreshed on 37026881f68fSopenharmony_ci rewinddir() */ 37036881f68fSopenharmony_ci if (!off) 37046881f68fSopenharmony_ci dh->filled = 0; 37056881f68fSopenharmony_ci 37066881f68fSopenharmony_ci if (!dh->filled) { 37076881f68fSopenharmony_ci err = readdir_fill(f, req, ino, size, off, dh, &fi, flags); 37086881f68fSopenharmony_ci if (err) { 37096881f68fSopenharmony_ci reply_err(req, err); 37106881f68fSopenharmony_ci goto out; 37116881f68fSopenharmony_ci } 37126881f68fSopenharmony_ci } 37136881f68fSopenharmony_ci if (dh->filled) { 37146881f68fSopenharmony_ci dh->needlen = size; 37156881f68fSopenharmony_ci err = readdir_fill_from_list(req, dh, off, flags); 37166881f68fSopenharmony_ci if (err) { 37176881f68fSopenharmony_ci reply_err(req, err); 37186881f68fSopenharmony_ci goto out; 37196881f68fSopenharmony_ci } 37206881f68fSopenharmony_ci } 37216881f68fSopenharmony_ci fuse_reply_buf(req, dh->contents, dh->len); 37226881f68fSopenharmony_ciout: 37236881f68fSopenharmony_ci pthread_mutex_unlock(&dh->lock); 37246881f68fSopenharmony_ci} 37256881f68fSopenharmony_ci 37266881f68fSopenharmony_cistatic void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, 37276881f68fSopenharmony_ci off_t off, struct fuse_file_info *llfi) 37286881f68fSopenharmony_ci{ 37296881f68fSopenharmony_ci fuse_readdir_common(req, ino, size, off, llfi, 0); 37306881f68fSopenharmony_ci} 37316881f68fSopenharmony_ci 37326881f68fSopenharmony_cistatic void fuse_lib_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, 37336881f68fSopenharmony_ci off_t off, struct fuse_file_info *llfi) 37346881f68fSopenharmony_ci{ 37356881f68fSopenharmony_ci fuse_readdir_common(req, ino, size, off, llfi, FUSE_READDIR_PLUS); 37366881f68fSopenharmony_ci} 37376881f68fSopenharmony_ci 37386881f68fSopenharmony_cistatic void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino, 37396881f68fSopenharmony_ci struct fuse_file_info *llfi) 37406881f68fSopenharmony_ci{ 37416881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 37426881f68fSopenharmony_ci struct fuse_intr_data d; 37436881f68fSopenharmony_ci struct fuse_file_info fi; 37446881f68fSopenharmony_ci struct fuse_dh *dh = get_dirhandle(llfi, &fi); 37456881f68fSopenharmony_ci char *path; 37466881f68fSopenharmony_ci 37476881f68fSopenharmony_ci get_path_nullok(f, ino, &path); 37486881f68fSopenharmony_ci 37496881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 37506881f68fSopenharmony_ci fuse_fs_releasedir(f->fs, path, &fi); 37516881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 37526881f68fSopenharmony_ci free_path(f, ino, path); 37536881f68fSopenharmony_ci 37546881f68fSopenharmony_ci pthread_mutex_lock(&dh->lock); 37556881f68fSopenharmony_ci pthread_mutex_unlock(&dh->lock); 37566881f68fSopenharmony_ci pthread_mutex_destroy(&dh->lock); 37576881f68fSopenharmony_ci free_direntries(dh->first); 37586881f68fSopenharmony_ci free(dh->contents); 37596881f68fSopenharmony_ci free(dh); 37606881f68fSopenharmony_ci reply_err(req, 0); 37616881f68fSopenharmony_ci} 37626881f68fSopenharmony_ci 37636881f68fSopenharmony_cistatic void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, 37646881f68fSopenharmony_ci struct fuse_file_info *llfi) 37656881f68fSopenharmony_ci{ 37666881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 37676881f68fSopenharmony_ci struct fuse_file_info fi; 37686881f68fSopenharmony_ci char *path; 37696881f68fSopenharmony_ci int err; 37706881f68fSopenharmony_ci 37716881f68fSopenharmony_ci get_dirhandle(llfi, &fi); 37726881f68fSopenharmony_ci 37736881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 37746881f68fSopenharmony_ci if (!err) { 37756881f68fSopenharmony_ci struct fuse_intr_data d; 37766881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 37776881f68fSopenharmony_ci err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); 37786881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 37796881f68fSopenharmony_ci free_path(f, ino, path); 37806881f68fSopenharmony_ci } 37816881f68fSopenharmony_ci reply_err(req, err); 37826881f68fSopenharmony_ci} 37836881f68fSopenharmony_ci 37846881f68fSopenharmony_cistatic void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) 37856881f68fSopenharmony_ci{ 37866881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 37876881f68fSopenharmony_ci struct statvfs buf; 37886881f68fSopenharmony_ci char *path = NULL; 37896881f68fSopenharmony_ci int err = 0; 37906881f68fSopenharmony_ci 37916881f68fSopenharmony_ci memset(&buf, 0, sizeof(buf)); 37926881f68fSopenharmony_ci if (ino) 37936881f68fSopenharmony_ci err = get_path(f, ino, &path); 37946881f68fSopenharmony_ci 37956881f68fSopenharmony_ci if (!err) { 37966881f68fSopenharmony_ci struct fuse_intr_data d; 37976881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 37986881f68fSopenharmony_ci err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); 37996881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 38006881f68fSopenharmony_ci free_path(f, ino, path); 38016881f68fSopenharmony_ci } 38026881f68fSopenharmony_ci 38036881f68fSopenharmony_ci if (!err) 38046881f68fSopenharmony_ci fuse_reply_statfs(req, &buf); 38056881f68fSopenharmony_ci else 38066881f68fSopenharmony_ci reply_err(req, err); 38076881f68fSopenharmony_ci} 38086881f68fSopenharmony_ci 38096881f68fSopenharmony_cistatic void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, 38106881f68fSopenharmony_ci const char *value, size_t size, int flags) 38116881f68fSopenharmony_ci{ 38126881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 38136881f68fSopenharmony_ci char *path; 38146881f68fSopenharmony_ci int err; 38156881f68fSopenharmony_ci 38166881f68fSopenharmony_ci err = get_path(f, ino, &path); 38176881f68fSopenharmony_ci if (!err) { 38186881f68fSopenharmony_ci struct fuse_intr_data d; 38196881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 38206881f68fSopenharmony_ci err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); 38216881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 38226881f68fSopenharmony_ci free_path(f, ino, path); 38236881f68fSopenharmony_ci } 38246881f68fSopenharmony_ci reply_err(req, err); 38256881f68fSopenharmony_ci} 38266881f68fSopenharmony_ci 38276881f68fSopenharmony_cistatic int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, 38286881f68fSopenharmony_ci const char *name, char *value, size_t size) 38296881f68fSopenharmony_ci{ 38306881f68fSopenharmony_ci int err; 38316881f68fSopenharmony_ci char *path; 38326881f68fSopenharmony_ci 38336881f68fSopenharmony_ci err = get_path(f, ino, &path); 38346881f68fSopenharmony_ci if (!err) { 38356881f68fSopenharmony_ci struct fuse_intr_data d; 38366881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 38376881f68fSopenharmony_ci err = fuse_fs_getxattr(f->fs, path, name, value, size); 38386881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 38396881f68fSopenharmony_ci free_path(f, ino, path); 38406881f68fSopenharmony_ci } 38416881f68fSopenharmony_ci return err; 38426881f68fSopenharmony_ci} 38436881f68fSopenharmony_ci 38446881f68fSopenharmony_cistatic void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, 38456881f68fSopenharmony_ci size_t size) 38466881f68fSopenharmony_ci{ 38476881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 38486881f68fSopenharmony_ci int res; 38496881f68fSopenharmony_ci 38506881f68fSopenharmony_ci if (size) { 38516881f68fSopenharmony_ci char *value = (char *) malloc(size); 38526881f68fSopenharmony_ci if (value == NULL) { 38536881f68fSopenharmony_ci reply_err(req, -ENOMEM); 38546881f68fSopenharmony_ci return; 38556881f68fSopenharmony_ci } 38566881f68fSopenharmony_ci res = common_getxattr(f, req, ino, name, value, size); 38576881f68fSopenharmony_ci if (res > 0) 38586881f68fSopenharmony_ci fuse_reply_buf(req, value, res); 38596881f68fSopenharmony_ci else 38606881f68fSopenharmony_ci reply_err(req, res); 38616881f68fSopenharmony_ci free(value); 38626881f68fSopenharmony_ci } else { 38636881f68fSopenharmony_ci res = common_getxattr(f, req, ino, name, NULL, 0); 38646881f68fSopenharmony_ci if (res >= 0) 38656881f68fSopenharmony_ci fuse_reply_xattr(req, res); 38666881f68fSopenharmony_ci else 38676881f68fSopenharmony_ci reply_err(req, res); 38686881f68fSopenharmony_ci } 38696881f68fSopenharmony_ci} 38706881f68fSopenharmony_ci 38716881f68fSopenharmony_cistatic int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, 38726881f68fSopenharmony_ci char *list, size_t size) 38736881f68fSopenharmony_ci{ 38746881f68fSopenharmony_ci char *path; 38756881f68fSopenharmony_ci int err; 38766881f68fSopenharmony_ci 38776881f68fSopenharmony_ci err = get_path(f, ino, &path); 38786881f68fSopenharmony_ci if (!err) { 38796881f68fSopenharmony_ci struct fuse_intr_data d; 38806881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 38816881f68fSopenharmony_ci err = fuse_fs_listxattr(f->fs, path, list, size); 38826881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 38836881f68fSopenharmony_ci free_path(f, ino, path); 38846881f68fSopenharmony_ci } 38856881f68fSopenharmony_ci return err; 38866881f68fSopenharmony_ci} 38876881f68fSopenharmony_ci 38886881f68fSopenharmony_cistatic void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) 38896881f68fSopenharmony_ci{ 38906881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 38916881f68fSopenharmony_ci int res; 38926881f68fSopenharmony_ci 38936881f68fSopenharmony_ci if (size) { 38946881f68fSopenharmony_ci char *list = (char *) malloc(size); 38956881f68fSopenharmony_ci if (list == NULL) { 38966881f68fSopenharmony_ci reply_err(req, -ENOMEM); 38976881f68fSopenharmony_ci return; 38986881f68fSopenharmony_ci } 38996881f68fSopenharmony_ci res = common_listxattr(f, req, ino, list, size); 39006881f68fSopenharmony_ci if (res > 0) 39016881f68fSopenharmony_ci fuse_reply_buf(req, list, res); 39026881f68fSopenharmony_ci else 39036881f68fSopenharmony_ci reply_err(req, res); 39046881f68fSopenharmony_ci free(list); 39056881f68fSopenharmony_ci } else { 39066881f68fSopenharmony_ci res = common_listxattr(f, req, ino, NULL, 0); 39076881f68fSopenharmony_ci if (res >= 0) 39086881f68fSopenharmony_ci fuse_reply_xattr(req, res); 39096881f68fSopenharmony_ci else 39106881f68fSopenharmony_ci reply_err(req, res); 39116881f68fSopenharmony_ci } 39126881f68fSopenharmony_ci} 39136881f68fSopenharmony_ci 39146881f68fSopenharmony_cistatic void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, 39156881f68fSopenharmony_ci const char *name) 39166881f68fSopenharmony_ci{ 39176881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 39186881f68fSopenharmony_ci char *path; 39196881f68fSopenharmony_ci int err; 39206881f68fSopenharmony_ci 39216881f68fSopenharmony_ci err = get_path(f, ino, &path); 39226881f68fSopenharmony_ci if (!err) { 39236881f68fSopenharmony_ci struct fuse_intr_data d; 39246881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 39256881f68fSopenharmony_ci err = fuse_fs_removexattr(f->fs, path, name); 39266881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 39276881f68fSopenharmony_ci free_path(f, ino, path); 39286881f68fSopenharmony_ci } 39296881f68fSopenharmony_ci reply_err(req, err); 39306881f68fSopenharmony_ci} 39316881f68fSopenharmony_ci 39326881f68fSopenharmony_cistatic struct lock *locks_conflict(struct node *node, const struct lock *lock) 39336881f68fSopenharmony_ci{ 39346881f68fSopenharmony_ci struct lock *l; 39356881f68fSopenharmony_ci 39366881f68fSopenharmony_ci for (l = node->locks; l; l = l->next) 39376881f68fSopenharmony_ci if (l->owner != lock->owner && 39386881f68fSopenharmony_ci lock->start <= l->end && l->start <= lock->end && 39396881f68fSopenharmony_ci (l->type == F_WRLCK || lock->type == F_WRLCK)) 39406881f68fSopenharmony_ci break; 39416881f68fSopenharmony_ci 39426881f68fSopenharmony_ci return l; 39436881f68fSopenharmony_ci} 39446881f68fSopenharmony_ci 39456881f68fSopenharmony_cistatic void delete_lock(struct lock **lockp) 39466881f68fSopenharmony_ci{ 39476881f68fSopenharmony_ci struct lock *l = *lockp; 39486881f68fSopenharmony_ci *lockp = l->next; 39496881f68fSopenharmony_ci free(l); 39506881f68fSopenharmony_ci} 39516881f68fSopenharmony_ci 39526881f68fSopenharmony_cistatic void insert_lock(struct lock **pos, struct lock *lock) 39536881f68fSopenharmony_ci{ 39546881f68fSopenharmony_ci lock->next = *pos; 39556881f68fSopenharmony_ci *pos = lock; 39566881f68fSopenharmony_ci} 39576881f68fSopenharmony_ci 39586881f68fSopenharmony_cistatic int locks_insert(struct node *node, struct lock *lock) 39596881f68fSopenharmony_ci{ 39606881f68fSopenharmony_ci struct lock **lp; 39616881f68fSopenharmony_ci struct lock *newl1 = NULL; 39626881f68fSopenharmony_ci struct lock *newl2 = NULL; 39636881f68fSopenharmony_ci 39646881f68fSopenharmony_ci if (lock->type != F_UNLCK || lock->start != 0 || 39656881f68fSopenharmony_ci lock->end != OFFSET_MAX) { 39666881f68fSopenharmony_ci newl1 = malloc(sizeof(struct lock)); 39676881f68fSopenharmony_ci newl2 = malloc(sizeof(struct lock)); 39686881f68fSopenharmony_ci 39696881f68fSopenharmony_ci if (!newl1 || !newl2) { 39706881f68fSopenharmony_ci free(newl1); 39716881f68fSopenharmony_ci free(newl2); 39726881f68fSopenharmony_ci return -ENOLCK; 39736881f68fSopenharmony_ci } 39746881f68fSopenharmony_ci } 39756881f68fSopenharmony_ci 39766881f68fSopenharmony_ci for (lp = &node->locks; *lp;) { 39776881f68fSopenharmony_ci struct lock *l = *lp; 39786881f68fSopenharmony_ci if (l->owner != lock->owner) 39796881f68fSopenharmony_ci goto skip; 39806881f68fSopenharmony_ci 39816881f68fSopenharmony_ci if (lock->type == l->type) { 39826881f68fSopenharmony_ci if (l->end < lock->start - 1) 39836881f68fSopenharmony_ci goto skip; 39846881f68fSopenharmony_ci if (lock->end < l->start - 1) 39856881f68fSopenharmony_ci break; 39866881f68fSopenharmony_ci if (l->start <= lock->start && lock->end <= l->end) 39876881f68fSopenharmony_ci goto out; 39886881f68fSopenharmony_ci if (l->start < lock->start) 39896881f68fSopenharmony_ci lock->start = l->start; 39906881f68fSopenharmony_ci if (lock->end < l->end) 39916881f68fSopenharmony_ci lock->end = l->end; 39926881f68fSopenharmony_ci goto delete; 39936881f68fSopenharmony_ci } else { 39946881f68fSopenharmony_ci if (l->end < lock->start) 39956881f68fSopenharmony_ci goto skip; 39966881f68fSopenharmony_ci if (lock->end < l->start) 39976881f68fSopenharmony_ci break; 39986881f68fSopenharmony_ci if (lock->start <= l->start && l->end <= lock->end) 39996881f68fSopenharmony_ci goto delete; 40006881f68fSopenharmony_ci if (l->end <= lock->end) { 40016881f68fSopenharmony_ci l->end = lock->start - 1; 40026881f68fSopenharmony_ci goto skip; 40036881f68fSopenharmony_ci } 40046881f68fSopenharmony_ci if (lock->start <= l->start) { 40056881f68fSopenharmony_ci l->start = lock->end + 1; 40066881f68fSopenharmony_ci break; 40076881f68fSopenharmony_ci } 40086881f68fSopenharmony_ci *newl2 = *l; 40096881f68fSopenharmony_ci newl2->start = lock->end + 1; 40106881f68fSopenharmony_ci l->end = lock->start - 1; 40116881f68fSopenharmony_ci insert_lock(&l->next, newl2); 40126881f68fSopenharmony_ci newl2 = NULL; 40136881f68fSopenharmony_ci } 40146881f68fSopenharmony_ci skip: 40156881f68fSopenharmony_ci lp = &l->next; 40166881f68fSopenharmony_ci continue; 40176881f68fSopenharmony_ci 40186881f68fSopenharmony_ci delete: 40196881f68fSopenharmony_ci delete_lock(lp); 40206881f68fSopenharmony_ci } 40216881f68fSopenharmony_ci if (lock->type != F_UNLCK) { 40226881f68fSopenharmony_ci *newl1 = *lock; 40236881f68fSopenharmony_ci insert_lock(lp, newl1); 40246881f68fSopenharmony_ci newl1 = NULL; 40256881f68fSopenharmony_ci } 40266881f68fSopenharmony_ciout: 40276881f68fSopenharmony_ci free(newl1); 40286881f68fSopenharmony_ci free(newl2); 40296881f68fSopenharmony_ci return 0; 40306881f68fSopenharmony_ci} 40316881f68fSopenharmony_ci 40326881f68fSopenharmony_cistatic void flock_to_lock(struct flock *flock, struct lock *lock) 40336881f68fSopenharmony_ci{ 40346881f68fSopenharmony_ci memset(lock, 0, sizeof(struct lock)); 40356881f68fSopenharmony_ci lock->type = flock->l_type; 40366881f68fSopenharmony_ci lock->start = flock->l_start; 40376881f68fSopenharmony_ci lock->end = 40386881f68fSopenharmony_ci flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; 40396881f68fSopenharmony_ci lock->pid = flock->l_pid; 40406881f68fSopenharmony_ci} 40416881f68fSopenharmony_ci 40426881f68fSopenharmony_cistatic void lock_to_flock(struct lock *lock, struct flock *flock) 40436881f68fSopenharmony_ci{ 40446881f68fSopenharmony_ci flock->l_type = lock->type; 40456881f68fSopenharmony_ci flock->l_start = lock->start; 40466881f68fSopenharmony_ci flock->l_len = 40476881f68fSopenharmony_ci (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; 40486881f68fSopenharmony_ci flock->l_pid = lock->pid; 40496881f68fSopenharmony_ci} 40506881f68fSopenharmony_ci 40516881f68fSopenharmony_cistatic int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, 40526881f68fSopenharmony_ci const char *path, struct fuse_file_info *fi) 40536881f68fSopenharmony_ci{ 40546881f68fSopenharmony_ci struct fuse_intr_data d; 40556881f68fSopenharmony_ci struct flock lock; 40566881f68fSopenharmony_ci struct lock l; 40576881f68fSopenharmony_ci int err; 40586881f68fSopenharmony_ci int errlock; 40596881f68fSopenharmony_ci 40606881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 40616881f68fSopenharmony_ci memset(&lock, 0, sizeof(lock)); 40626881f68fSopenharmony_ci lock.l_type = F_UNLCK; 40636881f68fSopenharmony_ci lock.l_whence = SEEK_SET; 40646881f68fSopenharmony_ci err = fuse_fs_flush(f->fs, path, fi); 40656881f68fSopenharmony_ci errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); 40666881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 40676881f68fSopenharmony_ci 40686881f68fSopenharmony_ci if (errlock != -ENOSYS) { 40696881f68fSopenharmony_ci flock_to_lock(&lock, &l); 40706881f68fSopenharmony_ci l.owner = fi->lock_owner; 40716881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 40726881f68fSopenharmony_ci locks_insert(get_node(f, ino), &l); 40736881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 40746881f68fSopenharmony_ci 40756881f68fSopenharmony_ci /* if op.lock() is defined FLUSH is needed regardless 40766881f68fSopenharmony_ci of op.flush() */ 40776881f68fSopenharmony_ci if (err == -ENOSYS) 40786881f68fSopenharmony_ci err = 0; 40796881f68fSopenharmony_ci } 40806881f68fSopenharmony_ci return err; 40816881f68fSopenharmony_ci} 40826881f68fSopenharmony_ci 40836881f68fSopenharmony_cistatic void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, 40846881f68fSopenharmony_ci struct fuse_file_info *fi) 40856881f68fSopenharmony_ci{ 40866881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 40876881f68fSopenharmony_ci struct fuse_intr_data d; 40886881f68fSopenharmony_ci char *path; 40896881f68fSopenharmony_ci int err = 0; 40906881f68fSopenharmony_ci 40916881f68fSopenharmony_ci get_path_nullok(f, ino, &path); 40926881f68fSopenharmony_ci if (fi->flush) { 40936881f68fSopenharmony_ci err = fuse_flush_common(f, req, ino, path, fi); 40946881f68fSopenharmony_ci if (err == -ENOSYS) 40956881f68fSopenharmony_ci err = 0; 40966881f68fSopenharmony_ci } 40976881f68fSopenharmony_ci 40986881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 40996881f68fSopenharmony_ci fuse_do_release(f, ino, path, fi); 41006881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 41016881f68fSopenharmony_ci free_path(f, ino, path); 41026881f68fSopenharmony_ci 41036881f68fSopenharmony_ci reply_err(req, err); 41046881f68fSopenharmony_ci} 41056881f68fSopenharmony_ci 41066881f68fSopenharmony_cistatic void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, 41076881f68fSopenharmony_ci struct fuse_file_info *fi) 41086881f68fSopenharmony_ci{ 41096881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 41106881f68fSopenharmony_ci char *path; 41116881f68fSopenharmony_ci int err; 41126881f68fSopenharmony_ci 41136881f68fSopenharmony_ci get_path_nullok(f, ino, &path); 41146881f68fSopenharmony_ci err = fuse_flush_common(f, req, ino, path, fi); 41156881f68fSopenharmony_ci free_path(f, ino, path); 41166881f68fSopenharmony_ci 41176881f68fSopenharmony_ci reply_err(req, err); 41186881f68fSopenharmony_ci} 41196881f68fSopenharmony_ci 41206881f68fSopenharmony_cistatic int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, 41216881f68fSopenharmony_ci struct fuse_file_info *fi, struct flock *lock, 41226881f68fSopenharmony_ci int cmd) 41236881f68fSopenharmony_ci{ 41246881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 41256881f68fSopenharmony_ci char *path; 41266881f68fSopenharmony_ci int err; 41276881f68fSopenharmony_ci 41286881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 41296881f68fSopenharmony_ci if (!err) { 41306881f68fSopenharmony_ci struct fuse_intr_data d; 41316881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 41326881f68fSopenharmony_ci err = fuse_fs_lock(f->fs, path, fi, cmd, lock); 41336881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 41346881f68fSopenharmony_ci free_path(f, ino, path); 41356881f68fSopenharmony_ci } 41366881f68fSopenharmony_ci return err; 41376881f68fSopenharmony_ci} 41386881f68fSopenharmony_ci 41396881f68fSopenharmony_cistatic void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, 41406881f68fSopenharmony_ci struct fuse_file_info *fi, struct flock *lock) 41416881f68fSopenharmony_ci{ 41426881f68fSopenharmony_ci int err; 41436881f68fSopenharmony_ci struct lock l; 41446881f68fSopenharmony_ci struct lock *conflict; 41456881f68fSopenharmony_ci struct fuse *f = req_fuse(req); 41466881f68fSopenharmony_ci 41476881f68fSopenharmony_ci flock_to_lock(lock, &l); 41486881f68fSopenharmony_ci l.owner = fi->lock_owner; 41496881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 41506881f68fSopenharmony_ci conflict = locks_conflict(get_node(f, ino), &l); 41516881f68fSopenharmony_ci if (conflict) 41526881f68fSopenharmony_ci lock_to_flock(conflict, lock); 41536881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 41546881f68fSopenharmony_ci if (!conflict) 41556881f68fSopenharmony_ci err = fuse_lock_common(req, ino, fi, lock, F_GETLK); 41566881f68fSopenharmony_ci else 41576881f68fSopenharmony_ci err = 0; 41586881f68fSopenharmony_ci 41596881f68fSopenharmony_ci if (!err) 41606881f68fSopenharmony_ci fuse_reply_lock(req, lock); 41616881f68fSopenharmony_ci else 41626881f68fSopenharmony_ci reply_err(req, err); 41636881f68fSopenharmony_ci} 41646881f68fSopenharmony_ci 41656881f68fSopenharmony_cistatic void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, 41666881f68fSopenharmony_ci struct fuse_file_info *fi, struct flock *lock, 41676881f68fSopenharmony_ci int sleep) 41686881f68fSopenharmony_ci{ 41696881f68fSopenharmony_ci int err = fuse_lock_common(req, ino, fi, lock, 41706881f68fSopenharmony_ci sleep ? F_SETLKW : F_SETLK); 41716881f68fSopenharmony_ci if (!err) { 41726881f68fSopenharmony_ci struct fuse *f = req_fuse(req); 41736881f68fSopenharmony_ci struct lock l; 41746881f68fSopenharmony_ci flock_to_lock(lock, &l); 41756881f68fSopenharmony_ci l.owner = fi->lock_owner; 41766881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 41776881f68fSopenharmony_ci locks_insert(get_node(f, ino), &l); 41786881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 41796881f68fSopenharmony_ci } 41806881f68fSopenharmony_ci reply_err(req, err); 41816881f68fSopenharmony_ci} 41826881f68fSopenharmony_ci 41836881f68fSopenharmony_cistatic void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino, 41846881f68fSopenharmony_ci struct fuse_file_info *fi, int op) 41856881f68fSopenharmony_ci{ 41866881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 41876881f68fSopenharmony_ci char *path; 41886881f68fSopenharmony_ci int err; 41896881f68fSopenharmony_ci 41906881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 41916881f68fSopenharmony_ci if (err == 0) { 41926881f68fSopenharmony_ci struct fuse_intr_data d; 41936881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 41946881f68fSopenharmony_ci err = fuse_fs_flock(f->fs, path, fi, op); 41956881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 41966881f68fSopenharmony_ci free_path(f, ino, path); 41976881f68fSopenharmony_ci } 41986881f68fSopenharmony_ci reply_err(req, err); 41996881f68fSopenharmony_ci} 42006881f68fSopenharmony_ci 42016881f68fSopenharmony_cistatic void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, 42026881f68fSopenharmony_ci uint64_t idx) 42036881f68fSopenharmony_ci{ 42046881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 42056881f68fSopenharmony_ci struct fuse_intr_data d; 42066881f68fSopenharmony_ci char *path; 42076881f68fSopenharmony_ci int err; 42086881f68fSopenharmony_ci 42096881f68fSopenharmony_ci err = get_path(f, ino, &path); 42106881f68fSopenharmony_ci if (!err) { 42116881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 42126881f68fSopenharmony_ci err = fuse_fs_bmap(f->fs, path, blocksize, &idx); 42136881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 42146881f68fSopenharmony_ci free_path(f, ino, path); 42156881f68fSopenharmony_ci } 42166881f68fSopenharmony_ci if (!err) 42176881f68fSopenharmony_ci fuse_reply_bmap(req, idx); 42186881f68fSopenharmony_ci else 42196881f68fSopenharmony_ci reply_err(req, err); 42206881f68fSopenharmony_ci} 42216881f68fSopenharmony_ci 42226881f68fSopenharmony_cistatic void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, 42236881f68fSopenharmony_ci void *arg, struct fuse_file_info *llfi, 42246881f68fSopenharmony_ci unsigned int flags, const void *in_buf, 42256881f68fSopenharmony_ci size_t in_bufsz, size_t out_bufsz) 42266881f68fSopenharmony_ci{ 42276881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 42286881f68fSopenharmony_ci struct fuse_intr_data d; 42296881f68fSopenharmony_ci struct fuse_file_info fi; 42306881f68fSopenharmony_ci char *path, *out_buf = NULL; 42316881f68fSopenharmony_ci int err; 42326881f68fSopenharmony_ci 42336881f68fSopenharmony_ci err = -EPERM; 42346881f68fSopenharmony_ci if (flags & FUSE_IOCTL_UNRESTRICTED) 42356881f68fSopenharmony_ci goto err; 42366881f68fSopenharmony_ci 42376881f68fSopenharmony_ci if (flags & FUSE_IOCTL_DIR) 42386881f68fSopenharmony_ci get_dirhandle(llfi, &fi); 42396881f68fSopenharmony_ci else 42406881f68fSopenharmony_ci fi = *llfi; 42416881f68fSopenharmony_ci 42426881f68fSopenharmony_ci if (out_bufsz) { 42436881f68fSopenharmony_ci err = -ENOMEM; 42446881f68fSopenharmony_ci out_buf = malloc(out_bufsz); 42456881f68fSopenharmony_ci if (!out_buf) 42466881f68fSopenharmony_ci goto err; 42476881f68fSopenharmony_ci } 42486881f68fSopenharmony_ci 42496881f68fSopenharmony_ci assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); 42506881f68fSopenharmony_ci if (out_buf && in_bufsz) 42516881f68fSopenharmony_ci memcpy(out_buf, in_buf, in_bufsz); 42526881f68fSopenharmony_ci 42536881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 42546881f68fSopenharmony_ci if (err) 42556881f68fSopenharmony_ci goto err; 42566881f68fSopenharmony_ci 42576881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 42586881f68fSopenharmony_ci 42596881f68fSopenharmony_ci err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags, 42606881f68fSopenharmony_ci out_buf ? out_buf : (void *)in_buf); 42616881f68fSopenharmony_ci 42626881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 42636881f68fSopenharmony_ci free_path(f, ino, path); 42646881f68fSopenharmony_ci 42656881f68fSopenharmony_ci if (err < 0) 42666881f68fSopenharmony_ci goto err; 42676881f68fSopenharmony_ci fuse_reply_ioctl(req, err, out_buf, out_bufsz); 42686881f68fSopenharmony_ci goto out; 42696881f68fSopenharmony_cierr: 42706881f68fSopenharmony_ci reply_err(req, err); 42716881f68fSopenharmony_ciout: 42726881f68fSopenharmony_ci free(out_buf); 42736881f68fSopenharmony_ci} 42746881f68fSopenharmony_ci 42756881f68fSopenharmony_cistatic void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino, 42766881f68fSopenharmony_ci struct fuse_file_info *fi, struct fuse_pollhandle *ph) 42776881f68fSopenharmony_ci{ 42786881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 42796881f68fSopenharmony_ci struct fuse_intr_data d; 42806881f68fSopenharmony_ci char *path; 42816881f68fSopenharmony_ci int err; 42826881f68fSopenharmony_ci unsigned revents = 0; 42836881f68fSopenharmony_ci 42846881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 42856881f68fSopenharmony_ci if (!err) { 42866881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 42876881f68fSopenharmony_ci err = fuse_fs_poll(f->fs, path, fi, ph, &revents); 42886881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 42896881f68fSopenharmony_ci free_path(f, ino, path); 42906881f68fSopenharmony_ci } 42916881f68fSopenharmony_ci if (!err) 42926881f68fSopenharmony_ci fuse_reply_poll(req, revents); 42936881f68fSopenharmony_ci else 42946881f68fSopenharmony_ci reply_err(req, err); 42956881f68fSopenharmony_ci} 42966881f68fSopenharmony_ci 42976881f68fSopenharmony_cistatic void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, 42986881f68fSopenharmony_ci off_t offset, off_t length, struct fuse_file_info *fi) 42996881f68fSopenharmony_ci{ 43006881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 43016881f68fSopenharmony_ci struct fuse_intr_data d; 43026881f68fSopenharmony_ci char *path; 43036881f68fSopenharmony_ci int err; 43046881f68fSopenharmony_ci 43056881f68fSopenharmony_ci err = get_path_nullok(f, ino, &path); 43066881f68fSopenharmony_ci if (!err) { 43076881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 43086881f68fSopenharmony_ci err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi); 43096881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 43106881f68fSopenharmony_ci free_path(f, ino, path); 43116881f68fSopenharmony_ci } 43126881f68fSopenharmony_ci reply_err(req, err); 43136881f68fSopenharmony_ci} 43146881f68fSopenharmony_ci 43156881f68fSopenharmony_cistatic void fuse_lib_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, 43166881f68fSopenharmony_ci off_t off_in, struct fuse_file_info *fi_in, 43176881f68fSopenharmony_ci fuse_ino_t nodeid_out, off_t off_out, 43186881f68fSopenharmony_ci struct fuse_file_info *fi_out, size_t len, 43196881f68fSopenharmony_ci int flags) 43206881f68fSopenharmony_ci{ 43216881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 43226881f68fSopenharmony_ci struct fuse_intr_data d; 43236881f68fSopenharmony_ci char *path_in, *path_out; 43246881f68fSopenharmony_ci int err; 43256881f68fSopenharmony_ci ssize_t res; 43266881f68fSopenharmony_ci 43276881f68fSopenharmony_ci err = get_path_nullok(f, nodeid_in, &path_in); 43286881f68fSopenharmony_ci if (err) { 43296881f68fSopenharmony_ci reply_err(req, err); 43306881f68fSopenharmony_ci return; 43316881f68fSopenharmony_ci } 43326881f68fSopenharmony_ci 43336881f68fSopenharmony_ci err = get_path_nullok(f, nodeid_out, &path_out); 43346881f68fSopenharmony_ci if (err) { 43356881f68fSopenharmony_ci free_path(f, nodeid_in, path_in); 43366881f68fSopenharmony_ci reply_err(req, err); 43376881f68fSopenharmony_ci return; 43386881f68fSopenharmony_ci } 43396881f68fSopenharmony_ci 43406881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 43416881f68fSopenharmony_ci res = fuse_fs_copy_file_range(f->fs, path_in, fi_in, off_in, path_out, 43426881f68fSopenharmony_ci fi_out, off_out, len, flags); 43436881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 43446881f68fSopenharmony_ci 43456881f68fSopenharmony_ci if (res >= 0) 43466881f68fSopenharmony_ci fuse_reply_write(req, res); 43476881f68fSopenharmony_ci else 43486881f68fSopenharmony_ci reply_err(req, res); 43496881f68fSopenharmony_ci 43506881f68fSopenharmony_ci free_path(f, nodeid_in, path_in); 43516881f68fSopenharmony_ci free_path(f, nodeid_out, path_out); 43526881f68fSopenharmony_ci} 43536881f68fSopenharmony_ci 43546881f68fSopenharmony_cistatic void fuse_lib_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, 43556881f68fSopenharmony_ci struct fuse_file_info *fi) 43566881f68fSopenharmony_ci{ 43576881f68fSopenharmony_ci struct fuse *f = req_fuse_prepare(req); 43586881f68fSopenharmony_ci struct fuse_intr_data d; 43596881f68fSopenharmony_ci char *path; 43606881f68fSopenharmony_ci int err; 43616881f68fSopenharmony_ci off_t res; 43626881f68fSopenharmony_ci 43636881f68fSopenharmony_ci err = get_path(f, ino, &path); 43646881f68fSopenharmony_ci if (err) { 43656881f68fSopenharmony_ci reply_err(req, err); 43666881f68fSopenharmony_ci return; 43676881f68fSopenharmony_ci } 43686881f68fSopenharmony_ci 43696881f68fSopenharmony_ci fuse_prepare_interrupt(f, req, &d); 43706881f68fSopenharmony_ci res = fuse_fs_lseek(f->fs, path, off, whence, fi); 43716881f68fSopenharmony_ci fuse_finish_interrupt(f, req, &d); 43726881f68fSopenharmony_ci free_path(f, ino, path); 43736881f68fSopenharmony_ci if (res >= 0) 43746881f68fSopenharmony_ci fuse_reply_lseek(req, res); 43756881f68fSopenharmony_ci else 43766881f68fSopenharmony_ci reply_err(req, res); 43776881f68fSopenharmony_ci} 43786881f68fSopenharmony_ci 43796881f68fSopenharmony_cistatic int clean_delay(struct fuse *f) 43806881f68fSopenharmony_ci{ 43816881f68fSopenharmony_ci /* 43826881f68fSopenharmony_ci * This is calculating the delay between clean runs. To 43836881f68fSopenharmony_ci * reduce the number of cleans we are doing them 10 times 43846881f68fSopenharmony_ci * within the remember window. 43856881f68fSopenharmony_ci */ 43866881f68fSopenharmony_ci int min_sleep = 60; 43876881f68fSopenharmony_ci int max_sleep = 3600; 43886881f68fSopenharmony_ci int sleep_time = f->conf.remember / 10; 43896881f68fSopenharmony_ci 43906881f68fSopenharmony_ci if (sleep_time > max_sleep) 43916881f68fSopenharmony_ci return max_sleep; 43926881f68fSopenharmony_ci if (sleep_time < min_sleep) 43936881f68fSopenharmony_ci return min_sleep; 43946881f68fSopenharmony_ci return sleep_time; 43956881f68fSopenharmony_ci} 43966881f68fSopenharmony_ci 43976881f68fSopenharmony_ciint fuse_clean_cache(struct fuse *f) 43986881f68fSopenharmony_ci{ 43996881f68fSopenharmony_ci struct node_lru *lnode; 44006881f68fSopenharmony_ci struct list_head *curr, *next; 44016881f68fSopenharmony_ci struct node *node; 44026881f68fSopenharmony_ci struct timespec now; 44036881f68fSopenharmony_ci 44046881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 44056881f68fSopenharmony_ci 44066881f68fSopenharmony_ci curr_time(&now); 44076881f68fSopenharmony_ci 44086881f68fSopenharmony_ci for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { 44096881f68fSopenharmony_ci double age; 44106881f68fSopenharmony_ci 44116881f68fSopenharmony_ci next = curr->next; 44126881f68fSopenharmony_ci lnode = list_entry(curr, struct node_lru, lru); 44136881f68fSopenharmony_ci node = &lnode->node; 44146881f68fSopenharmony_ci 44156881f68fSopenharmony_ci age = diff_timespec(&now, &lnode->forget_time); 44166881f68fSopenharmony_ci if (age <= f->conf.remember) 44176881f68fSopenharmony_ci break; 44186881f68fSopenharmony_ci 44196881f68fSopenharmony_ci assert(node->nlookup == 1); 44206881f68fSopenharmony_ci 44216881f68fSopenharmony_ci /* Don't forget active directories */ 44226881f68fSopenharmony_ci if (node->refctr > 1) 44236881f68fSopenharmony_ci continue; 44246881f68fSopenharmony_ci 44256881f68fSopenharmony_ci node->nlookup = 0; 44266881f68fSopenharmony_ci unhash_name(f, node); 44276881f68fSopenharmony_ci unref_node(f, node); 44286881f68fSopenharmony_ci } 44296881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 44306881f68fSopenharmony_ci 44316881f68fSopenharmony_ci return clean_delay(f); 44326881f68fSopenharmony_ci} 44336881f68fSopenharmony_ci 44346881f68fSopenharmony_cistatic struct fuse_lowlevel_ops fuse_path_ops = { 44356881f68fSopenharmony_ci .init = fuse_lib_init, 44366881f68fSopenharmony_ci .destroy = fuse_lib_destroy, 44376881f68fSopenharmony_ci .lookup = fuse_lib_lookup, 44386881f68fSopenharmony_ci .forget = fuse_lib_forget, 44396881f68fSopenharmony_ci .forget_multi = fuse_lib_forget_multi, 44406881f68fSopenharmony_ci .getattr = fuse_lib_getattr, 44416881f68fSopenharmony_ci .setattr = fuse_lib_setattr, 44426881f68fSopenharmony_ci .access = fuse_lib_access, 44436881f68fSopenharmony_ci .readlink = fuse_lib_readlink, 44446881f68fSopenharmony_ci .mknod = fuse_lib_mknod, 44456881f68fSopenharmony_ci .mkdir = fuse_lib_mkdir, 44466881f68fSopenharmony_ci .unlink = fuse_lib_unlink, 44476881f68fSopenharmony_ci .rmdir = fuse_lib_rmdir, 44486881f68fSopenharmony_ci .symlink = fuse_lib_symlink, 44496881f68fSopenharmony_ci .rename = fuse_lib_rename, 44506881f68fSopenharmony_ci .link = fuse_lib_link, 44516881f68fSopenharmony_ci .create = fuse_lib_create, 44526881f68fSopenharmony_ci .open = fuse_lib_open, 44536881f68fSopenharmony_ci .read = fuse_lib_read, 44546881f68fSopenharmony_ci .write_buf = fuse_lib_write_buf, 44556881f68fSopenharmony_ci .flush = fuse_lib_flush, 44566881f68fSopenharmony_ci .release = fuse_lib_release, 44576881f68fSopenharmony_ci .fsync = fuse_lib_fsync, 44586881f68fSopenharmony_ci .opendir = fuse_lib_opendir, 44596881f68fSopenharmony_ci .readdir = fuse_lib_readdir, 44606881f68fSopenharmony_ci .readdirplus = fuse_lib_readdirplus, 44616881f68fSopenharmony_ci .releasedir = fuse_lib_releasedir, 44626881f68fSopenharmony_ci .fsyncdir = fuse_lib_fsyncdir, 44636881f68fSopenharmony_ci .statfs = fuse_lib_statfs, 44646881f68fSopenharmony_ci .setxattr = fuse_lib_setxattr, 44656881f68fSopenharmony_ci .getxattr = fuse_lib_getxattr, 44666881f68fSopenharmony_ci .listxattr = fuse_lib_listxattr, 44676881f68fSopenharmony_ci .removexattr = fuse_lib_removexattr, 44686881f68fSopenharmony_ci .getlk = fuse_lib_getlk, 44696881f68fSopenharmony_ci .setlk = fuse_lib_setlk, 44706881f68fSopenharmony_ci .flock = fuse_lib_flock, 44716881f68fSopenharmony_ci .bmap = fuse_lib_bmap, 44726881f68fSopenharmony_ci .ioctl = fuse_lib_ioctl, 44736881f68fSopenharmony_ci .poll = fuse_lib_poll, 44746881f68fSopenharmony_ci .fallocate = fuse_lib_fallocate, 44756881f68fSopenharmony_ci .copy_file_range = fuse_lib_copy_file_range, 44766881f68fSopenharmony_ci .lseek = fuse_lib_lseek, 44776881f68fSopenharmony_ci}; 44786881f68fSopenharmony_ci 44796881f68fSopenharmony_ciint fuse_notify_poll(struct fuse_pollhandle *ph) 44806881f68fSopenharmony_ci{ 44816881f68fSopenharmony_ci return fuse_lowlevel_notify_poll(ph); 44826881f68fSopenharmony_ci} 44836881f68fSopenharmony_ci 44846881f68fSopenharmony_cistruct fuse_session *fuse_get_session(struct fuse *f) 44856881f68fSopenharmony_ci{ 44866881f68fSopenharmony_ci return f->se; 44876881f68fSopenharmony_ci} 44886881f68fSopenharmony_ci 44896881f68fSopenharmony_cistatic int fuse_session_loop_remember(struct fuse *f) 44906881f68fSopenharmony_ci{ 44916881f68fSopenharmony_ci struct fuse_session *se = f->se; 44926881f68fSopenharmony_ci int res = 0; 44936881f68fSopenharmony_ci struct timespec now; 44946881f68fSopenharmony_ci time_t next_clean; 44956881f68fSopenharmony_ci struct pollfd fds = { 44966881f68fSopenharmony_ci .fd = se->fd, 44976881f68fSopenharmony_ci .events = POLLIN 44986881f68fSopenharmony_ci }; 44996881f68fSopenharmony_ci struct fuse_buf fbuf = { 45006881f68fSopenharmony_ci .mem = NULL, 45016881f68fSopenharmony_ci }; 45026881f68fSopenharmony_ci 45036881f68fSopenharmony_ci curr_time(&now); 45046881f68fSopenharmony_ci next_clean = now.tv_sec; 45056881f68fSopenharmony_ci while (!fuse_session_exited(se)) { 45066881f68fSopenharmony_ci unsigned timeout; 45076881f68fSopenharmony_ci 45086881f68fSopenharmony_ci curr_time(&now); 45096881f68fSopenharmony_ci if (now.tv_sec < next_clean) 45106881f68fSopenharmony_ci timeout = next_clean - now.tv_sec; 45116881f68fSopenharmony_ci else 45126881f68fSopenharmony_ci timeout = 0; 45136881f68fSopenharmony_ci 45146881f68fSopenharmony_ci res = poll(&fds, 1, timeout * 1000); 45156881f68fSopenharmony_ci if (res == -1) { 45166881f68fSopenharmony_ci if (errno == EINTR) 45176881f68fSopenharmony_ci continue; 45186881f68fSopenharmony_ci else 45196881f68fSopenharmony_ci break; 45206881f68fSopenharmony_ci } else if (res > 0) { 45216881f68fSopenharmony_ci res = fuse_session_receive_buf_int(se, &fbuf, NULL); 45226881f68fSopenharmony_ci 45236881f68fSopenharmony_ci if (res == -EINTR) 45246881f68fSopenharmony_ci continue; 45256881f68fSopenharmony_ci if (res <= 0) 45266881f68fSopenharmony_ci break; 45276881f68fSopenharmony_ci 45286881f68fSopenharmony_ci fuse_session_process_buf_int(se, &fbuf, NULL); 45296881f68fSopenharmony_ci } else { 45306881f68fSopenharmony_ci timeout = fuse_clean_cache(f); 45316881f68fSopenharmony_ci curr_time(&now); 45326881f68fSopenharmony_ci next_clean = now.tv_sec + timeout; 45336881f68fSopenharmony_ci } 45346881f68fSopenharmony_ci } 45356881f68fSopenharmony_ci 45366881f68fSopenharmony_ci free(fbuf.mem); 45376881f68fSopenharmony_ci fuse_session_reset(se); 45386881f68fSopenharmony_ci return res < 0 ? -1 : 0; 45396881f68fSopenharmony_ci} 45406881f68fSopenharmony_ci 45416881f68fSopenharmony_ciint fuse_loop(struct fuse *f) 45426881f68fSopenharmony_ci{ 45436881f68fSopenharmony_ci if (!f) 45446881f68fSopenharmony_ci return -1; 45456881f68fSopenharmony_ci 45466881f68fSopenharmony_ci if (lru_enabled(f)) 45476881f68fSopenharmony_ci return fuse_session_loop_remember(f); 45486881f68fSopenharmony_ci 45496881f68fSopenharmony_ci return fuse_session_loop(f->se); 45506881f68fSopenharmony_ci} 45516881f68fSopenharmony_ci 45526881f68fSopenharmony_ciFUSE_SYMVER("fuse_loop_mt_312", "fuse_loop_mt@@FUSE_3.12") 45536881f68fSopenharmony_ciint fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config) 45546881f68fSopenharmony_ci{ 45556881f68fSopenharmony_ci if (f == NULL) 45566881f68fSopenharmony_ci return -1; 45576881f68fSopenharmony_ci 45586881f68fSopenharmony_ci int res = fuse_start_cleanup_thread(f); 45596881f68fSopenharmony_ci if (res) 45606881f68fSopenharmony_ci return -1; 45616881f68fSopenharmony_ci 45626881f68fSopenharmony_ci res = fuse_session_loop_mt_312(fuse_get_session(f), config); 45636881f68fSopenharmony_ci fuse_stop_cleanup_thread(f); 45646881f68fSopenharmony_ci return res; 45656881f68fSopenharmony_ci} 45666881f68fSopenharmony_ci 45676881f68fSopenharmony_ciint fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1); 45686881f68fSopenharmony_ciFUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@FUSE_3.2") 45696881f68fSopenharmony_ciint fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1) 45706881f68fSopenharmony_ci{ 45716881f68fSopenharmony_ci struct fuse_loop_config *config = fuse_loop_cfg_create(); 45726881f68fSopenharmony_ci if (config == NULL) 45736881f68fSopenharmony_ci return ENOMEM; 45746881f68fSopenharmony_ci 45756881f68fSopenharmony_ci fuse_loop_cfg_convert(config, config_v1); 45766881f68fSopenharmony_ci 45776881f68fSopenharmony_ci int res = fuse_loop_mt_312(f, config); 45786881f68fSopenharmony_ci 45796881f68fSopenharmony_ci fuse_loop_cfg_destroy(config); 45806881f68fSopenharmony_ci 45816881f68fSopenharmony_ci return res; 45826881f68fSopenharmony_ci} 45836881f68fSopenharmony_ci 45846881f68fSopenharmony_ciint fuse_loop_mt_31(struct fuse *f, int clone_fd); 45856881f68fSopenharmony_ciFUSE_SYMVER("fuse_loop_mt_31", "fuse_loop_mt@FUSE_3.0") 45866881f68fSopenharmony_ciint fuse_loop_mt_31(struct fuse *f, int clone_fd) 45876881f68fSopenharmony_ci{ 45886881f68fSopenharmony_ci int err; 45896881f68fSopenharmony_ci struct fuse_loop_config *config = fuse_loop_cfg_create(); 45906881f68fSopenharmony_ci 45916881f68fSopenharmony_ci if (config == NULL) 45926881f68fSopenharmony_ci return ENOMEM; 45936881f68fSopenharmony_ci 45946881f68fSopenharmony_ci fuse_loop_cfg_set_clone_fd(config, clone_fd); 45956881f68fSopenharmony_ci 45966881f68fSopenharmony_ci err = fuse_loop_mt_312(f, config); 45976881f68fSopenharmony_ci 45986881f68fSopenharmony_ci fuse_loop_cfg_destroy(config); 45996881f68fSopenharmony_ci 46006881f68fSopenharmony_ci return err; 46016881f68fSopenharmony_ci} 46026881f68fSopenharmony_ci 46036881f68fSopenharmony_civoid fuse_exit(struct fuse *f) 46046881f68fSopenharmony_ci{ 46056881f68fSopenharmony_ci fuse_session_exit(f->se); 46066881f68fSopenharmony_ci} 46076881f68fSopenharmony_ci 46086881f68fSopenharmony_cistruct fuse_context *fuse_get_context(void) 46096881f68fSopenharmony_ci{ 46106881f68fSopenharmony_ci struct fuse_context_i *c = fuse_get_context_internal(); 46116881f68fSopenharmony_ci 46126881f68fSopenharmony_ci if (c) 46136881f68fSopenharmony_ci return &c->ctx; 46146881f68fSopenharmony_ci else 46156881f68fSopenharmony_ci return NULL; 46166881f68fSopenharmony_ci} 46176881f68fSopenharmony_ci 46186881f68fSopenharmony_ciint fuse_getgroups(int size, gid_t list[]) 46196881f68fSopenharmony_ci{ 46206881f68fSopenharmony_ci struct fuse_context_i *c = fuse_get_context_internal(); 46216881f68fSopenharmony_ci if (!c) 46226881f68fSopenharmony_ci return -EINVAL; 46236881f68fSopenharmony_ci 46246881f68fSopenharmony_ci return fuse_req_getgroups(c->req, size, list); 46256881f68fSopenharmony_ci} 46266881f68fSopenharmony_ci 46276881f68fSopenharmony_ciint fuse_interrupted(void) 46286881f68fSopenharmony_ci{ 46296881f68fSopenharmony_ci struct fuse_context_i *c = fuse_get_context_internal(); 46306881f68fSopenharmony_ci 46316881f68fSopenharmony_ci if (c) 46326881f68fSopenharmony_ci return fuse_req_interrupted(c->req); 46336881f68fSopenharmony_ci else 46346881f68fSopenharmony_ci return 0; 46356881f68fSopenharmony_ci} 46366881f68fSopenharmony_ci 46376881f68fSopenharmony_ciint fuse_invalidate_path(struct fuse *f, const char *path) { 46386881f68fSopenharmony_ci fuse_ino_t ino; 46396881f68fSopenharmony_ci int err = lookup_path_in_cache(f, path, &ino); 46406881f68fSopenharmony_ci if (err) { 46416881f68fSopenharmony_ci return err; 46426881f68fSopenharmony_ci } 46436881f68fSopenharmony_ci 46446881f68fSopenharmony_ci return fuse_lowlevel_notify_inval_inode(f->se, ino, 0, 0); 46456881f68fSopenharmony_ci} 46466881f68fSopenharmony_ci 46476881f68fSopenharmony_ci#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } 46486881f68fSopenharmony_ci 46496881f68fSopenharmony_cistatic const struct fuse_opt fuse_lib_opts[] = { 46506881f68fSopenharmony_ci FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), 46516881f68fSopenharmony_ci FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), 46526881f68fSopenharmony_ci FUSE_LIB_OPT("debug", debug, 1), 46536881f68fSopenharmony_ci FUSE_LIB_OPT("-d", debug, 1), 46546881f68fSopenharmony_ci FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), 46556881f68fSopenharmony_ci FUSE_LIB_OPT("auto_cache", auto_cache, 1), 46566881f68fSopenharmony_ci FUSE_LIB_OPT("noauto_cache", auto_cache, 0), 46576881f68fSopenharmony_ci FUSE_LIB_OPT("no_rofd_flush", no_rofd_flush, 1), 46586881f68fSopenharmony_ci FUSE_LIB_OPT("umask=", set_mode, 1), 46596881f68fSopenharmony_ci FUSE_LIB_OPT("umask=%o", umask, 0), 46606881f68fSopenharmony_ci FUSE_LIB_OPT("uid=", set_uid, 1), 46616881f68fSopenharmony_ci FUSE_LIB_OPT("uid=%d", uid, 0), 46626881f68fSopenharmony_ci FUSE_LIB_OPT("gid=", set_gid, 1), 46636881f68fSopenharmony_ci FUSE_LIB_OPT("gid=%d", gid, 0), 46646881f68fSopenharmony_ci FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), 46656881f68fSopenharmony_ci FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), 46666881f68fSopenharmony_ci FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), 46676881f68fSopenharmony_ci FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), 46686881f68fSopenharmony_ci FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), 46696881f68fSopenharmony_ci FUSE_LIB_OPT("noforget", remember, -1), 46706881f68fSopenharmony_ci FUSE_LIB_OPT("remember=%u", remember, 0), 46716881f68fSopenharmony_ci FUSE_LIB_OPT("modules=%s", modules, 0), 46726881f68fSopenharmony_ci FUSE_LIB_OPT("parallel_direct_write=%d", parallel_direct_writes, 0), 46736881f68fSopenharmony_ci FUSE_OPT_END 46746881f68fSopenharmony_ci}; 46756881f68fSopenharmony_ci 46766881f68fSopenharmony_cistatic int fuse_lib_opt_proc(void *data, const char *arg, int key, 46776881f68fSopenharmony_ci struct fuse_args *outargs) 46786881f68fSopenharmony_ci{ 46796881f68fSopenharmony_ci (void) arg; (void) outargs; (void) data; (void) key; 46806881f68fSopenharmony_ci 46816881f68fSopenharmony_ci /* Pass through unknown options */ 46826881f68fSopenharmony_ci return 1; 46836881f68fSopenharmony_ci} 46846881f68fSopenharmony_ci 46856881f68fSopenharmony_ci 46866881f68fSopenharmony_cistatic const struct fuse_opt fuse_help_opts[] = { 46876881f68fSopenharmony_ci FUSE_LIB_OPT("modules=%s", modules, 1), 46886881f68fSopenharmony_ci FUSE_OPT_KEY("modules=%s", FUSE_OPT_KEY_KEEP), 46896881f68fSopenharmony_ci FUSE_OPT_END 46906881f68fSopenharmony_ci}; 46916881f68fSopenharmony_ci 46926881f68fSopenharmony_cistatic void print_module_help(const char *name, 46936881f68fSopenharmony_ci fuse_module_factory_t *fac) 46946881f68fSopenharmony_ci{ 46956881f68fSopenharmony_ci struct fuse_args a = FUSE_ARGS_INIT(0, NULL); 46966881f68fSopenharmony_ci if (fuse_opt_add_arg(&a, "") == -1 || 46976881f68fSopenharmony_ci fuse_opt_add_arg(&a, "-h") == -1) 46986881f68fSopenharmony_ci return; 46996881f68fSopenharmony_ci printf("\nOptions for %s module:\n", name); 47006881f68fSopenharmony_ci (*fac)(&a, NULL); 47016881f68fSopenharmony_ci fuse_opt_free_args(&a); 47026881f68fSopenharmony_ci} 47036881f68fSopenharmony_ci 47046881f68fSopenharmony_civoid fuse_lib_help(struct fuse_args *args) 47056881f68fSopenharmony_ci{ 47066881f68fSopenharmony_ci /* These are not all options, but only the ones that 47076881f68fSopenharmony_ci may be of interest to an end-user */ 47086881f68fSopenharmony_ci printf( 47096881f68fSopenharmony_ci" -o kernel_cache cache files in kernel\n" 47106881f68fSopenharmony_ci" -o [no]auto_cache enable caching based on modification times (off)\n" 47116881f68fSopenharmony_ci" -o no_rofd_flush disable flushing of read-only fd on close (off)\n" 47126881f68fSopenharmony_ci" -o umask=M set file permissions (octal)\n" 47136881f68fSopenharmony_ci" -o uid=N set file owner\n" 47146881f68fSopenharmony_ci" -o gid=N set file group\n" 47156881f68fSopenharmony_ci" -o entry_timeout=T cache timeout for names (1.0s)\n" 47166881f68fSopenharmony_ci" -o negative_timeout=T cache timeout for deleted names (0.0s)\n" 47176881f68fSopenharmony_ci" -o attr_timeout=T cache timeout for attributes (1.0s)\n" 47186881f68fSopenharmony_ci" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" 47196881f68fSopenharmony_ci" -o noforget never forget cached inodes\n" 47206881f68fSopenharmony_ci" -o remember=T remember cached inodes for T seconds (0s)\n" 47216881f68fSopenharmony_ci" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"); 47226881f68fSopenharmony_ci 47236881f68fSopenharmony_ci 47246881f68fSopenharmony_ci /* Print low-level help */ 47256881f68fSopenharmony_ci fuse_lowlevel_help(); 47266881f68fSopenharmony_ci 47276881f68fSopenharmony_ci /* Print help for builtin modules */ 47286881f68fSopenharmony_ci print_module_help("subdir", &fuse_module_subdir_factory); 47296881f68fSopenharmony_ci#ifdef HAVE_ICONV 47306881f68fSopenharmony_ci print_module_help("iconv", &fuse_module_iconv_factory); 47316881f68fSopenharmony_ci#endif 47326881f68fSopenharmony_ci 47336881f68fSopenharmony_ci /* Parse command line options in case we need to 47346881f68fSopenharmony_ci activate more modules */ 47356881f68fSopenharmony_ci struct fuse_config conf = { .modules = NULL }; 47366881f68fSopenharmony_ci if (fuse_opt_parse(args, &conf, fuse_help_opts, 47376881f68fSopenharmony_ci fuse_lib_opt_proc) == -1 47386881f68fSopenharmony_ci || !conf.modules) 47396881f68fSopenharmony_ci return; 47406881f68fSopenharmony_ci 47416881f68fSopenharmony_ci char *module; 47426881f68fSopenharmony_ci char *next; 47436881f68fSopenharmony_ci struct fuse_module *m; 47446881f68fSopenharmony_ci 47456881f68fSopenharmony_ci // Iterate over all modules 47466881f68fSopenharmony_ci for (module = conf.modules; module; module = next) { 47476881f68fSopenharmony_ci char *p; 47486881f68fSopenharmony_ci for (p = module; *p && *p != ':'; p++); 47496881f68fSopenharmony_ci next = *p ? p + 1 : NULL; 47506881f68fSopenharmony_ci *p = '\0'; 47516881f68fSopenharmony_ci 47526881f68fSopenharmony_ci m = fuse_get_module(module); 47536881f68fSopenharmony_ci if (m) 47546881f68fSopenharmony_ci print_module_help(module, &m->factory); 47556881f68fSopenharmony_ci } 47566881f68fSopenharmony_ci} 47576881f68fSopenharmony_ci 47586881f68fSopenharmony_ci 47596881f68fSopenharmony_ci 47606881f68fSopenharmony_cistatic int fuse_init_intr_signal(int signum, int *installed) 47616881f68fSopenharmony_ci{ 47626881f68fSopenharmony_ci struct sigaction old_sa; 47636881f68fSopenharmony_ci 47646881f68fSopenharmony_ci if (sigaction(signum, NULL, &old_sa) == -1) { 47656881f68fSopenharmony_ci perror("fuse: cannot get old signal handler"); 47666881f68fSopenharmony_ci return -1; 47676881f68fSopenharmony_ci } 47686881f68fSopenharmony_ci 47696881f68fSopenharmony_ci if (old_sa.sa_handler == SIG_DFL) { 47706881f68fSopenharmony_ci struct sigaction sa; 47716881f68fSopenharmony_ci 47726881f68fSopenharmony_ci memset(&sa, 0, sizeof(struct sigaction)); 47736881f68fSopenharmony_ci sa.sa_handler = fuse_intr_sighandler; 47746881f68fSopenharmony_ci sigemptyset(&sa.sa_mask); 47756881f68fSopenharmony_ci 47766881f68fSopenharmony_ci if (sigaction(signum, &sa, NULL) == -1) { 47776881f68fSopenharmony_ci perror("fuse: cannot set interrupt signal handler"); 47786881f68fSopenharmony_ci return -1; 47796881f68fSopenharmony_ci } 47806881f68fSopenharmony_ci *installed = 1; 47816881f68fSopenharmony_ci } 47826881f68fSopenharmony_ci return 0; 47836881f68fSopenharmony_ci} 47846881f68fSopenharmony_ci 47856881f68fSopenharmony_cistatic void fuse_restore_intr_signal(int signum) 47866881f68fSopenharmony_ci{ 47876881f68fSopenharmony_ci struct sigaction sa; 47886881f68fSopenharmony_ci 47896881f68fSopenharmony_ci memset(&sa, 0, sizeof(struct sigaction)); 47906881f68fSopenharmony_ci sa.sa_handler = SIG_DFL; 47916881f68fSopenharmony_ci sigaction(signum, &sa, NULL); 47926881f68fSopenharmony_ci} 47936881f68fSopenharmony_ci 47946881f68fSopenharmony_ci 47956881f68fSopenharmony_cistatic int fuse_push_module(struct fuse *f, const char *module, 47966881f68fSopenharmony_ci struct fuse_args *args) 47976881f68fSopenharmony_ci{ 47986881f68fSopenharmony_ci struct fuse_fs *fs[2] = { f->fs, NULL }; 47996881f68fSopenharmony_ci struct fuse_fs *newfs; 48006881f68fSopenharmony_ci struct fuse_module *m = fuse_get_module(module); 48016881f68fSopenharmony_ci 48026881f68fSopenharmony_ci if (!m) 48036881f68fSopenharmony_ci return -1; 48046881f68fSopenharmony_ci 48056881f68fSopenharmony_ci newfs = m->factory(args, fs); 48066881f68fSopenharmony_ci if (!newfs) { 48076881f68fSopenharmony_ci fuse_put_module(m); 48086881f68fSopenharmony_ci return -1; 48096881f68fSopenharmony_ci } 48106881f68fSopenharmony_ci f->fs = newfs; 48116881f68fSopenharmony_ci return 0; 48126881f68fSopenharmony_ci} 48136881f68fSopenharmony_ci 48146881f68fSopenharmony_cistruct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, 48156881f68fSopenharmony_ci void *user_data) 48166881f68fSopenharmony_ci{ 48176881f68fSopenharmony_ci struct fuse_fs *fs; 48186881f68fSopenharmony_ci 48196881f68fSopenharmony_ci if (sizeof(struct fuse_operations) < op_size) { 48206881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not not work\n"); 48216881f68fSopenharmony_ci op_size = sizeof(struct fuse_operations); 48226881f68fSopenharmony_ci } 48236881f68fSopenharmony_ci 48246881f68fSopenharmony_ci fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); 48256881f68fSopenharmony_ci if (!fs) { 48266881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse_fs object\n"); 48276881f68fSopenharmony_ci return NULL; 48286881f68fSopenharmony_ci } 48296881f68fSopenharmony_ci 48306881f68fSopenharmony_ci fs->user_data = user_data; 48316881f68fSopenharmony_ci if (op) 48326881f68fSopenharmony_ci memcpy(&fs->op, op, op_size); 48336881f68fSopenharmony_ci return fs; 48346881f68fSopenharmony_ci} 48356881f68fSopenharmony_ci 48366881f68fSopenharmony_cistatic int node_table_init(struct node_table *t) 48376881f68fSopenharmony_ci{ 48386881f68fSopenharmony_ci t->size = NODE_TABLE_MIN_SIZE; 48396881f68fSopenharmony_ci t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); 48406881f68fSopenharmony_ci if (t->array == NULL) { 48416881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); 48426881f68fSopenharmony_ci return -1; 48436881f68fSopenharmony_ci } 48446881f68fSopenharmony_ci t->use = 0; 48456881f68fSopenharmony_ci t->split = 0; 48466881f68fSopenharmony_ci 48476881f68fSopenharmony_ci return 0; 48486881f68fSopenharmony_ci} 48496881f68fSopenharmony_ci 48506881f68fSopenharmony_cistatic void *fuse_prune_nodes(void *fuse) 48516881f68fSopenharmony_ci{ 48526881f68fSopenharmony_ci struct fuse *f = fuse; 48536881f68fSopenharmony_ci int sleep_time; 48546881f68fSopenharmony_ci 48556881f68fSopenharmony_ci while(1) { 48566881f68fSopenharmony_ci sleep_time = fuse_clean_cache(f); 48576881f68fSopenharmony_ci sleep(sleep_time); 48586881f68fSopenharmony_ci } 48596881f68fSopenharmony_ci return NULL; 48606881f68fSopenharmony_ci} 48616881f68fSopenharmony_ci 48626881f68fSopenharmony_ciint fuse_start_cleanup_thread(struct fuse *f) 48636881f68fSopenharmony_ci{ 48646881f68fSopenharmony_ci if (lru_enabled(f)) 48656881f68fSopenharmony_ci return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); 48666881f68fSopenharmony_ci 48676881f68fSopenharmony_ci return 0; 48686881f68fSopenharmony_ci} 48696881f68fSopenharmony_ci 48706881f68fSopenharmony_civoid fuse_stop_cleanup_thread(struct fuse *f) 48716881f68fSopenharmony_ci{ 48726881f68fSopenharmony_ci if (lru_enabled(f)) { 48736881f68fSopenharmony_ci pthread_mutex_lock(&f->lock); 48746881f68fSopenharmony_ci pthread_cancel(f->prune_thread); 48756881f68fSopenharmony_ci pthread_mutex_unlock(&f->lock); 48766881f68fSopenharmony_ci pthread_join(f->prune_thread, NULL); 48776881f68fSopenharmony_ci } 48786881f68fSopenharmony_ci} 48796881f68fSopenharmony_ci 48806881f68fSopenharmony_ci 48816881f68fSopenharmony_ciFUSE_SYMVER("fuse_new_31", "fuse_new@@FUSE_3.1") 48826881f68fSopenharmony_cistruct fuse *fuse_new_31(struct fuse_args *args, 48836881f68fSopenharmony_ci const struct fuse_operations *op, 48846881f68fSopenharmony_ci size_t op_size, void *user_data) 48856881f68fSopenharmony_ci{ 48866881f68fSopenharmony_ci struct fuse *f; 48876881f68fSopenharmony_ci struct node *root; 48886881f68fSopenharmony_ci struct fuse_fs *fs; 48896881f68fSopenharmony_ci struct fuse_lowlevel_ops llop = fuse_path_ops; 48906881f68fSopenharmony_ci 48916881f68fSopenharmony_ci f = (struct fuse *) calloc(1, sizeof(struct fuse)); 48926881f68fSopenharmony_ci if (f == NULL) { 48936881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n"); 48946881f68fSopenharmony_ci goto out; 48956881f68fSopenharmony_ci } 48966881f68fSopenharmony_ci 48976881f68fSopenharmony_ci f->conf.entry_timeout = 1.0; 48986881f68fSopenharmony_ci f->conf.attr_timeout = 1.0; 48996881f68fSopenharmony_ci f->conf.negative_timeout = 0.0; 49006881f68fSopenharmony_ci f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; 49016881f68fSopenharmony_ci 49026881f68fSopenharmony_ci /* Parse options */ 49036881f68fSopenharmony_ci if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, 49046881f68fSopenharmony_ci fuse_lib_opt_proc) == -1) 49056881f68fSopenharmony_ci goto out_free; 49066881f68fSopenharmony_ci 49076881f68fSopenharmony_ci pthread_mutex_lock(&fuse_context_lock); 49086881f68fSopenharmony_ci static int builtin_modules_registered = 0; 49096881f68fSopenharmony_ci /* Have the builtin modules already been registered? */ 49106881f68fSopenharmony_ci if (builtin_modules_registered == 0) { 49116881f68fSopenharmony_ci /* If not, register them. */ 49126881f68fSopenharmony_ci fuse_register_module("subdir", fuse_module_subdir_factory, NULL); 49136881f68fSopenharmony_ci#ifdef HAVE_ICONV 49146881f68fSopenharmony_ci fuse_register_module("iconv", fuse_module_iconv_factory, NULL); 49156881f68fSopenharmony_ci#endif 49166881f68fSopenharmony_ci builtin_modules_registered= 1; 49176881f68fSopenharmony_ci } 49186881f68fSopenharmony_ci pthread_mutex_unlock(&fuse_context_lock); 49196881f68fSopenharmony_ci 49206881f68fSopenharmony_ci if (fuse_create_context_key() == -1) 49216881f68fSopenharmony_ci goto out_free; 49226881f68fSopenharmony_ci 49236881f68fSopenharmony_ci fs = fuse_fs_new(op, op_size, user_data); 49246881f68fSopenharmony_ci if (!fs) 49256881f68fSopenharmony_ci goto out_delete_context_key; 49266881f68fSopenharmony_ci 49276881f68fSopenharmony_ci f->fs = fs; 49286881f68fSopenharmony_ci 49296881f68fSopenharmony_ci /* Oh f**k, this is ugly! */ 49306881f68fSopenharmony_ci if (!fs->op.lock) { 49316881f68fSopenharmony_ci llop.getlk = NULL; 49326881f68fSopenharmony_ci llop.setlk = NULL; 49336881f68fSopenharmony_ci } 49346881f68fSopenharmony_ci 49356881f68fSopenharmony_ci f->pagesize = getpagesize(); 49366881f68fSopenharmony_ci init_list_head(&f->partial_slabs); 49376881f68fSopenharmony_ci init_list_head(&f->full_slabs); 49386881f68fSopenharmony_ci init_list_head(&f->lru_table); 49396881f68fSopenharmony_ci 49406881f68fSopenharmony_ci if (f->conf.modules) { 49416881f68fSopenharmony_ci char *module; 49426881f68fSopenharmony_ci char *next; 49436881f68fSopenharmony_ci 49446881f68fSopenharmony_ci for (module = f->conf.modules; module; module = next) { 49456881f68fSopenharmony_ci char *p; 49466881f68fSopenharmony_ci for (p = module; *p && *p != ':'; p++); 49476881f68fSopenharmony_ci next = *p ? p + 1 : NULL; 49486881f68fSopenharmony_ci *p = '\0'; 49496881f68fSopenharmony_ci if (module[0] && 49506881f68fSopenharmony_ci fuse_push_module(f, module, args) == -1) 49516881f68fSopenharmony_ci goto out_free_fs; 49526881f68fSopenharmony_ci } 49536881f68fSopenharmony_ci } 49546881f68fSopenharmony_ci 49556881f68fSopenharmony_ci if (!f->conf.ac_attr_timeout_set) 49566881f68fSopenharmony_ci f->conf.ac_attr_timeout = f->conf.attr_timeout; 49576881f68fSopenharmony_ci 49586881f68fSopenharmony_ci#if defined(__FreeBSD__) || defined(__NetBSD__) 49596881f68fSopenharmony_ci /* 49606881f68fSopenharmony_ci * In FreeBSD, we always use these settings as inode numbers 49616881f68fSopenharmony_ci * are needed to make getcwd(3) work. 49626881f68fSopenharmony_ci */ 49636881f68fSopenharmony_ci f->conf.readdir_ino = 1; 49646881f68fSopenharmony_ci#endif 49656881f68fSopenharmony_ci 49666881f68fSopenharmony_ci f->se = fuse_session_new(args, &llop, sizeof(llop), f); 49676881f68fSopenharmony_ci if (f->se == NULL) 49686881f68fSopenharmony_ci goto out_free_fs; 49696881f68fSopenharmony_ci 49706881f68fSopenharmony_ci if (f->conf.debug) { 49716881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "nullpath_ok: %i\n", f->conf.nullpath_ok); 49726881f68fSopenharmony_ci } 49736881f68fSopenharmony_ci 49746881f68fSopenharmony_ci /* Trace topmost layer by default */ 49756881f68fSopenharmony_ci f->fs->debug = f->conf.debug; 49766881f68fSopenharmony_ci f->ctr = 0; 49776881f68fSopenharmony_ci f->generation = 0; 49786881f68fSopenharmony_ci if (node_table_init(&f->name_table) == -1) 49796881f68fSopenharmony_ci goto out_free_session; 49806881f68fSopenharmony_ci 49816881f68fSopenharmony_ci if (node_table_init(&f->id_table) == -1) 49826881f68fSopenharmony_ci goto out_free_name_table; 49836881f68fSopenharmony_ci 49846881f68fSopenharmony_ci pthread_mutex_init(&f->lock, NULL); 49856881f68fSopenharmony_ci 49866881f68fSopenharmony_ci root = alloc_node(f); 49876881f68fSopenharmony_ci if (root == NULL) { 49886881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); 49896881f68fSopenharmony_ci goto out_free_id_table; 49906881f68fSopenharmony_ci } 49916881f68fSopenharmony_ci if (lru_enabled(f)) { 49926881f68fSopenharmony_ci struct node_lru *lnode = node_lru(root); 49936881f68fSopenharmony_ci init_list_head(&lnode->lru); 49946881f68fSopenharmony_ci } 49956881f68fSopenharmony_ci 49966881f68fSopenharmony_ci strcpy(root->inline_name, "/"); 49976881f68fSopenharmony_ci root->name = root->inline_name; 49986881f68fSopenharmony_ci 49996881f68fSopenharmony_ci if (f->conf.intr && 50006881f68fSopenharmony_ci fuse_init_intr_signal(f->conf.intr_signal, 50016881f68fSopenharmony_ci &f->intr_installed) == -1) 50026881f68fSopenharmony_ci goto out_free_root; 50036881f68fSopenharmony_ci 50046881f68fSopenharmony_ci root->parent = NULL; 50056881f68fSopenharmony_ci root->nodeid = FUSE_ROOT_ID; 50066881f68fSopenharmony_ci inc_nlookup(root); 50076881f68fSopenharmony_ci hash_id(f, root); 50086881f68fSopenharmony_ci 50096881f68fSopenharmony_ci return f; 50106881f68fSopenharmony_ci 50116881f68fSopenharmony_ciout_free_root: 50126881f68fSopenharmony_ci free(root); 50136881f68fSopenharmony_ciout_free_id_table: 50146881f68fSopenharmony_ci free(f->id_table.array); 50156881f68fSopenharmony_ciout_free_name_table: 50166881f68fSopenharmony_ci free(f->name_table.array); 50176881f68fSopenharmony_ciout_free_session: 50186881f68fSopenharmony_ci fuse_session_destroy(f->se); 50196881f68fSopenharmony_ciout_free_fs: 50206881f68fSopenharmony_ci free(f->fs); 50216881f68fSopenharmony_ci free(f->conf.modules); 50226881f68fSopenharmony_ciout_delete_context_key: 50236881f68fSopenharmony_ci fuse_delete_context_key(); 50246881f68fSopenharmony_ciout_free: 50256881f68fSopenharmony_ci free(f); 50266881f68fSopenharmony_ciout: 50276881f68fSopenharmony_ci return NULL; 50286881f68fSopenharmony_ci} 50296881f68fSopenharmony_ci 50306881f68fSopenharmony_ci/* Emulates 3.0-style fuse_new(), which processes --help */ 50316881f68fSopenharmony_cistruct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op, 50326881f68fSopenharmony_ci size_t op_size, void *private_data); 50336881f68fSopenharmony_ciFUSE_SYMVER("fuse_new_30", "fuse_new@FUSE_3.0") 50346881f68fSopenharmony_cistruct fuse *fuse_new_30(struct fuse_args *args, 50356881f68fSopenharmony_ci const struct fuse_operations *op, 50366881f68fSopenharmony_ci size_t op_size, void *user_data) 50376881f68fSopenharmony_ci{ 50386881f68fSopenharmony_ci struct fuse_config conf; 50396881f68fSopenharmony_ci 50406881f68fSopenharmony_ci memset(&conf, 0, sizeof(conf)); 50416881f68fSopenharmony_ci 50426881f68fSopenharmony_ci const struct fuse_opt opts[] = { 50436881f68fSopenharmony_ci FUSE_LIB_OPT("-h", show_help, 1), 50446881f68fSopenharmony_ci FUSE_LIB_OPT("--help", show_help, 1), 50456881f68fSopenharmony_ci FUSE_OPT_END 50466881f68fSopenharmony_ci }; 50476881f68fSopenharmony_ci 50486881f68fSopenharmony_ci if (fuse_opt_parse(args, &conf, opts, 50496881f68fSopenharmony_ci fuse_lib_opt_proc) == -1) 50506881f68fSopenharmony_ci return NULL; 50516881f68fSopenharmony_ci 50526881f68fSopenharmony_ci if (conf.show_help) { 50536881f68fSopenharmony_ci fuse_lib_help(args); 50546881f68fSopenharmony_ci return NULL; 50556881f68fSopenharmony_ci } else 50566881f68fSopenharmony_ci return fuse_new_31(args, op, op_size, user_data); 50576881f68fSopenharmony_ci} 50586881f68fSopenharmony_ci 50596881f68fSopenharmony_civoid fuse_destroy(struct fuse *f) 50606881f68fSopenharmony_ci{ 50616881f68fSopenharmony_ci size_t i; 50626881f68fSopenharmony_ci 50636881f68fSopenharmony_ci if (f->conf.intr && f->intr_installed) 50646881f68fSopenharmony_ci fuse_restore_intr_signal(f->conf.intr_signal); 50656881f68fSopenharmony_ci 50666881f68fSopenharmony_ci if (f->fs) { 50676881f68fSopenharmony_ci fuse_create_context(f); 50686881f68fSopenharmony_ci 50696881f68fSopenharmony_ci for (i = 0; i < f->id_table.size; i++) { 50706881f68fSopenharmony_ci struct node *node; 50716881f68fSopenharmony_ci 50726881f68fSopenharmony_ci for (node = f->id_table.array[i]; node != NULL; 50736881f68fSopenharmony_ci node = node->id_next) { 50746881f68fSopenharmony_ci if (node->is_hidden) { 50756881f68fSopenharmony_ci char *path; 50766881f68fSopenharmony_ci if (try_get_path(f, node->nodeid, NULL, &path, NULL, false) == 0) { 50776881f68fSopenharmony_ci fuse_fs_unlink(f->fs, path); 50786881f68fSopenharmony_ci free(path); 50796881f68fSopenharmony_ci } 50806881f68fSopenharmony_ci } 50816881f68fSopenharmony_ci } 50826881f68fSopenharmony_ci } 50836881f68fSopenharmony_ci } 50846881f68fSopenharmony_ci for (i = 0; i < f->id_table.size; i++) { 50856881f68fSopenharmony_ci struct node *node; 50866881f68fSopenharmony_ci struct node *next; 50876881f68fSopenharmony_ci 50886881f68fSopenharmony_ci for (node = f->id_table.array[i]; node != NULL; node = next) { 50896881f68fSopenharmony_ci next = node->id_next; 50906881f68fSopenharmony_ci free_node(f, node); 50916881f68fSopenharmony_ci f->id_table.use--; 50926881f68fSopenharmony_ci } 50936881f68fSopenharmony_ci } 50946881f68fSopenharmony_ci assert(list_empty(&f->partial_slabs)); 50956881f68fSopenharmony_ci assert(list_empty(&f->full_slabs)); 50966881f68fSopenharmony_ci 50976881f68fSopenharmony_ci while (fuse_modules) { 50986881f68fSopenharmony_ci fuse_put_module(fuse_modules); 50996881f68fSopenharmony_ci } 51006881f68fSopenharmony_ci free(f->id_table.array); 51016881f68fSopenharmony_ci free(f->name_table.array); 51026881f68fSopenharmony_ci pthread_mutex_destroy(&f->lock); 51036881f68fSopenharmony_ci fuse_session_destroy(f->se); 51046881f68fSopenharmony_ci free(f->fs); 51056881f68fSopenharmony_ci free(f->conf.modules); 51066881f68fSopenharmony_ci free(f); 51076881f68fSopenharmony_ci fuse_delete_context_key(); 51086881f68fSopenharmony_ci} 51096881f68fSopenharmony_ci 51106881f68fSopenharmony_ciint fuse_mount(struct fuse *f, const char *mountpoint) { 51116881f68fSopenharmony_ci return fuse_session_mount(fuse_get_session(f), mountpoint); 51126881f68fSopenharmony_ci} 51136881f68fSopenharmony_ci 51146881f68fSopenharmony_ci 51156881f68fSopenharmony_civoid fuse_unmount(struct fuse *f) { 51166881f68fSopenharmony_ci fuse_session_unmount(fuse_get_session(f)); 51176881f68fSopenharmony_ci} 51186881f68fSopenharmony_ci 51196881f68fSopenharmony_ciint fuse_version(void) 51206881f68fSopenharmony_ci{ 51216881f68fSopenharmony_ci return FUSE_VERSION; 51226881f68fSopenharmony_ci} 51236881f68fSopenharmony_ci 51246881f68fSopenharmony_ciconst char *fuse_pkgversion(void) 51256881f68fSopenharmony_ci{ 51266881f68fSopenharmony_ci return PACKAGE_VERSION; 51276881f68fSopenharmony_ci} 5128