1 1.114 pho /* $NetBSD: refuse.c,v 1.114 2022/01/22 08:09:39 pho Exp $ */ 2 1.7 pooka 3 1.1 agc /* 4 1.1 agc * Copyright 2007 Alistair Crooks. All rights reserved. 5 1.83 pooka * Copyright 2007 Antti Kantee. All rights reserved. 6 1.1 agc * 7 1.1 agc * Redistribution and use in source and binary forms, with or without 8 1.1 agc * modification, are permitted provided that the following conditions 9 1.1 agc * are met: 10 1.1 agc * 1. Redistributions of source code must retain the above copyright 11 1.1 agc * notice, this list of conditions and the following disclaimer. 12 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 agc * notice, this list of conditions and the following disclaimer in the 14 1.1 agc * documentation and/or other materials provided with the distribution. 15 1.1 agc * 3. The name of the author may not be used to endorse or promote 16 1.1 agc * products derived from this software without specific prior written 17 1.1 agc * permission. 18 1.1 agc * 19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 1.1 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 1.1 agc * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 1.1 agc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 1.1 agc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 1.1 agc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 1.1 agc * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 1.1 agc */ 31 1.7 pooka 32 1.7 pooka #include <sys/cdefs.h> 33 1.7 pooka #if !defined(lint) 34 1.114 pho __RCSID("$NetBSD: refuse.c,v 1.114 2022/01/22 08:09:39 pho Exp $"); 35 1.7 pooka #endif /* !lint */ 36 1.7 pooka 37 1.81 pooka #include <sys/types.h> 38 1.81 pooka 39 1.25 pooka #include <assert.h> 40 1.1 agc #include <err.h> 41 1.1 agc #include <errno.h> 42 1.103 pho #include <fuse_internal.h> 43 1.98 pho #include <fuse_opt.h> 44 1.72 pooka #include <paths.h> 45 1.104 pho #include <puffs.h> 46 1.104 pho #include <stdbool.h> 47 1.98 pho #include <stddef.h> 48 1.81 pooka #include <stdio.h> 49 1.81 pooka #include <stdlib.h> 50 1.81 pooka #include <string.h> 51 1.78 pooka #include <unistd.h> 52 1.78 pooka #ifdef MULTITHREADED_REFUSE 53 1.77 pooka #include <pthread.h> 54 1.78 pooka #endif 55 1.1 agc 56 1.1 agc typedef uint64_t fuse_ino_t; 57 1.1 agc 58 1.98 pho struct refuse_config { 59 1.98 pho int debug; 60 1.98 pho char *fsname; 61 1.1 agc }; 62 1.1 agc 63 1.98 pho #define REFUSE_OPT(t, p, v) \ 64 1.98 pho { t, offsetof(struct refuse_config, p), v } 65 1.98 pho 66 1.98 pho static struct fuse_opt refuse_opts[] = { 67 1.98 pho REFUSE_OPT("debug" , debug , 1), 68 1.98 pho REFUSE_OPT("fsname=%s", fsname, 0), 69 1.98 pho FUSE_OPT_END 70 1.38 pooka }; 71 1.38 pooka 72 1.36 pooka struct puffs_fuse_dirh { 73 1.43 agc void *dbuf; 74 1.43 agc struct dirent *d; 75 1.43 agc 76 1.43 agc size_t reslen; 77 1.43 agc size_t bufsize; 78 1.36 pooka }; 79 1.36 pooka 80 1.43 agc struct refusenode { 81 1.43 agc struct fuse_file_info file_info; 82 1.43 agc struct puffs_fuse_dirh dirh; 83 1.43 agc int opencount; 84 1.43 agc int flags; 85 1.43 agc }; 86 1.30 pooka #define RN_ROOT 0x01 87 1.31 pooka #define RN_OPEN 0x02 /* XXX: could just use opencount */ 88 1.5 pooka 89 1.43 agc static int fuse_setattr(struct fuse *, struct puffs_node *, 90 1.43 agc const char *, const struct vattr *); 91 1.26 pooka 92 1.5 pooka static struct puffs_node * 93 1.5 pooka newrn(struct puffs_usermount *pu) 94 1.5 pooka { 95 1.5 pooka struct puffs_node *pn; 96 1.5 pooka struct refusenode *rn; 97 1.5 pooka 98 1.62 agc if ((rn = calloc(1, sizeof(*rn))) == NULL) { 99 1.62 agc err(EXIT_FAILURE, "newrn"); 100 1.62 agc } 101 1.5 pooka pn = puffs_pn_new(pu, rn); 102 1.5 pooka 103 1.5 pooka return pn; 104 1.5 pooka } 105 1.5 pooka 106 1.5 pooka static void 107 1.5 pooka nukern(struct puffs_node *pn) 108 1.5 pooka { 109 1.36 pooka struct refusenode *rn = pn->pn_data; 110 1.5 pooka 111 1.36 pooka free(rn->dirh.dbuf); 112 1.36 pooka free(rn); 113 1.5 pooka puffs_pn_put(pn); 114 1.5 pooka } 115 1.5 pooka 116 1.66 agc /* XXX - not threadsafe */ 117 1.1 agc static ino_t fakeino = 3; 118 1.1 agc 119 1.66 agc /***************** start of pthread context routines ************************/ 120 1.66 agc 121 1.21 pooka /* 122 1.66 agc * Notes on fuse_context: 123 1.66 agc * we follow fuse's lead and use the pthread specific information to hold 124 1.66 agc * a reference to the fuse_context structure for this thread. 125 1.21 pooka */ 126 1.78 pooka #ifdef MULTITHREADED_REFUSE 127 1.66 agc static pthread_mutex_t context_mutex = PTHREAD_MUTEX_INITIALIZER; 128 1.66 agc static pthread_key_t context_key; 129 1.80 pooka static unsigned long context_refc; 130 1.78 pooka #endif 131 1.66 agc 132 1.66 agc /* return the fuse_context struct related to this thread */ 133 1.66 agc struct fuse_context * 134 1.66 agc fuse_get_context(void) 135 1.66 agc { 136 1.78 pooka #ifdef MULTITHREADED_REFUSE 137 1.66 agc struct fuse_context *ctxt; 138 1.66 agc 139 1.66 agc if ((ctxt = pthread_getspecific(context_key)) == NULL) { 140 1.66 agc if ((ctxt = calloc(1, sizeof(struct fuse_context))) == NULL) { 141 1.80 pooka abort(); 142 1.66 agc } 143 1.66 agc pthread_setspecific(context_key, ctxt); 144 1.66 agc } 145 1.66 agc return ctxt; 146 1.78 pooka #else 147 1.78 pooka static struct fuse_context fcon; 148 1.78 pooka 149 1.78 pooka return &fcon; 150 1.78 pooka #endif 151 1.66 agc } 152 1.66 agc 153 1.66 agc /* used as a callback function */ 154 1.78 pooka #ifdef MULTITHREADED_REFUSE 155 1.66 agc static void 156 1.66 agc free_context(void *ctxt) 157 1.66 agc { 158 1.66 agc free(ctxt); 159 1.66 agc } 160 1.78 pooka #endif 161 1.66 agc 162 1.80 pooka /* 163 1.80 pooka * Create the pthread key. The reason for the complexity is to 164 1.80 pooka * enable use of multiple fuse instances within a single process. 165 1.80 pooka */ 166 1.66 agc static int 167 1.66 agc create_context_key(void) 168 1.66 agc { 169 1.78 pooka #ifdef MULTITHREADED_REFUSE 170 1.80 pooka int rv; 171 1.80 pooka 172 1.80 pooka rv = pthread_mutex_lock(&context_mutex); 173 1.80 pooka assert(rv == 0); 174 1.80 pooka 175 1.80 pooka if (context_refc == 0) { 176 1.66 agc if (pthread_key_create(&context_key, free_context) != 0) { 177 1.66 agc warnx("create_context_key: pthread_key_create failed"); 178 1.66 agc pthread_mutex_unlock(&context_mutex); 179 1.66 agc return 0; 180 1.66 agc } 181 1.66 agc } 182 1.66 agc context_refc += 1; 183 1.66 agc pthread_mutex_unlock(&context_mutex); 184 1.66 agc return 1; 185 1.78 pooka #else 186 1.78 pooka return 1; 187 1.78 pooka #endif 188 1.66 agc } 189 1.66 agc 190 1.113 pho /* struct fuse_context is potentially reused among different 191 1.113 pho * invocations of fuse_new() / fuse_destroy() pair. Clear its content 192 1.113 pho * on fuse_destroy() so that no dangling pointers remain in the 193 1.113 pho * context. */ 194 1.113 pho static void 195 1.113 pho clear_context(void) 196 1.113 pho { 197 1.113 pho struct fuse_context *ctx; 198 1.113 pho 199 1.113 pho ctx = fuse_get_context(); 200 1.113 pho memset(ctx, 0, sizeof(*ctx)); 201 1.113 pho } 202 1.113 pho 203 1.66 agc static void 204 1.66 agc delete_context_key(void) 205 1.66 agc { 206 1.78 pooka #ifdef MULTITHREADED_REFUSE 207 1.66 agc pthread_mutex_lock(&context_mutex); 208 1.80 pooka /* If we are the last fuse instances using the key, delete it */ 209 1.66 agc if (--context_refc == 0) { 210 1.66 agc free(pthread_getspecific(context_key)); 211 1.66 agc pthread_key_delete(context_key); 212 1.66 agc } 213 1.66 agc pthread_mutex_unlock(&context_mutex); 214 1.78 pooka #endif 215 1.66 agc } 216 1.66 agc 217 1.66 agc /* set the uid and gid of the calling process in the current fuse context */ 218 1.66 agc static void 219 1.66 agc set_fuse_context_uid_gid(const struct puffs_cred *cred) 220 1.66 agc { 221 1.66 agc struct fuse_context *fusectx; 222 1.66 agc uid_t uid; 223 1.66 agc gid_t gid; 224 1.66 agc 225 1.66 agc fusectx = fuse_get_context(); 226 1.66 agc if (puffs_cred_getuid(cred, &uid) == 0) { 227 1.66 agc fusectx->uid = uid; 228 1.66 agc } 229 1.66 agc if (puffs_cred_getgid(cred, &gid) == 0) { 230 1.66 agc fusectx->gid = gid; 231 1.66 agc } 232 1.66 agc } 233 1.66 agc 234 1.66 agc /* set the pid of the calling process in the current fuse context */ 235 1.66 agc static void 236 1.85 pooka set_fuse_context_pid(struct puffs_usermount *pu) 237 1.66 agc { 238 1.85 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 239 1.66 agc struct fuse_context *fusectx; 240 1.21 pooka 241 1.66 agc fusectx = fuse_get_context(); 242 1.76 pooka puffs_cc_getcaller(pcc, &fusectx->pid, NULL); 243 1.66 agc } 244 1.66 agc 245 1.66 agc /***************** end of pthread context routines ************************/ 246 1.62 agc 247 1.36 pooka #define DIR_CHUNKSIZE 4096 248 1.36 pooka static int 249 1.36 pooka fill_dirbuf(struct puffs_fuse_dirh *dh, const char *name, ino_t dino, 250 1.36 pooka uint8_t dtype) 251 1.36 pooka { 252 1.36 pooka 253 1.36 pooka /* initial? */ 254 1.36 pooka if (dh->bufsize == 0) { 255 1.65 agc if ((dh->dbuf = calloc(1, DIR_CHUNKSIZE)) == NULL) { 256 1.80 pooka abort(); 257 1.62 agc } 258 1.36 pooka dh->d = dh->dbuf; 259 1.36 pooka dh->reslen = dh->bufsize = DIR_CHUNKSIZE; 260 1.36 pooka } 261 1.21 pooka 262 1.62 agc if (puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen)) { 263 1.36 pooka return 0; 264 1.62 agc } 265 1.36 pooka 266 1.36 pooka /* try to increase buffer space */ 267 1.36 pooka dh->dbuf = realloc(dh->dbuf, dh->bufsize + DIR_CHUNKSIZE); 268 1.62 agc if (dh->dbuf == NULL) { 269 1.80 pooka abort(); 270 1.62 agc } 271 1.36 pooka dh->d = (void *)((uint8_t *)dh->dbuf + (dh->bufsize - dh->reslen)); 272 1.36 pooka dh->reslen += DIR_CHUNKSIZE; 273 1.36 pooka dh->bufsize += DIR_CHUNKSIZE; 274 1.36 pooka 275 1.36 pooka return !puffs_nextdent(&dh->d, name, dino, dtype, &dh->reslen); 276 1.36 pooka } 277 1.1 agc 278 1.36 pooka /* ARGSUSED3 */ 279 1.36 pooka /* XXX: I have no idea how "off" is supposed to be used */ 280 1.1 agc static int 281 1.4 pooka puffs_fuse_fill_dir(void *buf, const char *name, 282 1.114 pho const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags) 283 1.1 agc { 284 1.36 pooka struct puffs_fuse_dirh *deh = buf; 285 1.13 pooka ino_t dino; 286 1.1 agc uint8_t dtype; 287 1.1 agc 288 1.13 pooka if (stbuf == NULL) { 289 1.13 pooka dtype = DT_UNKNOWN; 290 1.13 pooka dino = fakeino++; 291 1.13 pooka } else { 292 1.106 pho dtype = (uint8_t)puffs_vtype2dt(puffs_mode2vt(stbuf->st_mode)); 293 1.13 pooka dino = stbuf->st_ino; 294 1.50 pooka 295 1.50 pooka /* 296 1.50 pooka * Some FUSE file systems like to always use 0 as the 297 1.50 pooka * inode number. Our readdir() doesn't like to show 298 1.50 pooka * directory entries with inode number 0 ==> workaround. 299 1.50 pooka */ 300 1.62 agc if (dino == 0) { 301 1.50 pooka dino = fakeino++; 302 1.62 agc } 303 1.13 pooka } 304 1.1 agc 305 1.36 pooka return fill_dirbuf(deh, name, dino, dtype); 306 1.4 pooka } 307 1.4 pooka 308 1.26 pooka /* ARGSUSED1 */ 309 1.26 pooka static int 310 1.26 pooka fuse_getattr(struct fuse *fuse, struct puffs_node *pn, const char *path, 311 1.26 pooka struct vattr *va) 312 1.26 pooka { 313 1.114 pho struct refusenode *rn = pn->pn_data; 314 1.114 pho struct fuse_file_info *fi = rn->opencount > 0 ? &rn->file_info : NULL; 315 1.26 pooka struct stat st; 316 1.26 pooka int ret; 317 1.26 pooka 318 1.26 pooka /* wrap up return code */ 319 1.74 pooka memset(&st, 0, sizeof(st)); 320 1.114 pho ret = fuse_fs_getattr_v30(fuse->fs, path, &st, fi); 321 1.26 pooka 322 1.26 pooka if (ret == 0) { 323 1.74 pooka if (st.st_blksize == 0) 324 1.74 pooka st.st_blksize = DEV_BSIZE; 325 1.26 pooka puffs_stat2vattr(va, &st); 326 1.26 pooka } 327 1.26 pooka 328 1.26 pooka return -ret; 329 1.26 pooka } 330 1.26 pooka 331 1.66 agc /* utility function to set various elements of the attribute */ 332 1.26 pooka static int 333 1.26 pooka fuse_setattr(struct fuse *fuse, struct puffs_node *pn, const char *path, 334 1.26 pooka const struct vattr *va) 335 1.26 pooka { 336 1.26 pooka struct refusenode *rn = pn->pn_data; 337 1.114 pho struct fuse_file_info *fi = rn->opencount > 0 ? &rn->file_info : NULL; 338 1.26 pooka mode_t mode; 339 1.26 pooka uid_t uid; 340 1.26 pooka gid_t gid; 341 1.26 pooka int error, ret; 342 1.26 pooka 343 1.26 pooka error = 0; 344 1.26 pooka 345 1.26 pooka mode = va->va_mode; 346 1.26 pooka uid = va->va_uid; 347 1.26 pooka gid = va->va_gid; 348 1.26 pooka 349 1.26 pooka if (mode != (mode_t)PUFFS_VNOVAL) { 350 1.114 pho ret = fuse_fs_chmod_v30(fuse->fs, path, mode, fi); 351 1.114 pho if (ret) 352 1.114 pho error = ret; 353 1.26 pooka } 354 1.26 pooka if (uid != (uid_t)PUFFS_VNOVAL || gid != (gid_t)PUFFS_VNOVAL) { 355 1.114 pho ret = fuse_fs_chown_v30(fuse->fs, path, uid, gid, fi); 356 1.114 pho if (ret) 357 1.114 pho error = ret; 358 1.26 pooka } 359 1.26 pooka if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL 360 1.114 pho || va->va_mtime.tv_sec != (long)PUFFS_VNOVAL) { 361 1.26 pooka 362 1.114 pho struct timespec tv[2]; 363 1.26 pooka 364 1.114 pho tv[0].tv_sec = va->va_atime.tv_sec; 365 1.114 pho tv[0].tv_nsec = va->va_atime.tv_nsec; 366 1.114 pho tv[1].tv_sec = va->va_mtime.tv_sec; 367 1.114 pho tv[1].tv_nsec = va->va_mtime.tv_nsec; 368 1.26 pooka 369 1.114 pho ret = fuse_fs_utimens_v30(fuse->fs, path, tv, fi); 370 1.26 pooka if (ret) 371 1.26 pooka error = ret; 372 1.26 pooka } 373 1.26 pooka if (va->va_size != (u_quad_t)PUFFS_VNOVAL) { 374 1.114 pho ret = fuse_fs_truncate_v30(fuse->fs, path, (off_t)va->va_size, fi); 375 1.26 pooka if (ret) 376 1.26 pooka error = ret; 377 1.26 pooka } 378 1.26 pooka /* XXX: no reflection with reality */ 379 1.26 pooka puffs_setvattr(&pn->pn_va, va); 380 1.26 pooka 381 1.26 pooka return -error; 382 1.26 pooka 383 1.26 pooka } 384 1.26 pooka 385 1.26 pooka static int 386 1.26 pooka fuse_newnode(struct puffs_usermount *pu, const char *path, 387 1.71 pooka const struct vattr *va, struct fuse_file_info *fi, 388 1.71 pooka struct puffs_newinfo *pni, struct puffs_node **pn_new) 389 1.26 pooka { 390 1.26 pooka struct puffs_node *pn; 391 1.26 pooka struct refusenode *rn; 392 1.66 agc struct vattr newva; 393 1.66 agc struct fuse *fuse; 394 1.26 pooka 395 1.46 pooka fuse = puffs_getspecific(pu); 396 1.26 pooka 397 1.26 pooka /* fix up nodes */ 398 1.26 pooka pn = newrn(pu); 399 1.26 pooka if (pn == NULL) { 400 1.26 pooka if (va->va_type == VDIR) { 401 1.114 pho fuse_fs_rmdir(fuse->fs, path); 402 1.26 pooka } else { 403 1.114 pho fuse_fs_unlink(fuse->fs, path); 404 1.26 pooka } 405 1.26 pooka return ENOMEM; 406 1.26 pooka } 407 1.26 pooka fuse_setattr(fuse, pn, path, va); 408 1.26 pooka if (fuse_getattr(fuse, pn, path, &newva) == 0) 409 1.26 pooka puffs_setvattr(&pn->pn_va, &newva); 410 1.26 pooka 411 1.26 pooka rn = pn->pn_data; 412 1.26 pooka if (fi) 413 1.26 pooka memcpy(&rn->file_info, fi, sizeof(struct fuse_file_info)); 414 1.26 pooka 415 1.71 pooka puffs_newinfo_setcookie(pni, pn); 416 1.71 pooka if (pn_new) 417 1.71 pooka *pn_new = pn; 418 1.26 pooka 419 1.26 pooka return 0; 420 1.26 pooka } 421 1.26 pooka 422 1.26 pooka 423 1.1 agc /* operation wrappers start here */ 424 1.1 agc 425 1.1 agc /* lookup the path */ 426 1.1 agc /* ARGSUSED1 */ 427 1.1 agc static int 428 1.85 pooka puffs_fuse_node_lookup(struct puffs_usermount *pu, void *opc, 429 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn) 430 1.1 agc { 431 1.12 pooka struct puffs_node *pn_res; 432 1.66 agc struct stat st; 433 1.1 agc struct fuse *fuse; 434 1.1 agc const char *path = PCNPATH(pcn); 435 1.66 agc int ret; 436 1.1 agc 437 1.46 pooka fuse = puffs_getspecific(pu); 438 1.62 agc 439 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 440 1.62 agc 441 1.114 pho ret = fuse_fs_getattr_v30(fuse->fs, path, &st, NULL); 442 1.1 agc if (ret != 0) { 443 1.18 pooka return -ret; 444 1.12 pooka } 445 1.12 pooka 446 1.12 pooka /* XXX: fiXXXme unconst */ 447 1.12 pooka pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp, 448 1.12 pooka __UNCONST(&pcn->pcn_po_full)); 449 1.12 pooka if (pn_res == NULL) { 450 1.12 pooka pn_res = newrn(pu); 451 1.12 pooka if (pn_res == NULL) 452 1.12 pooka return errno; 453 1.26 pooka puffs_stat2vattr(&pn_res->pn_va, &st); 454 1.1 agc } 455 1.12 pooka 456 1.71 pooka puffs_newinfo_setcookie(pni, pn_res); 457 1.71 pooka puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type); 458 1.71 pooka puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size); 459 1.71 pooka puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev); 460 1.12 pooka 461 1.12 pooka return 0; 462 1.1 agc } 463 1.1 agc 464 1.1 agc /* get attributes for the path name */ 465 1.1 agc /* ARGSUSED3 */ 466 1.1 agc static int 467 1.85 pooka puffs_fuse_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *va, 468 1.84 pooka const struct puffs_cred *pcr) 469 1.1 agc { 470 1.1 agc struct puffs_node *pn = opc; 471 1.1 agc struct fuse *fuse; 472 1.1 agc const char *path = PNPATH(pn); 473 1.1 agc 474 1.46 pooka fuse = puffs_getspecific(pu); 475 1.62 agc 476 1.66 agc set_fuse_context_uid_gid(pcr); 477 1.62 agc 478 1.26 pooka return fuse_getattr(fuse, pn, path, va); 479 1.1 agc } 480 1.1 agc 481 1.1 agc /* read the contents of the symbolic link */ 482 1.1 agc /* ARGSUSED2 */ 483 1.1 agc static int 484 1.85 pooka puffs_fuse_node_readlink(struct puffs_usermount *pu, void *opc, 485 1.1 agc const struct puffs_cred *cred, char *linkname, size_t *linklen) 486 1.1 agc { 487 1.1 agc struct puffs_node *pn = opc; 488 1.1 agc struct fuse *fuse; 489 1.13 pooka const char *path = PNPATH(pn), *p; 490 1.1 agc int ret; 491 1.1 agc 492 1.46 pooka fuse = puffs_getspecific(pu); 493 1.1 agc 494 1.66 agc set_fuse_context_uid_gid(cred); 495 1.62 agc 496 1.1 agc /* wrap up return code */ 497 1.114 pho ret = fuse_fs_readlink(fuse->fs, path, linkname, *linklen); 498 1.1 agc 499 1.1 agc if (ret == 0) { 500 1.43 agc p = memchr(linkname, '\0', *linklen); 501 1.13 pooka if (!p) 502 1.13 pooka return EINVAL; 503 1.13 pooka 504 1.106 pho *linklen = (size_t)(p - linkname); 505 1.1 agc } 506 1.1 agc 507 1.13 pooka return -ret; 508 1.1 agc } 509 1.1 agc 510 1.1 agc /* make the special node */ 511 1.1 agc /* ARGSUSED1 */ 512 1.1 agc static int 513 1.85 pooka puffs_fuse_node_mknod(struct puffs_usermount *pu, void *opc, 514 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 515 1.71 pooka const struct vattr *va) 516 1.1 agc { 517 1.1 agc struct fuse *fuse; 518 1.44 pooka mode_t mode; 519 1.1 agc const char *path = PCNPATH(pcn); 520 1.1 agc int ret; 521 1.1 agc 522 1.46 pooka fuse = puffs_getspecific(pu); 523 1.1 agc 524 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 525 1.62 agc 526 1.1 agc /* wrap up return code */ 527 1.44 pooka mode = puffs_addvtype2mode(va->va_mode, va->va_type); 528 1.114 pho ret = fuse_fs_mknod(fuse->fs, path, mode, va->va_rdev); 529 1.1 agc 530 1.1 agc if (ret == 0) { 531 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL); 532 1.1 agc } 533 1.1 agc 534 1.18 pooka return -ret; 535 1.1 agc } 536 1.1 agc 537 1.1 agc /* make a directory */ 538 1.1 agc /* ARGSUSED1 */ 539 1.1 agc static int 540 1.85 pooka puffs_fuse_node_mkdir(struct puffs_usermount *pu, void *opc, 541 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 542 1.71 pooka const struct vattr *va) 543 1.1 agc { 544 1.1 agc struct fuse *fuse; 545 1.1 agc mode_t mode = va->va_mode; 546 1.1 agc const char *path = PCNPATH(pcn); 547 1.1 agc int ret; 548 1.1 agc 549 1.46 pooka fuse = puffs_getspecific(pu); 550 1.62 agc 551 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 552 1.62 agc 553 1.1 agc /* wrap up return code */ 554 1.114 pho ret = fuse_fs_mkdir(fuse->fs, path, mode); 555 1.1 agc 556 1.1 agc if (ret == 0) { 557 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL); 558 1.1 agc } 559 1.1 agc 560 1.18 pooka return -ret; 561 1.1 agc } 562 1.1 agc 563 1.21 pooka /* 564 1.21 pooka * create a regular file 565 1.21 pooka * 566 1.21 pooka * since linux/fuse sports using mknod for creating regular files 567 1.21 pooka * instead of having a separate call for it in some versions, if 568 1.21 pooka * we don't have create, just jump to op->mknod. 569 1.21 pooka */ 570 1.16 pooka /*ARGSUSED1*/ 571 1.16 pooka static int 572 1.85 pooka puffs_fuse_node_create(struct puffs_usermount *pu, void *opc, 573 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 574 1.71 pooka const struct vattr *va) 575 1.16 pooka { 576 1.16 pooka struct fuse *fuse; 577 1.16 pooka struct fuse_file_info fi; 578 1.71 pooka struct puffs_node *pn; 579 1.16 pooka mode_t mode = va->va_mode; 580 1.16 pooka const char *path = PCNPATH(pcn); 581 1.31 pooka int ret, created; 582 1.16 pooka 583 1.46 pooka fuse = puffs_getspecific(pu); 584 1.21 pooka 585 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 586 1.62 agc 587 1.97 pho memset(&fi, 0, sizeof(fi)); 588 1.114 pho /* In puffs "create" and "open" are two separate operations 589 1.114 pho * with atomicity achieved by locking the parent vnode. In 590 1.114 pho * fuse, on the other hand, "create" is actually a 591 1.114 pho * create-and-open-atomically and the open flags (O_RDWR, 592 1.114 pho * O_APPEND, ...) are passed via fi.flags. So the only way to 593 1.114 pho * emulate the fuse semantics is to open the file with dummy 594 1.114 pho * flags and then immediately close it. 595 1.114 pho * 596 1.114 pho * You might think that we could simply use fuse->op.mknod all 597 1.114 pho * the time but no, that's not possible because most file 598 1.114 pho * systems nowadays expect op.mknod to be called only for 599 1.114 pho * non-regular files and many don't even support it. */ 600 1.31 pooka created = 0; 601 1.114 pho fi.flags = O_WRONLY | O_CREAT | O_EXCL; 602 1.114 pho ret = fuse_fs_create(fuse->fs, path, mode | S_IFREG, &fi); 603 1.114 pho if (ret == 0) { 604 1.114 pho created = 1; 605 1.114 pho } 606 1.114 pho else if (ret == -ENOSYS) { 607 1.114 pho ret = fuse_fs_mknod(fuse->fs, path, mode | S_IFREG, 0); 608 1.16 pooka } 609 1.16 pooka 610 1.16 pooka if (ret == 0) { 611 1.71 pooka ret = fuse_newnode(pu, path, va, &fi, pni, &pn); 612 1.31 pooka 613 1.31 pooka /* sweet.. create also open the file */ 614 1.114 pho if (created) { 615 1.97 pho struct refusenode *rn = pn->pn_data; 616 1.97 pho /* The return value of op.release is expected to be 617 1.97 pho * discarded. */ 618 1.114 pho (void)fuse_fs_release(fuse->fs, path, &rn->file_info); 619 1.31 pooka } 620 1.16 pooka } 621 1.16 pooka 622 1.18 pooka return -ret; 623 1.16 pooka } 624 1.16 pooka 625 1.1 agc /* remove the directory entry */ 626 1.23 pooka /* ARGSUSED1 */ 627 1.1 agc static int 628 1.85 pooka puffs_fuse_node_remove(struct puffs_usermount *pu, void *opc, void *targ, 629 1.1 agc const struct puffs_cn *pcn) 630 1.1 agc { 631 1.23 pooka struct puffs_node *pn_targ = targ; 632 1.1 agc struct fuse *fuse; 633 1.23 pooka const char *path = PNPATH(pn_targ); 634 1.1 agc int ret; 635 1.1 agc 636 1.46 pooka fuse = puffs_getspecific(pu); 637 1.62 agc 638 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 639 1.62 agc 640 1.1 agc /* wrap up return code */ 641 1.114 pho ret = fuse_fs_unlink(fuse->fs, path); 642 1.1 agc 643 1.18 pooka return -ret; 644 1.1 agc } 645 1.1 agc 646 1.1 agc /* remove the directory */ 647 1.1 agc /* ARGSUSED1 */ 648 1.1 agc static int 649 1.85 pooka puffs_fuse_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ, 650 1.1 agc const struct puffs_cn *pcn) 651 1.1 agc { 652 1.23 pooka struct puffs_node *pn_targ = targ; 653 1.1 agc struct fuse *fuse; 654 1.23 pooka const char *path = PNPATH(pn_targ); 655 1.1 agc int ret; 656 1.1 agc 657 1.46 pooka fuse = puffs_getspecific(pu); 658 1.62 agc 659 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 660 1.62 agc 661 1.1 agc /* wrap up return code */ 662 1.114 pho ret = fuse_fs_rmdir(fuse->fs, path); 663 1.1 agc 664 1.18 pooka return -ret; 665 1.1 agc } 666 1.1 agc 667 1.1 agc /* create a symbolic link */ 668 1.1 agc /* ARGSUSED1 */ 669 1.1 agc static int 670 1.85 pooka puffs_fuse_node_symlink(struct puffs_usermount *pu, void *opc, 671 1.71 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 672 1.71 pooka const struct vattr *va, const char *link_target) 673 1.1 agc { 674 1.1 agc struct fuse *fuse; 675 1.1 agc const char *path = PCNPATH(pcn_src); 676 1.1 agc int ret; 677 1.1 agc 678 1.46 pooka fuse = puffs_getspecific(pu); 679 1.62 agc 680 1.69 pooka set_fuse_context_uid_gid(pcn_src->pcn_cred); 681 1.62 agc 682 1.1 agc /* wrap up return code */ 683 1.114 pho ret = fuse_fs_symlink(fuse->fs, link_target, path); 684 1.1 agc 685 1.1 agc if (ret == 0) { 686 1.71 pooka ret = fuse_newnode(pu, path, va, NULL, pni, NULL); 687 1.1 agc } 688 1.1 agc 689 1.18 pooka return -ret; 690 1.1 agc } 691 1.1 agc 692 1.1 agc /* rename a directory entry */ 693 1.1 agc /* ARGSUSED1 */ 694 1.1 agc static int 695 1.85 pooka puffs_fuse_node_rename(struct puffs_usermount *pu, void *opc, void *src, 696 1.1 agc const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 697 1.1 agc const struct puffs_cn *pcn_targ) 698 1.1 agc { 699 1.1 agc struct fuse *fuse; 700 1.24 pooka const char *path_src = PCNPATH(pcn_src); 701 1.24 pooka const char *path_dest = PCNPATH(pcn_targ); 702 1.1 agc int ret; 703 1.1 agc 704 1.46 pooka fuse = puffs_getspecific(pu); 705 1.62 agc 706 1.69 pooka set_fuse_context_uid_gid(pcn_targ->pcn_cred); 707 1.62 agc 708 1.114 pho ret = fuse_fs_rename_v30(fuse->fs, path_src, path_dest, 0); 709 1.1 agc 710 1.18 pooka return -ret; 711 1.1 agc } 712 1.1 agc 713 1.1 agc /* create a link in the file system */ 714 1.1 agc /* ARGSUSED1 */ 715 1.1 agc static int 716 1.85 pooka puffs_fuse_node_link(struct puffs_usermount *pu, void *opc, void *targ, 717 1.1 agc const struct puffs_cn *pcn) 718 1.1 agc { 719 1.1 agc struct puffs_node *pn = targ; 720 1.1 agc struct fuse *fuse; 721 1.1 agc int ret; 722 1.1 agc 723 1.46 pooka fuse = puffs_getspecific(pu); 724 1.62 agc 725 1.69 pooka set_fuse_context_uid_gid(pcn->pcn_cred); 726 1.62 agc 727 1.1 agc /* wrap up return code */ 728 1.114 pho ret = fuse_fs_link(fuse->fs, PNPATH(pn), PCNPATH(pcn)); 729 1.1 agc 730 1.18 pooka return -ret; 731 1.1 agc } 732 1.1 agc 733 1.1 agc /* 734 1.19 pooka * fuse's regular interface provides chmod(), chown(), utimes() 735 1.19 pooka * and truncate() + some variations, so try to fit the square block 736 1.19 pooka * in the circle hole and the circle block .... something like that 737 1.7 pooka */ 738 1.1 agc /* ARGSUSED3 */ 739 1.1 agc static int 740 1.85 pooka puffs_fuse_node_setattr(struct puffs_usermount *pu, void *opc, 741 1.84 pooka const struct vattr *va, const struct puffs_cred *pcr) 742 1.1 agc { 743 1.1 agc struct puffs_node *pn = opc; 744 1.1 agc struct fuse *fuse; 745 1.1 agc const char *path = PNPATH(pn); 746 1.1 agc 747 1.46 pooka fuse = puffs_getspecific(pu); 748 1.1 agc 749 1.66 agc set_fuse_context_uid_gid(pcr); 750 1.62 agc 751 1.26 pooka return fuse_setattr(fuse, pn, path, va); 752 1.1 agc } 753 1.1 agc 754 1.108 pho static int 755 1.108 pho puffs_fuse_node_pathconf(struct puffs_usermount *pu, void *opc, 756 1.108 pho int name, __register_t *retval) 757 1.108 pho { 758 1.108 pho /* Returning EINVAL for pathconf(2) means that this filesystem 759 1.108 pho * does not support an association of the given name with the 760 1.108 pho * file. This is necessary because the default error code 761 1.108 pho * returned by the puffs kernel module (ENOTSUPP) is not 762 1.108 pho * suitable for an errno from pathconf(2), and "ls -l" 763 1.108 pho * complains about it. */ 764 1.108 pho return EINVAL; 765 1.108 pho } 766 1.108 pho 767 1.1 agc /* ARGSUSED2 */ 768 1.1 agc static int 769 1.85 pooka puffs_fuse_node_open(struct puffs_usermount *pu, void *opc, int mode, 770 1.84 pooka const struct puffs_cred *cred) 771 1.1 agc { 772 1.1 agc struct puffs_node *pn = opc; 773 1.5 pooka struct refusenode *rn = pn->pn_data; 774 1.31 pooka struct fuse_file_info *fi = &rn->file_info; 775 1.1 agc struct fuse *fuse; 776 1.1 agc const char *path = PNPATH(pn); 777 1.114 pho int ret; 778 1.1 agc 779 1.46 pooka fuse = puffs_getspecific(pu); 780 1.1 agc 781 1.66 agc set_fuse_context_uid_gid(cred); 782 1.62 agc 783 1.30 pooka /* if open, don't open again, lest risk nuking file private info */ 784 1.31 pooka if (rn->flags & RN_OPEN) { 785 1.31 pooka rn->opencount++; 786 1.1 agc return 0; 787 1.31 pooka } 788 1.1 agc 789 1.37 pooka /* OFLAGS(), need to convert FREAD/FWRITE to O_RD/WR */ 790 1.37 pooka fi->flags = (mode & ~(O_CREAT | O_EXCL | O_TRUNC)) - 1; 791 1.37 pooka 792 1.30 pooka if (pn->pn_va.va_type == VDIR) { 793 1.114 pho ret = fuse_fs_opendir(fuse->fs, path, fi); 794 1.30 pooka } else { 795 1.114 pho ret = fuse_fs_open(fuse->fs, path, fi); 796 1.30 pooka } 797 1.1 agc 798 1.114 pho if (ret == 0) { 799 1.114 pho rn->flags |= RN_OPEN; 800 1.114 pho rn->opencount++; 801 1.114 pho } 802 1.1 agc 803 1.114 pho return -ret; 804 1.1 agc } 805 1.1 agc 806 1.31 pooka /* ARGSUSED2 */ 807 1.31 pooka static int 808 1.85 pooka puffs_fuse_node_close(struct puffs_usermount *pu, void *opc, int fflag, 809 1.84 pooka const struct puffs_cred *pcr) 810 1.31 pooka { 811 1.31 pooka struct puffs_node *pn = opc; 812 1.31 pooka struct refusenode *rn = pn->pn_data; 813 1.31 pooka struct fuse *fuse; 814 1.31 pooka struct fuse_file_info *fi; 815 1.31 pooka const char *path = PNPATH(pn); 816 1.31 pooka int ret; 817 1.31 pooka 818 1.46 pooka fuse = puffs_getspecific(pu); 819 1.31 pooka fi = &rn->file_info; 820 1.31 pooka ret = 0; 821 1.31 pooka 822 1.66 agc set_fuse_context_uid_gid(pcr); 823 1.62 agc 824 1.31 pooka if (rn->flags & RN_OPEN) { 825 1.31 pooka if (pn->pn_va.va_type == VDIR) { 826 1.114 pho ret = fuse_fs_releasedir(fuse->fs, path, fi); 827 1.31 pooka } else { 828 1.114 pho ret = fuse_fs_release(fuse->fs, path, fi); 829 1.31 pooka } 830 1.31 pooka } 831 1.31 pooka rn->flags &= ~RN_OPEN; 832 1.31 pooka rn->opencount--; 833 1.31 pooka 834 1.31 pooka return ret; 835 1.31 pooka } 836 1.31 pooka 837 1.1 agc /* read some more from the file */ 838 1.1 agc /* ARGSUSED5 */ 839 1.1 agc static int 840 1.85 pooka puffs_fuse_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf, 841 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr, 842 1.1 agc int ioflag) 843 1.1 agc { 844 1.1 agc struct puffs_node *pn = opc; 845 1.5 pooka struct refusenode *rn = pn->pn_data; 846 1.1 agc struct fuse *fuse; 847 1.1 agc const char *path = PNPATH(pn); 848 1.25 pooka size_t maxread; 849 1.1 agc int ret; 850 1.1 agc 851 1.46 pooka fuse = puffs_getspecific(pu); 852 1.1 agc 853 1.66 agc set_fuse_context_uid_gid(pcr); 854 1.62 agc 855 1.25 pooka maxread = *resid; 856 1.106 pho if (maxread > (size_t)((off_t)pn->pn_va.va_size - offset)) { 857 1.26 pooka /*LINTED*/ 858 1.106 pho maxread = (size_t)((off_t)pn->pn_va.va_size - offset); 859 1.26 pooka } 860 1.25 pooka if (maxread == 0) 861 1.25 pooka return 0; 862 1.25 pooka 863 1.114 pho ret = fuse_fs_read(fuse->fs, path, (char *)buf, maxread, offset, 864 1.114 pho &rn->file_info); 865 1.1 agc 866 1.1 agc if (ret > 0) { 867 1.106 pho *resid -= (size_t)ret; 868 1.16 pooka ret = 0; 869 1.1 agc } 870 1.1 agc 871 1.16 pooka return -ret; 872 1.1 agc } 873 1.1 agc 874 1.1 agc /* write to the file */ 875 1.1 agc /* ARGSUSED0 */ 876 1.1 agc static int 877 1.85 pooka puffs_fuse_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf, 878 1.1 agc off_t offset, size_t *resid, const struct puffs_cred *pcr, 879 1.1 agc int ioflag) 880 1.1 agc { 881 1.1 agc struct puffs_node *pn = opc; 882 1.8 pooka struct refusenode *rn = pn->pn_data; 883 1.1 agc struct fuse *fuse; 884 1.1 agc const char *path = PNPATH(pn); 885 1.1 agc int ret; 886 1.1 agc 887 1.46 pooka fuse = puffs_getspecific(pu); 888 1.1 agc 889 1.66 agc set_fuse_context_uid_gid(pcr); 890 1.62 agc 891 1.17 pooka if (ioflag & PUFFS_IO_APPEND) 892 1.106 pho offset = (off_t)pn->pn_va.va_size; 893 1.17 pooka 894 1.114 pho ret = fuse_fs_write(fuse->fs, path, (char *)buf, *resid, offset, 895 1.114 pho &rn->file_info); 896 1.1 agc 897 1.96 tron if (ret >= 0) { 898 1.90 lukem if ((uint64_t)(offset + ret) > pn->pn_va.va_size) 899 1.106 pho pn->pn_va.va_size = (u_quad_t)(offset + ret); 900 1.106 pho *resid -= (size_t)ret; 901 1.96 tron ret = (*resid == 0) ? 0 : ENOSPC; 902 1.96 tron } else { 903 1.96 tron ret = -ret; 904 1.1 agc } 905 1.1 agc 906 1.96 tron return ret; 907 1.1 agc } 908 1.1 agc 909 1.1 agc 910 1.1 agc /* ARGSUSED3 */ 911 1.1 agc static int 912 1.85 pooka puffs_fuse_node_readdir(struct puffs_usermount *pu, void *opc, 913 1.85 pooka struct dirent *dent, off_t *readoff, size_t *reslen, 914 1.85 pooka const struct puffs_cred *pcr, int *eofflag, 915 1.85 pooka off_t *cookies, size_t *ncookies) 916 1.1 agc { 917 1.1 agc struct puffs_node *pn = opc; 918 1.8 pooka struct refusenode *rn = pn->pn_data; 919 1.43 agc struct puffs_fuse_dirh *dirh; 920 1.43 agc struct fuse *fuse; 921 1.41 agc struct dirent *fromdent; 922 1.1 agc const char *path = PNPATH(pn); 923 1.1 agc int ret; 924 1.1 agc 925 1.46 pooka fuse = puffs_getspecific(pu); 926 1.1 agc 927 1.66 agc set_fuse_context_uid_gid(pcr); 928 1.62 agc 929 1.36 pooka if (pn->pn_va.va_type != VDIR) 930 1.36 pooka return ENOTDIR; 931 1.36 pooka 932 1.36 pooka dirh = &rn->dirh; 933 1.36 pooka 934 1.36 pooka /* 935 1.36 pooka * if we are starting from the beginning, slurp entire directory 936 1.36 pooka * into our buffers 937 1.36 pooka */ 938 1.36 pooka if (*readoff == 0) { 939 1.36 pooka /* free old buffers */ 940 1.36 pooka free(dirh->dbuf); 941 1.36 pooka memset(dirh, 0, sizeof(struct puffs_fuse_dirh)); 942 1.36 pooka 943 1.114 pho ret = fuse_fs_readdir_v30( 944 1.114 pho fuse->fs, path, dirh, puffs_fuse_fill_dir, 945 1.114 pho 0, &rn->file_info, (enum fuse_readdir_flags)0); 946 1.114 pho 947 1.36 pooka if (ret) 948 1.36 pooka return -ret; 949 1.35 pooka } 950 1.35 pooka 951 1.95 manu /* Both op.readdir and op.getdir read full directory */ 952 1.95 manu *eofflag = 1; 953 1.95 manu 954 1.36 pooka /* now, stuff results into the kernel buffers */ 955 1.91 lukem while (*readoff < (off_t)(dirh->bufsize - dirh->reslen)) { 956 1.36 pooka /*LINTED*/ 957 1.36 pooka fromdent = (struct dirent *)((uint8_t *)dirh->dbuf + *readoff); 958 1.36 pooka 959 1.36 pooka if (*reslen < _DIRENT_SIZE(fromdent)) 960 1.36 pooka break; 961 1.36 pooka 962 1.36 pooka memcpy(dent, fromdent, _DIRENT_SIZE(fromdent)); 963 1.106 pho *readoff += (off_t)_DIRENT_SIZE(fromdent); 964 1.36 pooka *reslen -= _DIRENT_SIZE(fromdent); 965 1.1 agc 966 1.36 pooka dent = _DIRENT_NEXT(dent); 967 1.1 agc } 968 1.1 agc 969 1.36 pooka return 0; 970 1.1 agc } 971 1.1 agc 972 1.26 pooka /* ARGSUSED */ 973 1.26 pooka static int 974 1.85 pooka puffs_fuse_node_reclaim(struct puffs_usermount *pu, void *opc) 975 1.26 pooka { 976 1.26 pooka struct puffs_node *pn = opc; 977 1.3 pooka 978 1.5 pooka nukern(pn); 979 1.26 pooka return 0; 980 1.3 pooka } 981 1.3 pooka 982 1.1 agc /* ARGSUSED1 */ 983 1.1 agc static int 984 1.85 pooka puffs_fuse_fs_unmount(struct puffs_usermount *pu, int flags) 985 1.1 agc { 986 1.1 agc struct fuse *fuse; 987 1.1 agc 988 1.46 pooka fuse = puffs_getspecific(pu); 989 1.114 pho fuse_fs_destroy(fuse->fs); 990 1.1 agc return 0; 991 1.1 agc } 992 1.1 agc 993 1.1 agc /* ARGSUSED0 */ 994 1.1 agc static int 995 1.85 pooka puffs_fuse_fs_sync(struct puffs_usermount *pu, int flags, 996 1.84 pooka const struct puffs_cred *cr) 997 1.1 agc { 998 1.66 agc set_fuse_context_uid_gid(cr); 999 1.1 agc return 0; 1000 1.1 agc } 1001 1.1 agc 1002 1.1 agc /* ARGSUSED2 */ 1003 1.1 agc static int 1004 1.101 christos puffs_fuse_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb) 1005 1.1 agc { 1006 1.1 agc struct fuse *fuse; 1007 1.1 agc int ret; 1008 1.101 christos struct statvfs sb; 1009 1.1 agc 1010 1.114 pho /* fuse_fs_statfs() is special: it returns 0 even if the 1011 1.114 pho * filesystem doesn't support statfs. So clear the struct 1012 1.114 pho * before calling it. */ 1013 1.114 pho memset(&sb, 0, sizeof(sb)); 1014 1.114 pho 1015 1.46 pooka fuse = puffs_getspecific(pu); 1016 1.114 pho ret = fuse_fs_statfs(fuse->fs, PNPATH(puffs_getroot(pu)), &sb); 1017 1.114 pho 1018 1.114 pho if (ret == 0) 1019 1.114 pho statvfs_to_puffs_statvfs(&sb, svfsb); 1020 1.1 agc 1021 1.88 pooka return -ret; 1022 1.1 agc } 1023 1.1 agc 1024 1.114 pho /* End of puffs_fuse operations */ 1025 1.1 agc 1026 1.114 pho struct fuse * 1027 1.114 pho __fuse_setup(int argc, char* argv[], 1028 1.114 pho const void* op, int op_version, void* user_data, 1029 1.114 pho struct fuse_cmdline_opts* opts) 1030 1.1 agc { 1031 1.98 pho struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 1032 1.114 pho struct fuse *fuse = NULL; 1033 1.98 pho 1034 1.98 pho /* parse low-level options */ 1035 1.114 pho if (fuse_parse_cmdline_v30(&args, opts) != 0) 1036 1.114 pho return NULL; 1037 1.98 pho 1038 1.114 pho if (opts->show_version) { 1039 1.98 pho fuse_lowlevel_version(); 1040 1.98 pho goto free_args; 1041 1.98 pho } 1042 1.98 pho 1043 1.114 pho if (opts->show_help) { 1044 1.114 pho switch (opts->show_help) { 1045 1.112 pho case REFUSE_SHOW_HELP_FULL: 1046 1.112 pho if (args.argv[0] != NULL && args.argv[0][0] != '\0') { 1047 1.112 pho /* argv[0] being empty means that the application doesn't 1048 1.112 pho * want us to print the usage string. 1049 1.112 pho */ 1050 1.112 pho printf("Usage: %s [options] mountpoint\n\n", args.argv[0]); 1051 1.112 pho } 1052 1.112 pho break; 1053 1.112 pho case REFUSE_SHOW_HELP_NO_HEADER: 1054 1.112 pho break; 1055 1.98 pho } 1056 1.98 pho fuse_cmdline_help(); 1057 1.98 pho goto free_args; 1058 1.98 pho } 1059 1.98 pho 1060 1.114 pho if (opts->mountpoint == NULL) { 1061 1.98 pho fprintf(stderr, "fuse: no mountpoint specified\n"); 1062 1.98 pho goto free_args; 1063 1.98 pho } 1064 1.38 pooka 1065 1.114 pho if (opts->debug) { 1066 1.114 pho if (fuse_opt_add_arg(&args, "-odebug") != 0) 1067 1.98 pho goto free_args; 1068 1.98 pho } 1069 1.38 pooka 1070 1.114 pho fuse = __fuse_new(&args, op, op_version, user_data); 1071 1.114 pho if (fuse == NULL) 1072 1.98 pho goto free_args; 1073 1.98 pho 1074 1.114 pho if (fuse_daemonize(opts->foreground) != 0) 1075 1.114 pho goto destroy; 1076 1.114 pho 1077 1.114 pho if (fuse_mount_v30(fuse, opts->mountpoint) != 0) 1078 1.114 pho goto destroy; 1079 1.98 pho 1080 1.114 pho if (__fuse_set_signal_handlers(fuse) != 0) { 1081 1.114 pho warn("%s: Failed to set signal handlers", __func__); 1082 1.98 pho goto destroy; 1083 1.98 pho } 1084 1.98 pho 1085 1.114 pho goto done; 1086 1.98 pho 1087 1.98 pho destroy: 1088 1.114 pho fuse_destroy_v30(fuse); 1089 1.114 pho fuse = NULL; 1090 1.98 pho free_args: 1091 1.114 pho free(opts->mountpoint); 1092 1.114 pho done: 1093 1.114 pho fuse_opt_free_args(&args); 1094 1.114 pho return fuse; 1095 1.114 pho } 1096 1.114 pho 1097 1.114 pho void 1098 1.114 pho __fuse_teardown(struct fuse* fuse) 1099 1.114 pho { 1100 1.114 pho if (__fuse_remove_signal_handlers(fuse) != 0) 1101 1.114 pho warn("%s: Failed to restore signal handlers", __func__); 1102 1.114 pho 1103 1.114 pho fuse_unmount_v30(fuse); 1104 1.114 pho } 1105 1.114 pho 1106 1.114 pho /* ARGSUSED3 */ 1107 1.114 pho int 1108 1.114 pho __fuse_main(int argc, char **argv, const void *op, 1109 1.114 pho int op_version, void *user_data) 1110 1.114 pho { 1111 1.114 pho struct fuse_cmdline_opts opts; 1112 1.114 pho struct fuse *fuse; 1113 1.114 pho int rv; 1114 1.114 pho 1115 1.114 pho fuse = __fuse_setup(argc, argv, op, op_version, user_data, &opts); 1116 1.114 pho if (fuse == NULL) 1117 1.114 pho return -1; 1118 1.114 pho 1119 1.114 pho rv = fuse_loop(fuse); 1120 1.114 pho 1121 1.114 pho __fuse_teardown(fuse); 1122 1.114 pho 1123 1.98 pho free(opts.mountpoint); 1124 1.98 pho return rv; 1125 1.38 pooka } 1126 1.38 pooka 1127 1.114 pho int __fuse_mount(struct fuse *fuse, const char *mountpoint) 1128 1.38 pooka { 1129 1.98 pho struct puffs_pathobj *po_root; 1130 1.98 pho struct puffs_node *pn_root; 1131 1.98 pho struct refusenode *rn_root; 1132 1.101 christos struct puffs_statvfs svfsb; 1133 1.98 pho 1134 1.98 pho pn_root = newrn(fuse->pu); 1135 1.98 pho puffs_setroot(fuse->pu, pn_root); 1136 1.98 pho rn_root = pn_root->pn_data; 1137 1.98 pho rn_root->flags |= RN_ROOT; 1138 1.98 pho 1139 1.98 pho po_root = puffs_getrootpathobj(fuse->pu); 1140 1.98 pho if ((po_root->po_path = strdup("/")) == NULL) 1141 1.98 pho err(1, "fuse_mount"); 1142 1.98 pho po_root->po_len = 1; 1143 1.98 pho puffs_path_buildhash(fuse->pu, po_root); 1144 1.98 pho 1145 1.98 pho /* sane defaults */ 1146 1.98 pho puffs_vattr_null(&pn_root->pn_va); 1147 1.98 pho pn_root->pn_va.va_type = VDIR; 1148 1.98 pho pn_root->pn_va.va_mode = 0755; 1149 1.107 pho /* It might be tempting to call op.getattr("/") here to 1150 1.107 pho * populate pn_root->pa_va, but that would mean invoking an 1151 1.107 pho * operation callback without initializing the filesystem. We 1152 1.107 pho * cannot call op.init() either, because that is supposed to 1153 1.107 pho * be called right before entering the main loop. */ 1154 1.38 pooka 1155 1.98 pho puffs_set_prepost(fuse->pu, set_fuse_context_pid, NULL); 1156 1.38 pooka 1157 1.98 pho puffs_zerostatvfs(&svfsb); 1158 1.98 pho if (puffs_mount(fuse->pu, mountpoint, MNT_NODEV | MNT_NOSUID, pn_root) == -1) { 1159 1.98 pho err(EXIT_FAILURE, "puffs_mount: directory \"%s\"", mountpoint); 1160 1.65 agc } 1161 1.48 agc 1162 1.98 pho return 0; 1163 1.98 pho } 1164 1.53 agc 1165 1.110 pho int fuse_daemonize(int foreground) 1166 1.98 pho { 1167 1.110 pho /* There is an impedance mismatch here: FUSE wants to 1168 1.110 pho * daemonize the process without any contexts but puffs wants 1169 1.110 pho * one. */ 1170 1.110 pho struct fuse *fuse = fuse_get_context()->fuse; 1171 1.110 pho 1172 1.110 pho if (!fuse) 1173 1.110 pho /* FUSE would probably allow this, but we cannot. */ 1174 1.110 pho errx(EXIT_FAILURE, 1175 1.110 pho "%s: librefuse doesn't allow calling" 1176 1.110 pho " this function before fuse_new().", __func__); 1177 1.110 pho 1178 1.110 pho if (!foreground) 1179 1.110 pho return puffs_daemon(fuse->pu, 0, 0); 1180 1.110 pho 1181 1.110 pho return 0; 1182 1.38 pooka } 1183 1.38 pooka 1184 1.38 pooka struct fuse * 1185 1.114 pho __fuse_new(struct fuse_args *args, const void *op, int op_version, void* user_data) 1186 1.38 pooka { 1187 1.98 pho struct refuse_config config; 1188 1.1 agc struct puffs_usermount *pu; 1189 1.66 agc struct fuse_context *fusectx; 1190 1.43 agc struct puffs_ops *pops; 1191 1.1 agc struct fuse *fuse; 1192 1.106 pho uint32_t puffs_flags; 1193 1.98 pho 1194 1.98 pho /* parse refuse options */ 1195 1.114 pho memset(&config, 0, sizeof(config)); 1196 1.98 pho if (fuse_opt_parse(args, &config, refuse_opts, NULL) == -1) 1197 1.98 pho return NULL; 1198 1.38 pooka 1199 1.65 agc if ((fuse = calloc(1, sizeof(*fuse))) == NULL) { 1200 1.65 agc err(EXIT_FAILURE, "fuse_new"); 1201 1.65 agc } 1202 1.38 pooka 1203 1.98 pho /* grab the pthread context key */ 1204 1.98 pho if (!create_context_key()) { 1205 1.98 pho free(config.fsname); 1206 1.98 pho free(fuse); 1207 1.98 pho return NULL; 1208 1.98 pho } 1209 1.98 pho 1210 1.114 pho /* Create the base filesystem layer. */ 1211 1.114 pho fuse->fs = __fuse_fs_new(op, op_version, user_data); 1212 1.114 pho 1213 1.66 agc fusectx = fuse_get_context(); 1214 1.66 agc fusectx->fuse = fuse; 1215 1.66 agc fusectx->uid = 0; 1216 1.66 agc fusectx->gid = 0; 1217 1.66 agc fusectx->pid = 0; 1218 1.114 pho fusectx->private_data = user_data; 1219 1.38 pooka 1220 1.1 agc /* initialise the puffs operations structure */ 1221 1.1 agc PUFFSOP_INIT(pops); 1222 1.1 agc 1223 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, sync); 1224 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, statvfs); 1225 1.1 agc PUFFSOP_SET(pops, puffs_fuse, fs, unmount); 1226 1.1 agc 1227 1.2 pooka /* 1228 1.2 pooka * XXX: all of these don't possibly need to be 1229 1.2 pooka * unconditionally set 1230 1.2 pooka */ 1231 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, lookup); 1232 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, getattr); 1233 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, setattr); 1234 1.108 pho PUFFSOP_SET(pops, puffs_fuse, node, pathconf); 1235 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readdir); 1236 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, readlink); 1237 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mknod); 1238 1.16 pooka PUFFSOP_SET(pops, puffs_fuse, node, create); 1239 1.15 pooka PUFFSOP_SET(pops, puffs_fuse, node, remove); 1240 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, mkdir); 1241 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rmdir); 1242 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, symlink); 1243 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, rename); 1244 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, link); 1245 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, open); 1246 1.31 pooka PUFFSOP_SET(pops, puffs_fuse, node, close); 1247 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, read); 1248 1.1 agc PUFFSOP_SET(pops, puffs_fuse, node, write); 1249 1.3 pooka PUFFSOP_SET(pops, puffs_fuse, node, reclaim); 1250 1.1 agc 1251 1.98 pho puffs_flags = PUFFS_FLAG_BUILDPATH 1252 1.98 pho | PUFFS_FLAG_HASHPATH 1253 1.98 pho | PUFFS_KFLAG_NOCACHE; 1254 1.98 pho if (config.debug) 1255 1.98 pho puffs_flags |= PUFFS_FLAG_OPDUMP; 1256 1.53 agc 1257 1.98 pho pu = puffs_init(pops, _PATH_PUFFS, config.fsname, fuse, puffs_flags); 1258 1.1 agc if (pu == NULL) { 1259 1.57 pooka err(EXIT_FAILURE, "puffs_init"); 1260 1.1 agc } 1261 1.98 pho fuse->pu = pu; 1262 1.1 agc 1263 1.98 pho free(config.fsname); 1264 1.38 pooka return fuse; 1265 1.38 pooka } 1266 1.38 pooka 1267 1.38 pooka int 1268 1.38 pooka fuse_loop(struct fuse *fuse) 1269 1.38 pooka { 1270 1.114 pho struct fuse_conn_info conn; 1271 1.114 pho struct fuse_config cfg; 1272 1.102 pho 1273 1.114 pho /* struct fuse_conn_info is a part of the FUSE API so we must 1274 1.114 pho * expose it to users, but we currently don't use them at 1275 1.114 pho * all. The same goes for struct fuse_config. */ 1276 1.114 pho memset(&conn, 0, sizeof(conn)); 1277 1.114 pho memset(&cfg, 0, sizeof(cfg)); 1278 1.114 pho 1279 1.114 pho fuse_fs_init_v30(fuse->fs, &conn, &cfg); 1280 1.102 pho 1281 1.98 pho return puffs_mainloop(fuse->pu); 1282 1.38 pooka } 1283 1.38 pooka 1284 1.114 pho int 1285 1.114 pho __fuse_loop_mt(struct fuse *fuse, 1286 1.114 pho struct fuse_loop_config *config __attribute__((__unused__))) 1287 1.114 pho { 1288 1.114 pho /* TODO: Implement a proper multi-threaded loop. */ 1289 1.114 pho return fuse_loop(fuse); 1290 1.114 pho } 1291 1.114 pho 1292 1.38 pooka void 1293 1.114 pho __fuse_destroy(struct fuse *fuse) 1294 1.38 pooka { 1295 1.38 pooka 1296 1.80 pooka /* 1297 1.80 pooka * TODO: needs to assert the fs is quiescent, i.e. no other 1298 1.80 pooka * threads exist 1299 1.80 pooka */ 1300 1.80 pooka 1301 1.113 pho clear_context(); 1302 1.66 agc delete_context_key(); 1303 1.38 pooka /* XXXXXX: missing stuff */ 1304 1.55 christos free(fuse); 1305 1.1 agc } 1306 1.1 agc 1307 1.20 agc void 1308 1.38 pooka fuse_exit(struct fuse *fuse) 1309 1.20 agc { 1310 1.60 pooka /* XXX: puffs_exit() is WRONG */ 1311 1.98 pho if (fuse->dead == 0) 1312 1.98 pho puffs_exit(fuse->pu, 1); 1313 1.98 pho fuse->dead = 1; 1314 1.20 agc } 1315 1.29 pooka 1316 1.29 pooka /* 1317 1.29 pooka * XXX: obviously not the most perfect of functions, but needs some 1318 1.29 pooka * puffs tweaking for a better tomorrow 1319 1.29 pooka */ 1320 1.29 pooka void 1321 1.114 pho __fuse_unmount(struct fuse *fuse) 1322 1.38 pooka { 1323 1.60 pooka /* XXX: puffs_exit() is WRONG */ 1324 1.98 pho if (fuse->dead == 0) 1325 1.98 pho puffs_exit(fuse->pu, 1); 1326 1.98 pho fuse->dead = 1; 1327 1.38 pooka } 1328 1.38 pooka 1329 1.111 pho void 1330 1.111 pho fuse_lib_help(struct fuse_args *args __attribute__((__unused__))) 1331 1.111 pho { 1332 1.111 pho fuse_cmdline_help(); 1333 1.111 pho } 1334 1.111 pho 1335 1.111 pho int 1336 1.111 pho fuse_interrupted(void) 1337 1.111 pho { 1338 1.111 pho /* ReFUSE doesn't support request interruption at the 1339 1.111 pho * moment. */ 1340 1.111 pho return 0; 1341 1.111 pho } 1342 1.111 pho 1343 1.99 maya int 1344 1.105 pho fuse_invalidate_path(struct fuse *fuse __attribute__((__unused__)), 1345 1.105 pho const char *path __attribute__((__unused__))) 1346 1.105 pho { 1347 1.105 pho /* ReFUSE doesn't cache anything at the moment. No need to do 1348 1.105 pho * anything. */ 1349 1.105 pho return -ENOENT; 1350 1.105 pho } 1351 1.105 pho 1352 1.105 pho int 1353 1.99 maya fuse_version(void) 1354 1.99 maya { 1355 1.109 pho return _REFUSE_VERSION_; 1356 1.99 maya } 1357 1.105 pho 1358 1.111 pho const char * 1359 1.111 pho fuse_pkgversion(void) 1360 1.111 pho { 1361 1.111 pho return "ReFUSE " ___STRING(_REFUSE_MAJOR_VERSION_) 1362 1.111 pho "." ___STRING(_REFUSE_MINOR_VERSION_); 1363 1.111 pho } 1364 1.111 pho 1365 1.111 pho int 1366 1.111 pho fuse_getgroups(int size, gid_t list[]) 1367 1.111 pho { 1368 1.111 pho /* XXX: In order to implement this, we need to save a pointer 1369 1.111 pho * to struct puffs_cred in struct fuse upon entering a puffs 1370 1.111 pho * callback, and set it back to NULL upon leaving it. Then we 1371 1.111 pho * can use puffs_cred_getgroups(3) here. */ 1372 1.111 pho return -ENOSYS; 1373 1.111 pho } 1374 1.111 pho 1375 1.111 pho int 1376 1.111 pho fuse_start_cleanup_thread(struct fuse *fuse) 1377 1.111 pho { 1378 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */ 1379 1.111 pho return 0; 1380 1.111 pho } 1381 1.111 pho 1382 1.111 pho void 1383 1.111 pho fuse_stop_cleanup_thread(struct fuse *fuse) { 1384 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */ 1385 1.111 pho } 1386 1.111 pho 1387 1.111 pho int 1388 1.111 pho fuse_clean_cache(struct fuse *fuse) { 1389 1.111 pho /* XXX: ReFUSE doesn't support -oremember at the moment. */ 1390 1.111 pho return 3600; 1391 1.111 pho } 1392 1.111 pho 1393 1.105 pho /* This is a legacy function that has been removed from the FUSE API, 1394 1.105 pho * but is defined here because it needs to access refuse_opts. */ 1395 1.105 pho int 1396 1.105 pho fuse_is_lib_option(const char *opt) 1397 1.105 pho { 1398 1.105 pho return fuse_opt_match(refuse_opts, opt); 1399 1.105 pho } 1400