16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci This program can be distributed under the terms of the GNU GPLv2. 66881f68fSopenharmony_ci See the file COPYING. 76881f68fSopenharmony_ci*/ 86881f68fSopenharmony_ci 96881f68fSopenharmony_ci/** @file 106881f68fSopenharmony_ci * 116881f68fSopenharmony_ci * This file system mirrors the existing file system hierarchy of the 126881f68fSopenharmony_ci * system, starting at the root file system. This is implemented by 136881f68fSopenharmony_ci * just "passing through" all requests to the corresponding user-space 146881f68fSopenharmony_ci * libc functions. In contrast to passthrough.c and passthrough_fh.c, 156881f68fSopenharmony_ci * this implementation uses the low-level API. Its performance should 166881f68fSopenharmony_ci * be the least bad among the three, but many operations are not 176881f68fSopenharmony_ci * implemented. In particular, it is not possible to remove files (or 186881f68fSopenharmony_ci * directories) because the code necessary to defer actual removal 196881f68fSopenharmony_ci * until the file is not opened anymore would make the example much 206881f68fSopenharmony_ci * more complicated. 216881f68fSopenharmony_ci * 226881f68fSopenharmony_ci * When writeback caching is enabled (-o writeback mount option), it 236881f68fSopenharmony_ci * is only possible to write to files for which the mounting user has 246881f68fSopenharmony_ci * read permissions. This is because the writeback cache requires the 256881f68fSopenharmony_ci * kernel to be able to issue read requests for all files (which the 266881f68fSopenharmony_ci * passthrough filesystem cannot satisfy if it can't read the file in 276881f68fSopenharmony_ci * the underlying filesystem). 286881f68fSopenharmony_ci * 296881f68fSopenharmony_ci * Compile with: 306881f68fSopenharmony_ci * 316881f68fSopenharmony_ci * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll 326881f68fSopenharmony_ci * 336881f68fSopenharmony_ci * ## Source code ## 346881f68fSopenharmony_ci * \include passthrough_ll.c 356881f68fSopenharmony_ci */ 366881f68fSopenharmony_ci 376881f68fSopenharmony_ci#define _GNU_SOURCE 386881f68fSopenharmony_ci#define FUSE_USE_VERSION 34 396881f68fSopenharmony_ci 406881f68fSopenharmony_ci#include <fuse_lowlevel.h> 416881f68fSopenharmony_ci#include <unistd.h> 426881f68fSopenharmony_ci#include <stdlib.h> 436881f68fSopenharmony_ci#include <stdio.h> 446881f68fSopenharmony_ci#include <stddef.h> 456881f68fSopenharmony_ci#include <stdbool.h> 466881f68fSopenharmony_ci#include <string.h> 476881f68fSopenharmony_ci#include <limits.h> 486881f68fSopenharmony_ci#include <dirent.h> 496881f68fSopenharmony_ci#include <assert.h> 506881f68fSopenharmony_ci#include <errno.h> 516881f68fSopenharmony_ci#include <inttypes.h> 526881f68fSopenharmony_ci#include <pthread.h> 536881f68fSopenharmony_ci#include <sys/file.h> 546881f68fSopenharmony_ci#include <sys/xattr.h> 556881f68fSopenharmony_ci 566881f68fSopenharmony_ci#include "passthrough_helpers.h" 576881f68fSopenharmony_ci 586881f68fSopenharmony_ci/* We are re-using pointers to our `struct lo_inode` and `struct 596881f68fSopenharmony_ci lo_dirp` elements as inodes. This means that we must be able to 606881f68fSopenharmony_ci store uintptr_t values in a fuse_ino_t variable. The following 616881f68fSopenharmony_ci incantation checks this condition at compile time. */ 626881f68fSopenharmony_ci#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus 636881f68fSopenharmony_ci_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t), 646881f68fSopenharmony_ci "fuse_ino_t too small to hold uintptr_t values!"); 656881f68fSopenharmony_ci#else 666881f68fSopenharmony_cistruct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \ 676881f68fSopenharmony_ci { unsigned _uintptr_to_must_hold_fuse_ino_t: 686881f68fSopenharmony_ci ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); }; 696881f68fSopenharmony_ci#endif 706881f68fSopenharmony_ci 716881f68fSopenharmony_cistruct lo_inode { 726881f68fSopenharmony_ci struct lo_inode *next; /* protected by lo->mutex */ 736881f68fSopenharmony_ci struct lo_inode *prev; /* protected by lo->mutex */ 746881f68fSopenharmony_ci int fd; 756881f68fSopenharmony_ci ino_t ino; 766881f68fSopenharmony_ci dev_t dev; 776881f68fSopenharmony_ci uint64_t refcount; /* protected by lo->mutex */ 786881f68fSopenharmony_ci}; 796881f68fSopenharmony_ci 806881f68fSopenharmony_cienum { 816881f68fSopenharmony_ci CACHE_NEVER, 826881f68fSopenharmony_ci CACHE_NORMAL, 836881f68fSopenharmony_ci CACHE_ALWAYS, 846881f68fSopenharmony_ci}; 856881f68fSopenharmony_ci 866881f68fSopenharmony_cistruct lo_data { 876881f68fSopenharmony_ci pthread_mutex_t mutex; 886881f68fSopenharmony_ci int debug; 896881f68fSopenharmony_ci int writeback; 906881f68fSopenharmony_ci int flock; 916881f68fSopenharmony_ci int xattr; 926881f68fSopenharmony_ci char *source; 936881f68fSopenharmony_ci double timeout; 946881f68fSopenharmony_ci int cache; 956881f68fSopenharmony_ci int timeout_set; 966881f68fSopenharmony_ci struct lo_inode root; /* protected by lo->mutex */ 976881f68fSopenharmony_ci}; 986881f68fSopenharmony_ci 996881f68fSopenharmony_cistatic const struct fuse_opt lo_opts[] = { 1006881f68fSopenharmony_ci { "writeback", 1016881f68fSopenharmony_ci offsetof(struct lo_data, writeback), 1 }, 1026881f68fSopenharmony_ci { "no_writeback", 1036881f68fSopenharmony_ci offsetof(struct lo_data, writeback), 0 }, 1046881f68fSopenharmony_ci { "source=%s", 1056881f68fSopenharmony_ci offsetof(struct lo_data, source), 0 }, 1066881f68fSopenharmony_ci { "flock", 1076881f68fSopenharmony_ci offsetof(struct lo_data, flock), 1 }, 1086881f68fSopenharmony_ci { "no_flock", 1096881f68fSopenharmony_ci offsetof(struct lo_data, flock), 0 }, 1106881f68fSopenharmony_ci { "xattr", 1116881f68fSopenharmony_ci offsetof(struct lo_data, xattr), 1 }, 1126881f68fSopenharmony_ci { "no_xattr", 1136881f68fSopenharmony_ci offsetof(struct lo_data, xattr), 0 }, 1146881f68fSopenharmony_ci { "timeout=%lf", 1156881f68fSopenharmony_ci offsetof(struct lo_data, timeout), 0 }, 1166881f68fSopenharmony_ci { "timeout=", 1176881f68fSopenharmony_ci offsetof(struct lo_data, timeout_set), 1 }, 1186881f68fSopenharmony_ci { "cache=never", 1196881f68fSopenharmony_ci offsetof(struct lo_data, cache), CACHE_NEVER }, 1206881f68fSopenharmony_ci { "cache=auto", 1216881f68fSopenharmony_ci offsetof(struct lo_data, cache), CACHE_NORMAL }, 1226881f68fSopenharmony_ci { "cache=always", 1236881f68fSopenharmony_ci offsetof(struct lo_data, cache), CACHE_ALWAYS }, 1246881f68fSopenharmony_ci 1256881f68fSopenharmony_ci FUSE_OPT_END 1266881f68fSopenharmony_ci}; 1276881f68fSopenharmony_ci 1286881f68fSopenharmony_cistatic void passthrough_ll_help(void) 1296881f68fSopenharmony_ci{ 1306881f68fSopenharmony_ci printf( 1316881f68fSopenharmony_ci" -o writeback Enable writeback\n" 1326881f68fSopenharmony_ci" -o no_writeback Disable write back\n" 1336881f68fSopenharmony_ci" -o source=/home/dir Source directory to be mounted\n" 1346881f68fSopenharmony_ci" -o flock Enable flock\n" 1356881f68fSopenharmony_ci" -o no_flock Disable flock\n" 1366881f68fSopenharmony_ci" -o xattr Enable xattr\n" 1376881f68fSopenharmony_ci" -o no_xattr Disable xattr\n" 1386881f68fSopenharmony_ci" -o timeout=1.0 Caching timeout\n" 1396881f68fSopenharmony_ci" -o timeout=0/1 Timeout is set\n" 1406881f68fSopenharmony_ci" -o cache=never Disable cache\n" 1416881f68fSopenharmony_ci" -o cache=auto Auto enable cache\n" 1426881f68fSopenharmony_ci" -o cache=always Cache always\n"); 1436881f68fSopenharmony_ci} 1446881f68fSopenharmony_ci 1456881f68fSopenharmony_cistatic struct lo_data *lo_data(fuse_req_t req) 1466881f68fSopenharmony_ci{ 1476881f68fSopenharmony_ci return (struct lo_data *) fuse_req_userdata(req); 1486881f68fSopenharmony_ci} 1496881f68fSopenharmony_ci 1506881f68fSopenharmony_cistatic struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino) 1516881f68fSopenharmony_ci{ 1526881f68fSopenharmony_ci if (ino == FUSE_ROOT_ID) 1536881f68fSopenharmony_ci return &lo_data(req)->root; 1546881f68fSopenharmony_ci else 1556881f68fSopenharmony_ci return (struct lo_inode *) (uintptr_t) ino; 1566881f68fSopenharmony_ci} 1576881f68fSopenharmony_ci 1586881f68fSopenharmony_cistatic int lo_fd(fuse_req_t req, fuse_ino_t ino) 1596881f68fSopenharmony_ci{ 1606881f68fSopenharmony_ci return lo_inode(req, ino)->fd; 1616881f68fSopenharmony_ci} 1626881f68fSopenharmony_ci 1636881f68fSopenharmony_cistatic bool lo_debug(fuse_req_t req) 1646881f68fSopenharmony_ci{ 1656881f68fSopenharmony_ci return lo_data(req)->debug != 0; 1666881f68fSopenharmony_ci} 1676881f68fSopenharmony_ci 1686881f68fSopenharmony_cistatic void lo_init(void *userdata, 1696881f68fSopenharmony_ci struct fuse_conn_info *conn) 1706881f68fSopenharmony_ci{ 1716881f68fSopenharmony_ci struct lo_data *lo = (struct lo_data*) userdata; 1726881f68fSopenharmony_ci 1736881f68fSopenharmony_ci if(conn->capable & FUSE_CAP_EXPORT_SUPPORT) 1746881f68fSopenharmony_ci conn->want |= FUSE_CAP_EXPORT_SUPPORT; 1756881f68fSopenharmony_ci 1766881f68fSopenharmony_ci if (lo->writeback && 1776881f68fSopenharmony_ci conn->capable & FUSE_CAP_WRITEBACK_CACHE) { 1786881f68fSopenharmony_ci if (lo->debug) 1796881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n"); 1806881f68fSopenharmony_ci conn->want |= FUSE_CAP_WRITEBACK_CACHE; 1816881f68fSopenharmony_ci } 1826881f68fSopenharmony_ci if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) { 1836881f68fSopenharmony_ci if (lo->debug) 1846881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n"); 1856881f68fSopenharmony_ci conn->want |= FUSE_CAP_FLOCK_LOCKS; 1866881f68fSopenharmony_ci } 1876881f68fSopenharmony_ci} 1886881f68fSopenharmony_ci 1896881f68fSopenharmony_cistatic void lo_destroy(void *userdata) 1906881f68fSopenharmony_ci{ 1916881f68fSopenharmony_ci struct lo_data *lo = (struct lo_data*) userdata; 1926881f68fSopenharmony_ci 1936881f68fSopenharmony_ci while (lo->root.next != &lo->root) { 1946881f68fSopenharmony_ci struct lo_inode* next = lo->root.next; 1956881f68fSopenharmony_ci lo->root.next = next->next; 1966881f68fSopenharmony_ci free(next); 1976881f68fSopenharmony_ci } 1986881f68fSopenharmony_ci} 1996881f68fSopenharmony_ci 2006881f68fSopenharmony_cistatic void lo_getattr(fuse_req_t req, fuse_ino_t ino, 2016881f68fSopenharmony_ci struct fuse_file_info *fi) 2026881f68fSopenharmony_ci{ 2036881f68fSopenharmony_ci int res; 2046881f68fSopenharmony_ci struct stat buf; 2056881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 2066881f68fSopenharmony_ci 2076881f68fSopenharmony_ci (void) fi; 2086881f68fSopenharmony_ci 2096881f68fSopenharmony_ci res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 2106881f68fSopenharmony_ci if (res == -1) 2116881f68fSopenharmony_ci return (void) fuse_reply_err(req, errno); 2126881f68fSopenharmony_ci 2136881f68fSopenharmony_ci fuse_reply_attr(req, &buf, lo->timeout); 2146881f68fSopenharmony_ci} 2156881f68fSopenharmony_ci 2166881f68fSopenharmony_cistatic void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, 2176881f68fSopenharmony_ci int valid, struct fuse_file_info *fi) 2186881f68fSopenharmony_ci{ 2196881f68fSopenharmony_ci int saverr; 2206881f68fSopenharmony_ci char procname[64]; 2216881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 2226881f68fSopenharmony_ci int ifd = inode->fd; 2236881f68fSopenharmony_ci int res; 2246881f68fSopenharmony_ci 2256881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_MODE) { 2266881f68fSopenharmony_ci if (fi) { 2276881f68fSopenharmony_ci res = fchmod(fi->fh, attr->st_mode); 2286881f68fSopenharmony_ci } else { 2296881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", ifd); 2306881f68fSopenharmony_ci res = chmod(procname, attr->st_mode); 2316881f68fSopenharmony_ci } 2326881f68fSopenharmony_ci if (res == -1) 2336881f68fSopenharmony_ci goto out_err; 2346881f68fSopenharmony_ci } 2356881f68fSopenharmony_ci if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) { 2366881f68fSopenharmony_ci uid_t uid = (valid & FUSE_SET_ATTR_UID) ? 2376881f68fSopenharmony_ci attr->st_uid : (uid_t) -1; 2386881f68fSopenharmony_ci gid_t gid = (valid & FUSE_SET_ATTR_GID) ? 2396881f68fSopenharmony_ci attr->st_gid : (gid_t) -1; 2406881f68fSopenharmony_ci 2416881f68fSopenharmony_ci res = fchownat(ifd, "", uid, gid, 2426881f68fSopenharmony_ci AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 2436881f68fSopenharmony_ci if (res == -1) 2446881f68fSopenharmony_ci goto out_err; 2456881f68fSopenharmony_ci } 2466881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_SIZE) { 2476881f68fSopenharmony_ci if (fi) { 2486881f68fSopenharmony_ci res = ftruncate(fi->fh, attr->st_size); 2496881f68fSopenharmony_ci } else { 2506881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", ifd); 2516881f68fSopenharmony_ci res = truncate(procname, attr->st_size); 2526881f68fSopenharmony_ci } 2536881f68fSopenharmony_ci if (res == -1) 2546881f68fSopenharmony_ci goto out_err; 2556881f68fSopenharmony_ci } 2566881f68fSopenharmony_ci if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { 2576881f68fSopenharmony_ci struct timespec tv[2]; 2586881f68fSopenharmony_ci 2596881f68fSopenharmony_ci tv[0].tv_sec = 0; 2606881f68fSopenharmony_ci tv[1].tv_sec = 0; 2616881f68fSopenharmony_ci tv[0].tv_nsec = UTIME_OMIT; 2626881f68fSopenharmony_ci tv[1].tv_nsec = UTIME_OMIT; 2636881f68fSopenharmony_ci 2646881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_ATIME_NOW) 2656881f68fSopenharmony_ci tv[0].tv_nsec = UTIME_NOW; 2666881f68fSopenharmony_ci else if (valid & FUSE_SET_ATTR_ATIME) 2676881f68fSopenharmony_ci tv[0] = attr->st_atim; 2686881f68fSopenharmony_ci 2696881f68fSopenharmony_ci if (valid & FUSE_SET_ATTR_MTIME_NOW) 2706881f68fSopenharmony_ci tv[1].tv_nsec = UTIME_NOW; 2716881f68fSopenharmony_ci else if (valid & FUSE_SET_ATTR_MTIME) 2726881f68fSopenharmony_ci tv[1] = attr->st_mtim; 2736881f68fSopenharmony_ci 2746881f68fSopenharmony_ci if (fi) 2756881f68fSopenharmony_ci res = futimens(fi->fh, tv); 2766881f68fSopenharmony_ci else { 2776881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", ifd); 2786881f68fSopenharmony_ci res = utimensat(AT_FDCWD, procname, tv, 0); 2796881f68fSopenharmony_ci } 2806881f68fSopenharmony_ci if (res == -1) 2816881f68fSopenharmony_ci goto out_err; 2826881f68fSopenharmony_ci } 2836881f68fSopenharmony_ci 2846881f68fSopenharmony_ci return lo_getattr(req, ino, fi); 2856881f68fSopenharmony_ci 2866881f68fSopenharmony_ciout_err: 2876881f68fSopenharmony_ci saverr = errno; 2886881f68fSopenharmony_ci fuse_reply_err(req, saverr); 2896881f68fSopenharmony_ci} 2906881f68fSopenharmony_ci 2916881f68fSopenharmony_cistatic struct lo_inode *lo_find(struct lo_data *lo, struct stat *st) 2926881f68fSopenharmony_ci{ 2936881f68fSopenharmony_ci struct lo_inode *p; 2946881f68fSopenharmony_ci struct lo_inode *ret = NULL; 2956881f68fSopenharmony_ci 2966881f68fSopenharmony_ci pthread_mutex_lock(&lo->mutex); 2976881f68fSopenharmony_ci for (p = lo->root.next; p != &lo->root; p = p->next) { 2986881f68fSopenharmony_ci if (p->ino == st->st_ino && p->dev == st->st_dev) { 2996881f68fSopenharmony_ci assert(p->refcount > 0); 3006881f68fSopenharmony_ci ret = p; 3016881f68fSopenharmony_ci ret->refcount++; 3026881f68fSopenharmony_ci break; 3036881f68fSopenharmony_ci } 3046881f68fSopenharmony_ci } 3056881f68fSopenharmony_ci pthread_mutex_unlock(&lo->mutex); 3066881f68fSopenharmony_ci return ret; 3076881f68fSopenharmony_ci} 3086881f68fSopenharmony_ci 3096881f68fSopenharmony_cistatic int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name, 3106881f68fSopenharmony_ci struct fuse_entry_param *e) 3116881f68fSopenharmony_ci{ 3126881f68fSopenharmony_ci int newfd; 3136881f68fSopenharmony_ci int res; 3146881f68fSopenharmony_ci int saverr; 3156881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 3166881f68fSopenharmony_ci struct lo_inode *inode; 3176881f68fSopenharmony_ci 3186881f68fSopenharmony_ci memset(e, 0, sizeof(*e)); 3196881f68fSopenharmony_ci e->attr_timeout = lo->timeout; 3206881f68fSopenharmony_ci e->entry_timeout = lo->timeout; 3216881f68fSopenharmony_ci 3226881f68fSopenharmony_ci newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW); 3236881f68fSopenharmony_ci if (newfd == -1) 3246881f68fSopenharmony_ci goto out_err; 3256881f68fSopenharmony_ci 3266881f68fSopenharmony_ci res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 3276881f68fSopenharmony_ci if (res == -1) 3286881f68fSopenharmony_ci goto out_err; 3296881f68fSopenharmony_ci 3306881f68fSopenharmony_ci inode = lo_find(lo_data(req), &e->attr); 3316881f68fSopenharmony_ci if (inode) { 3326881f68fSopenharmony_ci close(newfd); 3336881f68fSopenharmony_ci newfd = -1; 3346881f68fSopenharmony_ci } else { 3356881f68fSopenharmony_ci struct lo_inode *prev, *next; 3366881f68fSopenharmony_ci 3376881f68fSopenharmony_ci saverr = ENOMEM; 3386881f68fSopenharmony_ci inode = calloc(1, sizeof(struct lo_inode)); 3396881f68fSopenharmony_ci if (!inode) 3406881f68fSopenharmony_ci goto out_err; 3416881f68fSopenharmony_ci 3426881f68fSopenharmony_ci inode->refcount = 1; 3436881f68fSopenharmony_ci inode->fd = newfd; 3446881f68fSopenharmony_ci inode->ino = e->attr.st_ino; 3456881f68fSopenharmony_ci inode->dev = e->attr.st_dev; 3466881f68fSopenharmony_ci 3476881f68fSopenharmony_ci pthread_mutex_lock(&lo->mutex); 3486881f68fSopenharmony_ci prev = &lo->root; 3496881f68fSopenharmony_ci next = prev->next; 3506881f68fSopenharmony_ci next->prev = inode; 3516881f68fSopenharmony_ci inode->next = next; 3526881f68fSopenharmony_ci inode->prev = prev; 3536881f68fSopenharmony_ci prev->next = inode; 3546881f68fSopenharmony_ci pthread_mutex_unlock(&lo->mutex); 3556881f68fSopenharmony_ci } 3566881f68fSopenharmony_ci e->ino = (uintptr_t) inode; 3576881f68fSopenharmony_ci 3586881f68fSopenharmony_ci if (lo_debug(req)) 3596881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", 3606881f68fSopenharmony_ci (unsigned long long) parent, name, (unsigned long long) e->ino); 3616881f68fSopenharmony_ci 3626881f68fSopenharmony_ci return 0; 3636881f68fSopenharmony_ci 3646881f68fSopenharmony_ciout_err: 3656881f68fSopenharmony_ci saverr = errno; 3666881f68fSopenharmony_ci if (newfd != -1) 3676881f68fSopenharmony_ci close(newfd); 3686881f68fSopenharmony_ci return saverr; 3696881f68fSopenharmony_ci} 3706881f68fSopenharmony_ci 3716881f68fSopenharmony_cistatic void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) 3726881f68fSopenharmony_ci{ 3736881f68fSopenharmony_ci struct fuse_entry_param e; 3746881f68fSopenharmony_ci int err; 3756881f68fSopenharmony_ci 3766881f68fSopenharmony_ci if (lo_debug(req)) 3776881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n", 3786881f68fSopenharmony_ci parent, name); 3796881f68fSopenharmony_ci 3806881f68fSopenharmony_ci err = lo_do_lookup(req, parent, name, &e); 3816881f68fSopenharmony_ci if (err) 3826881f68fSopenharmony_ci fuse_reply_err(req, err); 3836881f68fSopenharmony_ci else 3846881f68fSopenharmony_ci fuse_reply_entry(req, &e); 3856881f68fSopenharmony_ci} 3866881f68fSopenharmony_ci 3876881f68fSopenharmony_cistatic void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent, 3886881f68fSopenharmony_ci const char *name, mode_t mode, dev_t rdev, 3896881f68fSopenharmony_ci const char *link) 3906881f68fSopenharmony_ci{ 3916881f68fSopenharmony_ci int res; 3926881f68fSopenharmony_ci int saverr; 3936881f68fSopenharmony_ci struct lo_inode *dir = lo_inode(req, parent); 3946881f68fSopenharmony_ci struct fuse_entry_param e; 3956881f68fSopenharmony_ci 3966881f68fSopenharmony_ci res = mknod_wrapper(dir->fd, name, link, mode, rdev); 3976881f68fSopenharmony_ci 3986881f68fSopenharmony_ci saverr = errno; 3996881f68fSopenharmony_ci if (res == -1) 4006881f68fSopenharmony_ci goto out; 4016881f68fSopenharmony_ci 4026881f68fSopenharmony_ci saverr = lo_do_lookup(req, parent, name, &e); 4036881f68fSopenharmony_ci if (saverr) 4046881f68fSopenharmony_ci goto out; 4056881f68fSopenharmony_ci 4066881f68fSopenharmony_ci if (lo_debug(req)) 4076881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", 4086881f68fSopenharmony_ci (unsigned long long) parent, name, (unsigned long long) e.ino); 4096881f68fSopenharmony_ci 4106881f68fSopenharmony_ci fuse_reply_entry(req, &e); 4116881f68fSopenharmony_ci return; 4126881f68fSopenharmony_ci 4136881f68fSopenharmony_ciout: 4146881f68fSopenharmony_ci fuse_reply_err(req, saverr); 4156881f68fSopenharmony_ci} 4166881f68fSopenharmony_ci 4176881f68fSopenharmony_cistatic void lo_mknod(fuse_req_t req, fuse_ino_t parent, 4186881f68fSopenharmony_ci const char *name, mode_t mode, dev_t rdev) 4196881f68fSopenharmony_ci{ 4206881f68fSopenharmony_ci lo_mknod_symlink(req, parent, name, mode, rdev, NULL); 4216881f68fSopenharmony_ci} 4226881f68fSopenharmony_ci 4236881f68fSopenharmony_cistatic void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, 4246881f68fSopenharmony_ci mode_t mode) 4256881f68fSopenharmony_ci{ 4266881f68fSopenharmony_ci lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL); 4276881f68fSopenharmony_ci} 4286881f68fSopenharmony_ci 4296881f68fSopenharmony_cistatic void lo_symlink(fuse_req_t req, const char *link, 4306881f68fSopenharmony_ci fuse_ino_t parent, const char *name) 4316881f68fSopenharmony_ci{ 4326881f68fSopenharmony_ci lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link); 4336881f68fSopenharmony_ci} 4346881f68fSopenharmony_ci 4356881f68fSopenharmony_cistatic void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, 4366881f68fSopenharmony_ci const char *name) 4376881f68fSopenharmony_ci{ 4386881f68fSopenharmony_ci int res; 4396881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 4406881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 4416881f68fSopenharmony_ci struct fuse_entry_param e; 4426881f68fSopenharmony_ci char procname[64]; 4436881f68fSopenharmony_ci int saverr; 4446881f68fSopenharmony_ci 4456881f68fSopenharmony_ci memset(&e, 0, sizeof(struct fuse_entry_param)); 4466881f68fSopenharmony_ci e.attr_timeout = lo->timeout; 4476881f68fSopenharmony_ci e.entry_timeout = lo->timeout; 4486881f68fSopenharmony_ci 4496881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", inode->fd); 4506881f68fSopenharmony_ci res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name, 4516881f68fSopenharmony_ci AT_SYMLINK_FOLLOW); 4526881f68fSopenharmony_ci if (res == -1) 4536881f68fSopenharmony_ci goto out_err; 4546881f68fSopenharmony_ci 4556881f68fSopenharmony_ci res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); 4566881f68fSopenharmony_ci if (res == -1) 4576881f68fSopenharmony_ci goto out_err; 4586881f68fSopenharmony_ci 4596881f68fSopenharmony_ci pthread_mutex_lock(&lo->mutex); 4606881f68fSopenharmony_ci inode->refcount++; 4616881f68fSopenharmony_ci pthread_mutex_unlock(&lo->mutex); 4626881f68fSopenharmony_ci e.ino = (uintptr_t) inode; 4636881f68fSopenharmony_ci 4646881f68fSopenharmony_ci if (lo_debug(req)) 4656881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", 4666881f68fSopenharmony_ci (unsigned long long) parent, name, 4676881f68fSopenharmony_ci (unsigned long long) e.ino); 4686881f68fSopenharmony_ci 4696881f68fSopenharmony_ci fuse_reply_entry(req, &e); 4706881f68fSopenharmony_ci return; 4716881f68fSopenharmony_ci 4726881f68fSopenharmony_ciout_err: 4736881f68fSopenharmony_ci saverr = errno; 4746881f68fSopenharmony_ci fuse_reply_err(req, saverr); 4756881f68fSopenharmony_ci} 4766881f68fSopenharmony_ci 4776881f68fSopenharmony_cistatic void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) 4786881f68fSopenharmony_ci{ 4796881f68fSopenharmony_ci int res; 4806881f68fSopenharmony_ci 4816881f68fSopenharmony_ci res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR); 4826881f68fSopenharmony_ci 4836881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 4846881f68fSopenharmony_ci} 4856881f68fSopenharmony_ci 4866881f68fSopenharmony_cistatic void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name, 4876881f68fSopenharmony_ci fuse_ino_t newparent, const char *newname, 4886881f68fSopenharmony_ci unsigned int flags) 4896881f68fSopenharmony_ci{ 4906881f68fSopenharmony_ci int res; 4916881f68fSopenharmony_ci 4926881f68fSopenharmony_ci if (flags) { 4936881f68fSopenharmony_ci fuse_reply_err(req, EINVAL); 4946881f68fSopenharmony_ci return; 4956881f68fSopenharmony_ci } 4966881f68fSopenharmony_ci 4976881f68fSopenharmony_ci res = renameat(lo_fd(req, parent), name, 4986881f68fSopenharmony_ci lo_fd(req, newparent), newname); 4996881f68fSopenharmony_ci 5006881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 5016881f68fSopenharmony_ci} 5026881f68fSopenharmony_ci 5036881f68fSopenharmony_cistatic void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) 5046881f68fSopenharmony_ci{ 5056881f68fSopenharmony_ci int res; 5066881f68fSopenharmony_ci 5076881f68fSopenharmony_ci res = unlinkat(lo_fd(req, parent), name, 0); 5086881f68fSopenharmony_ci 5096881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 5106881f68fSopenharmony_ci} 5116881f68fSopenharmony_ci 5126881f68fSopenharmony_cistatic void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n) 5136881f68fSopenharmony_ci{ 5146881f68fSopenharmony_ci if (!inode) 5156881f68fSopenharmony_ci return; 5166881f68fSopenharmony_ci 5176881f68fSopenharmony_ci pthread_mutex_lock(&lo->mutex); 5186881f68fSopenharmony_ci assert(inode->refcount >= n); 5196881f68fSopenharmony_ci inode->refcount -= n; 5206881f68fSopenharmony_ci if (!inode->refcount) { 5216881f68fSopenharmony_ci struct lo_inode *prev, *next; 5226881f68fSopenharmony_ci 5236881f68fSopenharmony_ci prev = inode->prev; 5246881f68fSopenharmony_ci next = inode->next; 5256881f68fSopenharmony_ci next->prev = prev; 5266881f68fSopenharmony_ci prev->next = next; 5276881f68fSopenharmony_ci 5286881f68fSopenharmony_ci pthread_mutex_unlock(&lo->mutex); 5296881f68fSopenharmony_ci close(inode->fd); 5306881f68fSopenharmony_ci free(inode); 5316881f68fSopenharmony_ci 5326881f68fSopenharmony_ci } else { 5336881f68fSopenharmony_ci pthread_mutex_unlock(&lo->mutex); 5346881f68fSopenharmony_ci } 5356881f68fSopenharmony_ci} 5366881f68fSopenharmony_ci 5376881f68fSopenharmony_cistatic void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) 5386881f68fSopenharmony_ci{ 5396881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 5406881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 5416881f68fSopenharmony_ci 5426881f68fSopenharmony_ci if (lo_debug(req)) { 5436881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n", 5446881f68fSopenharmony_ci (unsigned long long) ino, 5456881f68fSopenharmony_ci (unsigned long long) inode->refcount, 5466881f68fSopenharmony_ci (unsigned long long) nlookup); 5476881f68fSopenharmony_ci } 5486881f68fSopenharmony_ci 5496881f68fSopenharmony_ci unref_inode(lo, inode, nlookup); 5506881f68fSopenharmony_ci} 5516881f68fSopenharmony_ci 5526881f68fSopenharmony_cistatic void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) 5536881f68fSopenharmony_ci{ 5546881f68fSopenharmony_ci lo_forget_one(req, ino, nlookup); 5556881f68fSopenharmony_ci fuse_reply_none(req); 5566881f68fSopenharmony_ci} 5576881f68fSopenharmony_ci 5586881f68fSopenharmony_cistatic void lo_forget_multi(fuse_req_t req, size_t count, 5596881f68fSopenharmony_ci struct fuse_forget_data *forgets) 5606881f68fSopenharmony_ci{ 5616881f68fSopenharmony_ci int i; 5626881f68fSopenharmony_ci 5636881f68fSopenharmony_ci for (i = 0; i < count; i++) 5646881f68fSopenharmony_ci lo_forget_one(req, forgets[i].ino, forgets[i].nlookup); 5656881f68fSopenharmony_ci fuse_reply_none(req); 5666881f68fSopenharmony_ci} 5676881f68fSopenharmony_ci 5686881f68fSopenharmony_cistatic void lo_readlink(fuse_req_t req, fuse_ino_t ino) 5696881f68fSopenharmony_ci{ 5706881f68fSopenharmony_ci char buf[PATH_MAX + 1]; 5716881f68fSopenharmony_ci int res; 5726881f68fSopenharmony_ci 5736881f68fSopenharmony_ci res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf)); 5746881f68fSopenharmony_ci if (res == -1) 5756881f68fSopenharmony_ci return (void) fuse_reply_err(req, errno); 5766881f68fSopenharmony_ci 5776881f68fSopenharmony_ci if (res == sizeof(buf)) 5786881f68fSopenharmony_ci return (void) fuse_reply_err(req, ENAMETOOLONG); 5796881f68fSopenharmony_ci 5806881f68fSopenharmony_ci buf[res] = '\0'; 5816881f68fSopenharmony_ci 5826881f68fSopenharmony_ci fuse_reply_readlink(req, buf); 5836881f68fSopenharmony_ci} 5846881f68fSopenharmony_ci 5856881f68fSopenharmony_cistruct lo_dirp { 5866881f68fSopenharmony_ci DIR *dp; 5876881f68fSopenharmony_ci struct dirent *entry; 5886881f68fSopenharmony_ci off_t offset; 5896881f68fSopenharmony_ci}; 5906881f68fSopenharmony_ci 5916881f68fSopenharmony_cistatic struct lo_dirp *lo_dirp(struct fuse_file_info *fi) 5926881f68fSopenharmony_ci{ 5936881f68fSopenharmony_ci return (struct lo_dirp *) (uintptr_t) fi->fh; 5946881f68fSopenharmony_ci} 5956881f68fSopenharmony_ci 5966881f68fSopenharmony_cistatic void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) 5976881f68fSopenharmony_ci{ 5986881f68fSopenharmony_ci int error = ENOMEM; 5996881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 6006881f68fSopenharmony_ci struct lo_dirp *d; 6016881f68fSopenharmony_ci int fd; 6026881f68fSopenharmony_ci 6036881f68fSopenharmony_ci d = calloc(1, sizeof(struct lo_dirp)); 6046881f68fSopenharmony_ci if (d == NULL) 6056881f68fSopenharmony_ci goto out_err; 6066881f68fSopenharmony_ci 6076881f68fSopenharmony_ci fd = openat(lo_fd(req, ino), ".", O_RDONLY); 6086881f68fSopenharmony_ci if (fd == -1) 6096881f68fSopenharmony_ci goto out_errno; 6106881f68fSopenharmony_ci 6116881f68fSopenharmony_ci d->dp = fdopendir(fd); 6126881f68fSopenharmony_ci if (d->dp == NULL) 6136881f68fSopenharmony_ci goto out_errno; 6146881f68fSopenharmony_ci 6156881f68fSopenharmony_ci d->offset = 0; 6166881f68fSopenharmony_ci d->entry = NULL; 6176881f68fSopenharmony_ci 6186881f68fSopenharmony_ci fi->fh = (uintptr_t) d; 6196881f68fSopenharmony_ci if (lo->cache == CACHE_ALWAYS) 6206881f68fSopenharmony_ci fi->cache_readdir = 1; 6216881f68fSopenharmony_ci fuse_reply_open(req, fi); 6226881f68fSopenharmony_ci return; 6236881f68fSopenharmony_ci 6246881f68fSopenharmony_ciout_errno: 6256881f68fSopenharmony_ci error = errno; 6266881f68fSopenharmony_ciout_err: 6276881f68fSopenharmony_ci if (d) { 6286881f68fSopenharmony_ci if (fd != -1) 6296881f68fSopenharmony_ci close(fd); 6306881f68fSopenharmony_ci free(d); 6316881f68fSopenharmony_ci } 6326881f68fSopenharmony_ci fuse_reply_err(req, error); 6336881f68fSopenharmony_ci} 6346881f68fSopenharmony_ci 6356881f68fSopenharmony_cistatic int is_dot_or_dotdot(const char *name) 6366881f68fSopenharmony_ci{ 6376881f68fSopenharmony_ci return name[0] == '.' && (name[1] == '\0' || 6386881f68fSopenharmony_ci (name[1] == '.' && name[2] == '\0')); 6396881f68fSopenharmony_ci} 6406881f68fSopenharmony_ci 6416881f68fSopenharmony_cistatic void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, 6426881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi, int plus) 6436881f68fSopenharmony_ci{ 6446881f68fSopenharmony_ci struct lo_dirp *d = lo_dirp(fi); 6456881f68fSopenharmony_ci char *buf; 6466881f68fSopenharmony_ci char *p; 6476881f68fSopenharmony_ci size_t rem = size; 6486881f68fSopenharmony_ci int err; 6496881f68fSopenharmony_ci 6506881f68fSopenharmony_ci (void) ino; 6516881f68fSopenharmony_ci 6526881f68fSopenharmony_ci buf = calloc(1, size); 6536881f68fSopenharmony_ci if (!buf) { 6546881f68fSopenharmony_ci err = ENOMEM; 6556881f68fSopenharmony_ci goto error; 6566881f68fSopenharmony_ci } 6576881f68fSopenharmony_ci p = buf; 6586881f68fSopenharmony_ci 6596881f68fSopenharmony_ci if (offset != d->offset) { 6606881f68fSopenharmony_ci seekdir(d->dp, offset); 6616881f68fSopenharmony_ci d->entry = NULL; 6626881f68fSopenharmony_ci d->offset = offset; 6636881f68fSopenharmony_ci } 6646881f68fSopenharmony_ci while (1) { 6656881f68fSopenharmony_ci size_t entsize; 6666881f68fSopenharmony_ci off_t nextoff; 6676881f68fSopenharmony_ci const char *name; 6686881f68fSopenharmony_ci 6696881f68fSopenharmony_ci if (!d->entry) { 6706881f68fSopenharmony_ci errno = 0; 6716881f68fSopenharmony_ci d->entry = readdir(d->dp); 6726881f68fSopenharmony_ci if (!d->entry) { 6736881f68fSopenharmony_ci if (errno) { // Error 6746881f68fSopenharmony_ci err = errno; 6756881f68fSopenharmony_ci goto error; 6766881f68fSopenharmony_ci } else { // End of stream 6776881f68fSopenharmony_ci break; 6786881f68fSopenharmony_ci } 6796881f68fSopenharmony_ci } 6806881f68fSopenharmony_ci } 6816881f68fSopenharmony_ci nextoff = d->entry->d_off; 6826881f68fSopenharmony_ci name = d->entry->d_name; 6836881f68fSopenharmony_ci fuse_ino_t entry_ino = 0; 6846881f68fSopenharmony_ci if (plus) { 6856881f68fSopenharmony_ci struct fuse_entry_param e; 6866881f68fSopenharmony_ci if (is_dot_or_dotdot(name)) { 6876881f68fSopenharmony_ci e = (struct fuse_entry_param) { 6886881f68fSopenharmony_ci .attr.st_ino = d->entry->d_ino, 6896881f68fSopenharmony_ci .attr.st_mode = d->entry->d_type << 12, 6906881f68fSopenharmony_ci }; 6916881f68fSopenharmony_ci } else { 6926881f68fSopenharmony_ci err = lo_do_lookup(req, ino, name, &e); 6936881f68fSopenharmony_ci if (err) 6946881f68fSopenharmony_ci goto error; 6956881f68fSopenharmony_ci entry_ino = e.ino; 6966881f68fSopenharmony_ci } 6976881f68fSopenharmony_ci 6986881f68fSopenharmony_ci entsize = fuse_add_direntry_plus(req, p, rem, name, 6996881f68fSopenharmony_ci &e, nextoff); 7006881f68fSopenharmony_ci } else { 7016881f68fSopenharmony_ci struct stat st = { 7026881f68fSopenharmony_ci .st_ino = d->entry->d_ino, 7036881f68fSopenharmony_ci .st_mode = d->entry->d_type << 12, 7046881f68fSopenharmony_ci }; 7056881f68fSopenharmony_ci entsize = fuse_add_direntry(req, p, rem, name, 7066881f68fSopenharmony_ci &st, nextoff); 7076881f68fSopenharmony_ci } 7086881f68fSopenharmony_ci if (entsize > rem) { 7096881f68fSopenharmony_ci if (entry_ino != 0) 7106881f68fSopenharmony_ci lo_forget_one(req, entry_ino, 1); 7116881f68fSopenharmony_ci break; 7126881f68fSopenharmony_ci } 7136881f68fSopenharmony_ci 7146881f68fSopenharmony_ci p += entsize; 7156881f68fSopenharmony_ci rem -= entsize; 7166881f68fSopenharmony_ci 7176881f68fSopenharmony_ci d->entry = NULL; 7186881f68fSopenharmony_ci d->offset = nextoff; 7196881f68fSopenharmony_ci } 7206881f68fSopenharmony_ci 7216881f68fSopenharmony_ci err = 0; 7226881f68fSopenharmony_cierror: 7236881f68fSopenharmony_ci // If there's an error, we can only signal it if we haven't stored 7246881f68fSopenharmony_ci // any entries yet - otherwise we'd end up with wrong lookup 7256881f68fSopenharmony_ci // counts for the entries that are already in the buffer. So we 7266881f68fSopenharmony_ci // return what we've collected until that point. 7276881f68fSopenharmony_ci if (err && rem == size) 7286881f68fSopenharmony_ci fuse_reply_err(req, err); 7296881f68fSopenharmony_ci else 7306881f68fSopenharmony_ci fuse_reply_buf(req, buf, size - rem); 7316881f68fSopenharmony_ci free(buf); 7326881f68fSopenharmony_ci} 7336881f68fSopenharmony_ci 7346881f68fSopenharmony_cistatic void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, 7356881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 7366881f68fSopenharmony_ci{ 7376881f68fSopenharmony_ci lo_do_readdir(req, ino, size, offset, fi, 0); 7386881f68fSopenharmony_ci} 7396881f68fSopenharmony_ci 7406881f68fSopenharmony_cistatic void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, 7416881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 7426881f68fSopenharmony_ci{ 7436881f68fSopenharmony_ci lo_do_readdir(req, ino, size, offset, fi, 1); 7446881f68fSopenharmony_ci} 7456881f68fSopenharmony_ci 7466881f68fSopenharmony_cistatic void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) 7476881f68fSopenharmony_ci{ 7486881f68fSopenharmony_ci struct lo_dirp *d = lo_dirp(fi); 7496881f68fSopenharmony_ci (void) ino; 7506881f68fSopenharmony_ci closedir(d->dp); 7516881f68fSopenharmony_ci free(d); 7526881f68fSopenharmony_ci fuse_reply_err(req, 0); 7536881f68fSopenharmony_ci} 7546881f68fSopenharmony_ci 7556881f68fSopenharmony_cistatic void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name, 7566881f68fSopenharmony_ci mode_t mode, struct fuse_file_info *fi) 7576881f68fSopenharmony_ci{ 7586881f68fSopenharmony_ci int fd; 7596881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 7606881f68fSopenharmony_ci struct fuse_entry_param e; 7616881f68fSopenharmony_ci int err; 7626881f68fSopenharmony_ci 7636881f68fSopenharmony_ci if (lo_debug(req)) 7646881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n", 7656881f68fSopenharmony_ci parent, name); 7666881f68fSopenharmony_ci 7676881f68fSopenharmony_ci fd = openat(lo_fd(req, parent), name, 7686881f68fSopenharmony_ci (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode); 7696881f68fSopenharmony_ci if (fd == -1) 7706881f68fSopenharmony_ci return (void) fuse_reply_err(req, errno); 7716881f68fSopenharmony_ci 7726881f68fSopenharmony_ci fi->fh = fd; 7736881f68fSopenharmony_ci if (lo->cache == CACHE_NEVER) 7746881f68fSopenharmony_ci fi->direct_io = 1; 7756881f68fSopenharmony_ci else if (lo->cache == CACHE_ALWAYS) 7766881f68fSopenharmony_ci fi->keep_cache = 1; 7776881f68fSopenharmony_ci 7786881f68fSopenharmony_ci err = lo_do_lookup(req, parent, name, &e); 7796881f68fSopenharmony_ci if (err) 7806881f68fSopenharmony_ci fuse_reply_err(req, err); 7816881f68fSopenharmony_ci else 7826881f68fSopenharmony_ci fuse_reply_create(req, &e, fi); 7836881f68fSopenharmony_ci} 7846881f68fSopenharmony_ci 7856881f68fSopenharmony_cistatic void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, 7866881f68fSopenharmony_ci struct fuse_file_info *fi) 7876881f68fSopenharmony_ci{ 7886881f68fSopenharmony_ci int res; 7896881f68fSopenharmony_ci int fd = dirfd(lo_dirp(fi)->dp); 7906881f68fSopenharmony_ci (void) ino; 7916881f68fSopenharmony_ci if (datasync) 7926881f68fSopenharmony_ci res = fdatasync(fd); 7936881f68fSopenharmony_ci else 7946881f68fSopenharmony_ci res = fsync(fd); 7956881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 7966881f68fSopenharmony_ci} 7976881f68fSopenharmony_ci 7986881f68fSopenharmony_cistatic void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) 7996881f68fSopenharmony_ci{ 8006881f68fSopenharmony_ci int fd; 8016881f68fSopenharmony_ci char buf[64]; 8026881f68fSopenharmony_ci struct lo_data *lo = lo_data(req); 8036881f68fSopenharmony_ci 8046881f68fSopenharmony_ci if (lo_debug(req)) 8056881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n", 8066881f68fSopenharmony_ci ino, fi->flags); 8076881f68fSopenharmony_ci 8086881f68fSopenharmony_ci /* With writeback cache, kernel may send read requests even 8096881f68fSopenharmony_ci when userspace opened write-only */ 8106881f68fSopenharmony_ci if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) { 8116881f68fSopenharmony_ci fi->flags &= ~O_ACCMODE; 8126881f68fSopenharmony_ci fi->flags |= O_RDWR; 8136881f68fSopenharmony_ci } 8146881f68fSopenharmony_ci 8156881f68fSopenharmony_ci /* With writeback cache, O_APPEND is handled by the kernel. 8166881f68fSopenharmony_ci This breaks atomicity (since the file may change in the 8176881f68fSopenharmony_ci underlying filesystem, so that the kernel's idea of the 8186881f68fSopenharmony_ci end of the file isn't accurate anymore). In this example, 8196881f68fSopenharmony_ci we just accept that. A more rigorous filesystem may want 8206881f68fSopenharmony_ci to return an error here */ 8216881f68fSopenharmony_ci if (lo->writeback && (fi->flags & O_APPEND)) 8226881f68fSopenharmony_ci fi->flags &= ~O_APPEND; 8236881f68fSopenharmony_ci 8246881f68fSopenharmony_ci sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino)); 8256881f68fSopenharmony_ci fd = open(buf, fi->flags & ~O_NOFOLLOW); 8266881f68fSopenharmony_ci if (fd == -1) 8276881f68fSopenharmony_ci return (void) fuse_reply_err(req, errno); 8286881f68fSopenharmony_ci 8296881f68fSopenharmony_ci fi->fh = fd; 8306881f68fSopenharmony_ci if (lo->cache == CACHE_NEVER) 8316881f68fSopenharmony_ci fi->direct_io = 1; 8326881f68fSopenharmony_ci else if (lo->cache == CACHE_ALWAYS) 8336881f68fSopenharmony_ci fi->keep_cache = 1; 8346881f68fSopenharmony_ci fuse_reply_open(req, fi); 8356881f68fSopenharmony_ci} 8366881f68fSopenharmony_ci 8376881f68fSopenharmony_cistatic void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) 8386881f68fSopenharmony_ci{ 8396881f68fSopenharmony_ci (void) ino; 8406881f68fSopenharmony_ci 8416881f68fSopenharmony_ci close(fi->fh); 8426881f68fSopenharmony_ci fuse_reply_err(req, 0); 8436881f68fSopenharmony_ci} 8446881f68fSopenharmony_ci 8456881f68fSopenharmony_cistatic void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) 8466881f68fSopenharmony_ci{ 8476881f68fSopenharmony_ci int res; 8486881f68fSopenharmony_ci (void) ino; 8496881f68fSopenharmony_ci res = close(dup(fi->fh)); 8506881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 8516881f68fSopenharmony_ci} 8526881f68fSopenharmony_ci 8536881f68fSopenharmony_cistatic void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, 8546881f68fSopenharmony_ci struct fuse_file_info *fi) 8556881f68fSopenharmony_ci{ 8566881f68fSopenharmony_ci int res; 8576881f68fSopenharmony_ci (void) ino; 8586881f68fSopenharmony_ci if (datasync) 8596881f68fSopenharmony_ci res = fdatasync(fi->fh); 8606881f68fSopenharmony_ci else 8616881f68fSopenharmony_ci res = fsync(fi->fh); 8626881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 8636881f68fSopenharmony_ci} 8646881f68fSopenharmony_ci 8656881f68fSopenharmony_cistatic void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size, 8666881f68fSopenharmony_ci off_t offset, struct fuse_file_info *fi) 8676881f68fSopenharmony_ci{ 8686881f68fSopenharmony_ci struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size); 8696881f68fSopenharmony_ci 8706881f68fSopenharmony_ci if (lo_debug(req)) 8716881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, " 8726881f68fSopenharmony_ci "off=%lu)\n", ino, size, (unsigned long) offset); 8736881f68fSopenharmony_ci 8746881f68fSopenharmony_ci buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; 8756881f68fSopenharmony_ci buf.buf[0].fd = fi->fh; 8766881f68fSopenharmony_ci buf.buf[0].pos = offset; 8776881f68fSopenharmony_ci 8786881f68fSopenharmony_ci fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE); 8796881f68fSopenharmony_ci} 8806881f68fSopenharmony_ci 8816881f68fSopenharmony_cistatic void lo_write_buf(fuse_req_t req, fuse_ino_t ino, 8826881f68fSopenharmony_ci struct fuse_bufvec *in_buf, off_t off, 8836881f68fSopenharmony_ci struct fuse_file_info *fi) 8846881f68fSopenharmony_ci{ 8856881f68fSopenharmony_ci (void) ino; 8866881f68fSopenharmony_ci ssize_t res; 8876881f68fSopenharmony_ci struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf)); 8886881f68fSopenharmony_ci 8896881f68fSopenharmony_ci out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; 8906881f68fSopenharmony_ci out_buf.buf[0].fd = fi->fh; 8916881f68fSopenharmony_ci out_buf.buf[0].pos = off; 8926881f68fSopenharmony_ci 8936881f68fSopenharmony_ci if (lo_debug(req)) 8946881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n", 8956881f68fSopenharmony_ci ino, out_buf.buf[0].size, (unsigned long) off); 8966881f68fSopenharmony_ci 8976881f68fSopenharmony_ci res = fuse_buf_copy(&out_buf, in_buf, 0); 8986881f68fSopenharmony_ci if(res < 0) 8996881f68fSopenharmony_ci fuse_reply_err(req, -res); 9006881f68fSopenharmony_ci else 9016881f68fSopenharmony_ci fuse_reply_write(req, (size_t) res); 9026881f68fSopenharmony_ci} 9036881f68fSopenharmony_ci 9046881f68fSopenharmony_cistatic void lo_statfs(fuse_req_t req, fuse_ino_t ino) 9056881f68fSopenharmony_ci{ 9066881f68fSopenharmony_ci int res; 9076881f68fSopenharmony_ci struct statvfs stbuf; 9086881f68fSopenharmony_ci 9096881f68fSopenharmony_ci res = fstatvfs(lo_fd(req, ino), &stbuf); 9106881f68fSopenharmony_ci if (res == -1) 9116881f68fSopenharmony_ci fuse_reply_err(req, errno); 9126881f68fSopenharmony_ci else 9136881f68fSopenharmony_ci fuse_reply_statfs(req, &stbuf); 9146881f68fSopenharmony_ci} 9156881f68fSopenharmony_ci 9166881f68fSopenharmony_cistatic void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, 9176881f68fSopenharmony_ci off_t offset, off_t length, struct fuse_file_info *fi) 9186881f68fSopenharmony_ci{ 9196881f68fSopenharmony_ci int err = EOPNOTSUPP; 9206881f68fSopenharmony_ci (void) ino; 9216881f68fSopenharmony_ci 9226881f68fSopenharmony_ci#ifdef HAVE_FALLOCATE 9236881f68fSopenharmony_ci err = fallocate(fi->fh, mode, offset, length); 9246881f68fSopenharmony_ci if (err < 0) 9256881f68fSopenharmony_ci err = errno; 9266881f68fSopenharmony_ci 9276881f68fSopenharmony_ci#elif defined(HAVE_POSIX_FALLOCATE) 9286881f68fSopenharmony_ci if (mode) { 9296881f68fSopenharmony_ci fuse_reply_err(req, EOPNOTSUPP); 9306881f68fSopenharmony_ci return; 9316881f68fSopenharmony_ci } 9326881f68fSopenharmony_ci 9336881f68fSopenharmony_ci err = posix_fallocate(fi->fh, offset, length); 9346881f68fSopenharmony_ci#endif 9356881f68fSopenharmony_ci 9366881f68fSopenharmony_ci fuse_reply_err(req, err); 9376881f68fSopenharmony_ci} 9386881f68fSopenharmony_ci 9396881f68fSopenharmony_cistatic void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, 9406881f68fSopenharmony_ci int op) 9416881f68fSopenharmony_ci{ 9426881f68fSopenharmony_ci int res; 9436881f68fSopenharmony_ci (void) ino; 9446881f68fSopenharmony_ci 9456881f68fSopenharmony_ci res = flock(fi->fh, op); 9466881f68fSopenharmony_ci 9476881f68fSopenharmony_ci fuse_reply_err(req, res == -1 ? errno : 0); 9486881f68fSopenharmony_ci} 9496881f68fSopenharmony_ci 9506881f68fSopenharmony_cistatic void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, 9516881f68fSopenharmony_ci size_t size) 9526881f68fSopenharmony_ci{ 9536881f68fSopenharmony_ci char *value = NULL; 9546881f68fSopenharmony_ci char procname[64]; 9556881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 9566881f68fSopenharmony_ci ssize_t ret; 9576881f68fSopenharmony_ci int saverr; 9586881f68fSopenharmony_ci 9596881f68fSopenharmony_ci saverr = ENOSYS; 9606881f68fSopenharmony_ci if (!lo_data(req)->xattr) 9616881f68fSopenharmony_ci goto out; 9626881f68fSopenharmony_ci 9636881f68fSopenharmony_ci if (lo_debug(req)) { 9646881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", 9656881f68fSopenharmony_ci ino, name, size); 9666881f68fSopenharmony_ci } 9676881f68fSopenharmony_ci 9686881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", inode->fd); 9696881f68fSopenharmony_ci 9706881f68fSopenharmony_ci if (size) { 9716881f68fSopenharmony_ci value = malloc(size); 9726881f68fSopenharmony_ci if (!value) 9736881f68fSopenharmony_ci goto out_err; 9746881f68fSopenharmony_ci 9756881f68fSopenharmony_ci ret = getxattr(procname, name, value, size); 9766881f68fSopenharmony_ci if (ret == -1) 9776881f68fSopenharmony_ci goto out_err; 9786881f68fSopenharmony_ci saverr = 0; 9796881f68fSopenharmony_ci if (ret == 0) 9806881f68fSopenharmony_ci goto out; 9816881f68fSopenharmony_ci 9826881f68fSopenharmony_ci fuse_reply_buf(req, value, ret); 9836881f68fSopenharmony_ci } else { 9846881f68fSopenharmony_ci ret = getxattr(procname, name, NULL, 0); 9856881f68fSopenharmony_ci if (ret == -1) 9866881f68fSopenharmony_ci goto out_err; 9876881f68fSopenharmony_ci 9886881f68fSopenharmony_ci fuse_reply_xattr(req, ret); 9896881f68fSopenharmony_ci } 9906881f68fSopenharmony_ciout_free: 9916881f68fSopenharmony_ci free(value); 9926881f68fSopenharmony_ci return; 9936881f68fSopenharmony_ci 9946881f68fSopenharmony_ciout_err: 9956881f68fSopenharmony_ci saverr = errno; 9966881f68fSopenharmony_ciout: 9976881f68fSopenharmony_ci fuse_reply_err(req, saverr); 9986881f68fSopenharmony_ci goto out_free; 9996881f68fSopenharmony_ci} 10006881f68fSopenharmony_ci 10016881f68fSopenharmony_cistatic void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) 10026881f68fSopenharmony_ci{ 10036881f68fSopenharmony_ci char *value = NULL; 10046881f68fSopenharmony_ci char procname[64]; 10056881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 10066881f68fSopenharmony_ci ssize_t ret; 10076881f68fSopenharmony_ci int saverr; 10086881f68fSopenharmony_ci 10096881f68fSopenharmony_ci saverr = ENOSYS; 10106881f68fSopenharmony_ci if (!lo_data(req)->xattr) 10116881f68fSopenharmony_ci goto out; 10126881f68fSopenharmony_ci 10136881f68fSopenharmony_ci if (lo_debug(req)) { 10146881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n", 10156881f68fSopenharmony_ci ino, size); 10166881f68fSopenharmony_ci } 10176881f68fSopenharmony_ci 10186881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", inode->fd); 10196881f68fSopenharmony_ci 10206881f68fSopenharmony_ci if (size) { 10216881f68fSopenharmony_ci value = malloc(size); 10226881f68fSopenharmony_ci if (!value) 10236881f68fSopenharmony_ci goto out_err; 10246881f68fSopenharmony_ci 10256881f68fSopenharmony_ci ret = listxattr(procname, value, size); 10266881f68fSopenharmony_ci if (ret == -1) 10276881f68fSopenharmony_ci goto out_err; 10286881f68fSopenharmony_ci saverr = 0; 10296881f68fSopenharmony_ci if (ret == 0) 10306881f68fSopenharmony_ci goto out; 10316881f68fSopenharmony_ci 10326881f68fSopenharmony_ci fuse_reply_buf(req, value, ret); 10336881f68fSopenharmony_ci } else { 10346881f68fSopenharmony_ci ret = listxattr(procname, NULL, 0); 10356881f68fSopenharmony_ci if (ret == -1) 10366881f68fSopenharmony_ci goto out_err; 10376881f68fSopenharmony_ci 10386881f68fSopenharmony_ci fuse_reply_xattr(req, ret); 10396881f68fSopenharmony_ci } 10406881f68fSopenharmony_ciout_free: 10416881f68fSopenharmony_ci free(value); 10426881f68fSopenharmony_ci return; 10436881f68fSopenharmony_ci 10446881f68fSopenharmony_ciout_err: 10456881f68fSopenharmony_ci saverr = errno; 10466881f68fSopenharmony_ciout: 10476881f68fSopenharmony_ci fuse_reply_err(req, saverr); 10486881f68fSopenharmony_ci goto out_free; 10496881f68fSopenharmony_ci} 10506881f68fSopenharmony_ci 10516881f68fSopenharmony_cistatic void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, 10526881f68fSopenharmony_ci const char *value, size_t size, int flags) 10536881f68fSopenharmony_ci{ 10546881f68fSopenharmony_ci char procname[64]; 10556881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 10566881f68fSopenharmony_ci ssize_t ret; 10576881f68fSopenharmony_ci int saverr; 10586881f68fSopenharmony_ci 10596881f68fSopenharmony_ci saverr = ENOSYS; 10606881f68fSopenharmony_ci if (!lo_data(req)->xattr) 10616881f68fSopenharmony_ci goto out; 10626881f68fSopenharmony_ci 10636881f68fSopenharmony_ci if (lo_debug(req)) { 10646881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n", 10656881f68fSopenharmony_ci ino, name, value, size); 10666881f68fSopenharmony_ci } 10676881f68fSopenharmony_ci 10686881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", inode->fd); 10696881f68fSopenharmony_ci 10706881f68fSopenharmony_ci ret = setxattr(procname, name, value, size, flags); 10716881f68fSopenharmony_ci saverr = ret == -1 ? errno : 0; 10726881f68fSopenharmony_ci 10736881f68fSopenharmony_ciout: 10746881f68fSopenharmony_ci fuse_reply_err(req, saverr); 10756881f68fSopenharmony_ci} 10766881f68fSopenharmony_ci 10776881f68fSopenharmony_cistatic void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) 10786881f68fSopenharmony_ci{ 10796881f68fSopenharmony_ci char procname[64]; 10806881f68fSopenharmony_ci struct lo_inode *inode = lo_inode(req, ino); 10816881f68fSopenharmony_ci ssize_t ret; 10826881f68fSopenharmony_ci int saverr; 10836881f68fSopenharmony_ci 10846881f68fSopenharmony_ci saverr = ENOSYS; 10856881f68fSopenharmony_ci if (!lo_data(req)->xattr) 10866881f68fSopenharmony_ci goto out; 10876881f68fSopenharmony_ci 10886881f68fSopenharmony_ci if (lo_debug(req)) { 10896881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n", 10906881f68fSopenharmony_ci ino, name); 10916881f68fSopenharmony_ci } 10926881f68fSopenharmony_ci 10936881f68fSopenharmony_ci sprintf(procname, "/proc/self/fd/%i", inode->fd); 10946881f68fSopenharmony_ci 10956881f68fSopenharmony_ci ret = removexattr(procname, name); 10966881f68fSopenharmony_ci saverr = ret == -1 ? errno : 0; 10976881f68fSopenharmony_ci 10986881f68fSopenharmony_ciout: 10996881f68fSopenharmony_ci fuse_reply_err(req, saverr); 11006881f68fSopenharmony_ci} 11016881f68fSopenharmony_ci 11026881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE 11036881f68fSopenharmony_cistatic void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, 11046881f68fSopenharmony_ci struct fuse_file_info *fi_in, 11056881f68fSopenharmony_ci fuse_ino_t ino_out, off_t off_out, 11066881f68fSopenharmony_ci struct fuse_file_info *fi_out, size_t len, 11076881f68fSopenharmony_ci int flags) 11086881f68fSopenharmony_ci{ 11096881f68fSopenharmony_ci ssize_t res; 11106881f68fSopenharmony_ci 11116881f68fSopenharmony_ci if (lo_debug(req)) 11126881f68fSopenharmony_ci fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, " 11136881f68fSopenharmony_ci "off=%lu, ino=%" PRIu64 "/fd=%lu, " 11146881f68fSopenharmony_ci "off=%lu, size=%zd, flags=0x%x)\n", 11156881f68fSopenharmony_ci ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out, 11166881f68fSopenharmony_ci len, flags); 11176881f68fSopenharmony_ci 11186881f68fSopenharmony_ci res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, 11196881f68fSopenharmony_ci flags); 11206881f68fSopenharmony_ci if (res < 0) 11216881f68fSopenharmony_ci fuse_reply_err(req, errno); 11226881f68fSopenharmony_ci else 11236881f68fSopenharmony_ci fuse_reply_write(req, res); 11246881f68fSopenharmony_ci} 11256881f68fSopenharmony_ci#endif 11266881f68fSopenharmony_ci 11276881f68fSopenharmony_cistatic void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, 11286881f68fSopenharmony_ci struct fuse_file_info *fi) 11296881f68fSopenharmony_ci{ 11306881f68fSopenharmony_ci off_t res; 11316881f68fSopenharmony_ci 11326881f68fSopenharmony_ci (void)ino; 11336881f68fSopenharmony_ci res = lseek(fi->fh, off, whence); 11346881f68fSopenharmony_ci if (res != -1) 11356881f68fSopenharmony_ci fuse_reply_lseek(req, res); 11366881f68fSopenharmony_ci else 11376881f68fSopenharmony_ci fuse_reply_err(req, errno); 11386881f68fSopenharmony_ci} 11396881f68fSopenharmony_ci 11406881f68fSopenharmony_cistatic const struct fuse_lowlevel_ops lo_oper = { 11416881f68fSopenharmony_ci .init = lo_init, 11426881f68fSopenharmony_ci .destroy = lo_destroy, 11436881f68fSopenharmony_ci .lookup = lo_lookup, 11446881f68fSopenharmony_ci .mkdir = lo_mkdir, 11456881f68fSopenharmony_ci .mknod = lo_mknod, 11466881f68fSopenharmony_ci .symlink = lo_symlink, 11476881f68fSopenharmony_ci .link = lo_link, 11486881f68fSopenharmony_ci .unlink = lo_unlink, 11496881f68fSopenharmony_ci .rmdir = lo_rmdir, 11506881f68fSopenharmony_ci .rename = lo_rename, 11516881f68fSopenharmony_ci .forget = lo_forget, 11526881f68fSopenharmony_ci .forget_multi = lo_forget_multi, 11536881f68fSopenharmony_ci .getattr = lo_getattr, 11546881f68fSopenharmony_ci .setattr = lo_setattr, 11556881f68fSopenharmony_ci .readlink = lo_readlink, 11566881f68fSopenharmony_ci .opendir = lo_opendir, 11576881f68fSopenharmony_ci .readdir = lo_readdir, 11586881f68fSopenharmony_ci .readdirplus = lo_readdirplus, 11596881f68fSopenharmony_ci .releasedir = lo_releasedir, 11606881f68fSopenharmony_ci .fsyncdir = lo_fsyncdir, 11616881f68fSopenharmony_ci .create = lo_create, 11626881f68fSopenharmony_ci .open = lo_open, 11636881f68fSopenharmony_ci .release = lo_release, 11646881f68fSopenharmony_ci .flush = lo_flush, 11656881f68fSopenharmony_ci .fsync = lo_fsync, 11666881f68fSopenharmony_ci .read = lo_read, 11676881f68fSopenharmony_ci .write_buf = lo_write_buf, 11686881f68fSopenharmony_ci .statfs = lo_statfs, 11696881f68fSopenharmony_ci .fallocate = lo_fallocate, 11706881f68fSopenharmony_ci .flock = lo_flock, 11716881f68fSopenharmony_ci .getxattr = lo_getxattr, 11726881f68fSopenharmony_ci .listxattr = lo_listxattr, 11736881f68fSopenharmony_ci .setxattr = lo_setxattr, 11746881f68fSopenharmony_ci .removexattr = lo_removexattr, 11756881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE 11766881f68fSopenharmony_ci .copy_file_range = lo_copy_file_range, 11776881f68fSopenharmony_ci#endif 11786881f68fSopenharmony_ci .lseek = lo_lseek, 11796881f68fSopenharmony_ci}; 11806881f68fSopenharmony_ci 11816881f68fSopenharmony_ciint main(int argc, char *argv[]) 11826881f68fSopenharmony_ci{ 11836881f68fSopenharmony_ci struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 11846881f68fSopenharmony_ci struct fuse_session *se; 11856881f68fSopenharmony_ci struct fuse_cmdline_opts opts; 11866881f68fSopenharmony_ci struct fuse_loop_config config; 11876881f68fSopenharmony_ci struct lo_data lo = { .debug = 0, 11886881f68fSopenharmony_ci .writeback = 0 }; 11896881f68fSopenharmony_ci int ret = -1; 11906881f68fSopenharmony_ci 11916881f68fSopenharmony_ci /* Don't mask creation mode, kernel already did that */ 11926881f68fSopenharmony_ci umask(0); 11936881f68fSopenharmony_ci 11946881f68fSopenharmony_ci pthread_mutex_init(&lo.mutex, NULL); 11956881f68fSopenharmony_ci lo.root.next = lo.root.prev = &lo.root; 11966881f68fSopenharmony_ci lo.root.fd = -1; 11976881f68fSopenharmony_ci lo.cache = CACHE_NORMAL; 11986881f68fSopenharmony_ci 11996881f68fSopenharmony_ci if (fuse_parse_cmdline(&args, &opts) != 0) 12006881f68fSopenharmony_ci return 1; 12016881f68fSopenharmony_ci if (opts.show_help) { 12026881f68fSopenharmony_ci printf("usage: %s [options] <mountpoint>\n\n", argv[0]); 12036881f68fSopenharmony_ci fuse_cmdline_help(); 12046881f68fSopenharmony_ci fuse_lowlevel_help(); 12056881f68fSopenharmony_ci passthrough_ll_help(); 12066881f68fSopenharmony_ci ret = 0; 12076881f68fSopenharmony_ci goto err_out1; 12086881f68fSopenharmony_ci } else if (opts.show_version) { 12096881f68fSopenharmony_ci printf("FUSE library version %s\n", fuse_pkgversion()); 12106881f68fSopenharmony_ci fuse_lowlevel_version(); 12116881f68fSopenharmony_ci ret = 0; 12126881f68fSopenharmony_ci goto err_out1; 12136881f68fSopenharmony_ci } 12146881f68fSopenharmony_ci 12156881f68fSopenharmony_ci if(opts.mountpoint == NULL) { 12166881f68fSopenharmony_ci printf("usage: %s [options] <mountpoint>\n", argv[0]); 12176881f68fSopenharmony_ci printf(" %s --help\n", argv[0]); 12186881f68fSopenharmony_ci ret = 1; 12196881f68fSopenharmony_ci goto err_out1; 12206881f68fSopenharmony_ci } 12216881f68fSopenharmony_ci 12226881f68fSopenharmony_ci if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1) 12236881f68fSopenharmony_ci return 1; 12246881f68fSopenharmony_ci 12256881f68fSopenharmony_ci lo.debug = opts.debug; 12266881f68fSopenharmony_ci lo.root.refcount = 2; 12276881f68fSopenharmony_ci if (lo.source) { 12286881f68fSopenharmony_ci struct stat stat; 12296881f68fSopenharmony_ci int res; 12306881f68fSopenharmony_ci 12316881f68fSopenharmony_ci res = lstat(lo.source, &stat); 12326881f68fSopenharmony_ci if (res == -1) { 12336881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n", 12346881f68fSopenharmony_ci lo.source); 12356881f68fSopenharmony_ci exit(1); 12366881f68fSopenharmony_ci } 12376881f68fSopenharmony_ci if (!S_ISDIR(stat.st_mode)) { 12386881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "source is not a directory\n"); 12396881f68fSopenharmony_ci exit(1); 12406881f68fSopenharmony_ci } 12416881f68fSopenharmony_ci 12426881f68fSopenharmony_ci } else { 12436881f68fSopenharmony_ci lo.source = strdup("/"); 12446881f68fSopenharmony_ci if(!lo.source) { 12456881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); 12466881f68fSopenharmony_ci exit(1); 12476881f68fSopenharmony_ci } 12486881f68fSopenharmony_ci } 12496881f68fSopenharmony_ci if (!lo.timeout_set) { 12506881f68fSopenharmony_ci switch (lo.cache) { 12516881f68fSopenharmony_ci case CACHE_NEVER: 12526881f68fSopenharmony_ci lo.timeout = 0.0; 12536881f68fSopenharmony_ci break; 12546881f68fSopenharmony_ci 12556881f68fSopenharmony_ci case CACHE_NORMAL: 12566881f68fSopenharmony_ci lo.timeout = 1.0; 12576881f68fSopenharmony_ci break; 12586881f68fSopenharmony_ci 12596881f68fSopenharmony_ci case CACHE_ALWAYS: 12606881f68fSopenharmony_ci lo.timeout = 86400.0; 12616881f68fSopenharmony_ci break; 12626881f68fSopenharmony_ci } 12636881f68fSopenharmony_ci } else if (lo.timeout < 0) { 12646881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", 12656881f68fSopenharmony_ci lo.timeout); 12666881f68fSopenharmony_ci exit(1); 12676881f68fSopenharmony_ci } 12686881f68fSopenharmony_ci 12696881f68fSopenharmony_ci lo.root.fd = open(lo.source, O_PATH); 12706881f68fSopenharmony_ci if (lo.root.fd == -1) { 12716881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", 12726881f68fSopenharmony_ci lo.source); 12736881f68fSopenharmony_ci exit(1); 12746881f68fSopenharmony_ci } 12756881f68fSopenharmony_ci 12766881f68fSopenharmony_ci se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); 12776881f68fSopenharmony_ci if (se == NULL) 12786881f68fSopenharmony_ci goto err_out1; 12796881f68fSopenharmony_ci 12806881f68fSopenharmony_ci if (fuse_set_signal_handlers(se) != 0) 12816881f68fSopenharmony_ci goto err_out2; 12826881f68fSopenharmony_ci 12836881f68fSopenharmony_ci if (fuse_session_mount(se, opts.mountpoint) != 0) 12846881f68fSopenharmony_ci goto err_out3; 12856881f68fSopenharmony_ci 12866881f68fSopenharmony_ci fuse_daemonize(opts.foreground); 12876881f68fSopenharmony_ci 12886881f68fSopenharmony_ci /* Block until ctrl+c or fusermount -u */ 12896881f68fSopenharmony_ci if (opts.singlethread) 12906881f68fSopenharmony_ci ret = fuse_session_loop(se); 12916881f68fSopenharmony_ci else { 12926881f68fSopenharmony_ci config.clone_fd = opts.clone_fd; 12936881f68fSopenharmony_ci config.max_idle_threads = opts.max_idle_threads; 12946881f68fSopenharmony_ci ret = fuse_session_loop_mt(se, &config); 12956881f68fSopenharmony_ci } 12966881f68fSopenharmony_ci 12976881f68fSopenharmony_ci fuse_session_unmount(se); 12986881f68fSopenharmony_cierr_out3: 12996881f68fSopenharmony_ci fuse_remove_signal_handlers(se); 13006881f68fSopenharmony_cierr_out2: 13016881f68fSopenharmony_ci fuse_session_destroy(se); 13026881f68fSopenharmony_cierr_out1: 13036881f68fSopenharmony_ci free(opts.mountpoint); 13046881f68fSopenharmony_ci fuse_opt_free_args(&args); 13056881f68fSopenharmony_ci 13066881f68fSopenharmony_ci if (lo.root.fd >= 0) 13076881f68fSopenharmony_ci close(lo.root.fd); 13086881f68fSopenharmony_ci 13096881f68fSopenharmony_ci free(lo.source); 13106881f68fSopenharmony_ci return ret ? 1 : 0; 13116881f68fSopenharmony_ci} 1312