1 1.36 andvar /* $NetBSD: null.c,v 1.36 2021/09/11 20:28:03 andvar Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.1 pooka #include <sys/cdefs.h> 29 1.1 pooka #if !defined(lint) 30 1.36 andvar __RCSID("$NetBSD: null.c,v 1.36 2021/09/11 20:28:03 andvar Exp $"); 31 1.1 pooka #endif /* !lint */ 32 1.1 pooka 33 1.1 pooka /* 34 1.1 pooka * A "nullfs" using puffs, i.e. maps one location in the hierarchy 35 1.1 pooka * to another using standard system calls. 36 1.1 pooka */ 37 1.1 pooka 38 1.1 pooka #include <sys/types.h> 39 1.28 pooka #include <sys/stat.h> 40 1.1 pooka #include <sys/time.h> 41 1.1 pooka 42 1.1 pooka #include <assert.h> 43 1.1 pooka #include <dirent.h> 44 1.1 pooka #include <errno.h> 45 1.1 pooka #include <fcntl.h> 46 1.1 pooka #include <puffs.h> 47 1.1 pooka #include <stdio.h> 48 1.9 pooka #include <stdlib.h> 49 1.28 pooka #include <time.h> 50 1.1 pooka #include <unistd.h> 51 1.1 pooka 52 1.1 pooka PUFFSOP_PROTOS(puffs_null) 53 1.1 pooka 54 1.1 pooka /* 55 1.1 pooka * set attributes to what is specified. XXX: no rollback in case of failure 56 1.1 pooka */ 57 1.1 pooka static int 58 1.2 pooka processvattr(const char *path, const struct vattr *va, int regular) 59 1.1 pooka { 60 1.1 pooka struct timeval tv[2]; 61 1.1 pooka 62 1.1 pooka /* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */ 63 1.1 pooka if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1) 64 1.2 pooka if (lchown(path, va->va_uid, va->va_gid) == -1) 65 1.1 pooka return errno; 66 1.1 pooka 67 1.1 pooka if (va->va_mode != (unsigned)PUFFS_VNOVAL) 68 1.2 pooka if (lchmod(path, va->va_mode) == -1) 69 1.1 pooka return errno; 70 1.1 pooka 71 1.1 pooka /* sloppy */ 72 1.27 lukem if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL 73 1.27 lukem || va->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) { 74 1.1 pooka TIMESPEC_TO_TIMEVAL(&tv[0], &va->va_atime); 75 1.1 pooka TIMESPEC_TO_TIMEVAL(&tv[1], &va->va_mtime); 76 1.1 pooka 77 1.1 pooka if (lutimes(path, tv) == -1) 78 1.1 pooka return errno; 79 1.1 pooka } 80 1.1 pooka 81 1.2 pooka if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL) 82 1.1 pooka if (truncate(path, (off_t)va->va_size) == -1) 83 1.1 pooka return errno; 84 1.1 pooka 85 1.1 pooka return 0; 86 1.1 pooka } 87 1.1 pooka 88 1.3 pooka /* 89 1.3 pooka * Kludge to open files which aren't writable *any longer*. This kinda 90 1.3 pooka * works because the vfs layer does validation checks based on the file's 91 1.3 pooka * permissions to allow writable opening before opening them. However, 92 1.3 pooka * the problem arises if we want to create a file, write to it (cache), 93 1.3 pooka * adjust permissions and then flush the file. 94 1.3 pooka */ 95 1.3 pooka static int 96 1.3 pooka writeableopen(const char *path) 97 1.3 pooka { 98 1.3 pooka struct stat sb; 99 1.3 pooka mode_t origmode; 100 1.3 pooka int sverr = 0; 101 1.3 pooka int fd; 102 1.3 pooka 103 1.3 pooka fd = open(path, O_WRONLY); 104 1.3 pooka if (fd == -1) { 105 1.3 pooka if (errno == EACCES) { 106 1.3 pooka if (stat(path, &sb) == -1) 107 1.15 pooka return -1; 108 1.3 pooka origmode = sb.st_mode & ALLPERMS; 109 1.3 pooka 110 1.3 pooka if (chmod(path, 0200) == -1) 111 1.15 pooka return -1; 112 1.3 pooka 113 1.3 pooka fd = open(path, O_WRONLY); 114 1.3 pooka if (fd == -1) 115 1.3 pooka sverr = errno; 116 1.3 pooka 117 1.3 pooka chmod(path, origmode); 118 1.3 pooka if (sverr) 119 1.3 pooka errno = sverr; 120 1.3 pooka } else 121 1.15 pooka return -1; 122 1.3 pooka } 123 1.3 pooka 124 1.3 pooka return fd; 125 1.3 pooka } 126 1.3 pooka 127 1.1 pooka /*ARGSUSED*/ 128 1.9 pooka static void * 129 1.9 pooka inodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 130 1.9 pooka { 131 1.9 pooka ino_t *cmpino = arg; 132 1.9 pooka 133 1.9 pooka if (pn->pn_va.va_fileid == *cmpino) 134 1.9 pooka return pn; 135 1.9 pooka return NULL; 136 1.9 pooka } 137 1.9 pooka 138 1.19 pooka static int 139 1.21 pooka makenode(struct puffs_usermount *pu, struct puffs_newinfo *pni, 140 1.19 pooka const struct puffs_cn *pcn, const struct vattr *va, int regular) 141 1.19 pooka { 142 1.19 pooka struct puffs_node *pn; 143 1.19 pooka struct stat sb; 144 1.19 pooka int rv; 145 1.19 pooka 146 1.19 pooka if ((rv = processvattr(PCNPATH(pcn), va, regular)) != 0) 147 1.19 pooka return rv; 148 1.19 pooka 149 1.19 pooka pn = puffs_pn_new(pu, NULL); 150 1.19 pooka if (!pn) 151 1.19 pooka return ENOMEM; 152 1.19 pooka puffs_setvattr(&pn->pn_va, va); 153 1.19 pooka 154 1.19 pooka if (lstat(PCNPATH(pcn), &sb) == -1) 155 1.19 pooka return errno; 156 1.19 pooka puffs_stat2vattr(&pn->pn_va, &sb); 157 1.19 pooka 158 1.21 pooka puffs_newinfo_setcookie(pni, pn); 159 1.19 pooka return 0; 160 1.19 pooka } 161 1.19 pooka 162 1.36 andvar /* This should be called first and overridden from the file system */ 163 1.17 pooka void 164 1.17 pooka puffs_null_setops(struct puffs_ops *pops) 165 1.17 pooka { 166 1.17 pooka 167 1.17 pooka PUFFSOP_SET(pops, puffs_null, fs, statvfs); 168 1.17 pooka PUFFSOP_SETFSNOP(pops, unmount); 169 1.17 pooka PUFFSOP_SETFSNOP(pops, sync); 170 1.26 pooka PUFFSOP_SET(pops, puffs_null, fs, fhtonode); 171 1.26 pooka PUFFSOP_SET(pops, puffs_null, fs, nodetofh); 172 1.17 pooka 173 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, lookup); 174 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, create); 175 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, mknod); 176 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, getattr); 177 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, setattr); 178 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, fsync); 179 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, remove); 180 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, link); 181 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, rename); 182 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, mkdir); 183 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, rmdir); 184 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, symlink); 185 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, readlink); 186 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, readdir); 187 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, read); 188 1.17 pooka PUFFSOP_SET(pops, puffs_null, node, write); 189 1.22 pooka PUFFSOP_SET(pops, puffs_genfs, node, reclaim); 190 1.17 pooka } 191 1.17 pooka 192 1.9 pooka /*ARGSUSED*/ 193 1.1 pooka int 194 1.34 christos puffs_null_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *svfsb) 195 1.1 pooka { 196 1.34 christos struct statvfs sb; 197 1.34 christos if (statvfs(PNPATH(puffs_getroot(pu)), &sb) == -1) 198 1.1 pooka return errno; 199 1.34 christos statvfs_to_puffs_statvfs(&sb, svfsb); 200 1.1 pooka 201 1.1 pooka return 0; 202 1.1 pooka } 203 1.1 pooka 204 1.26 pooka /* 205 1.26 pooka * XXX: this is the stupidest crap ever, but: 206 1.26 pooka * getfh() returns the fhandle type, when we are expected to deliver 207 1.26 pooka * the fid type. Just adjust it a bit and stop whining. 208 1.26 pooka * 209 1.26 pooka * Yes, this really really needs fixing. Yes, *REALLY*. 210 1.26 pooka */ 211 1.26 pooka #define FHANDLE_HEADERLEN 8 212 1.26 pooka struct kernfid { 213 1.26 pooka unsigned short fid_len; /* length of data in bytes */ 214 1.26 pooka unsigned short fid_reserved; /* compat: historic align */ 215 1.26 pooka char fid_data[0]; /* data (variable length) */ 216 1.26 pooka }; 217 1.26 pooka 218 1.26 pooka /*ARGSUSED*/ 219 1.26 pooka static void * 220 1.26 pooka fhcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 221 1.26 pooka { 222 1.26 pooka struct kernfid *kf1, *kf2; 223 1.26 pooka 224 1.26 pooka if ((kf1 = pn->pn_data) == NULL) 225 1.26 pooka return NULL; 226 1.26 pooka kf2 = arg; 227 1.26 pooka 228 1.26 pooka if (kf1->fid_len != kf2->fid_len) 229 1.26 pooka return NULL; 230 1.26 pooka 231 1.26 pooka /*LINTED*/ 232 1.26 pooka if (memcmp(kf1, kf2, kf1->fid_len) == 0) 233 1.26 pooka return pn; 234 1.26 pooka return NULL; 235 1.26 pooka } 236 1.26 pooka 237 1.26 pooka /* 238 1.26 pooka * This routine only supports file handles which have been issued while 239 1.26 pooka * the server was alive. Not really stable ones, that is. 240 1.26 pooka */ 241 1.26 pooka /*ARGSUSED*/ 242 1.26 pooka int 243 1.26 pooka puffs_null_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 244 1.26 pooka struct puffs_newinfo *pni) 245 1.26 pooka { 246 1.26 pooka struct puffs_node *pn_res; 247 1.26 pooka 248 1.26 pooka pn_res = puffs_pn_nodewalk(pu, fhcmp, fid); 249 1.26 pooka if (pn_res == NULL) 250 1.26 pooka return ENOENT; 251 1.26 pooka 252 1.26 pooka puffs_newinfo_setcookie(pni, pn_res); 253 1.26 pooka puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type); 254 1.26 pooka puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size); 255 1.26 pooka puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev); 256 1.26 pooka return 0; 257 1.26 pooka } 258 1.26 pooka 259 1.26 pooka /*ARGSUSED*/ 260 1.26 pooka int 261 1.26 pooka puffs_null_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t opc, 262 1.26 pooka void *fid, size_t *fidsize) 263 1.26 pooka { 264 1.26 pooka struct puffs_node *pn = opc; 265 1.26 pooka struct kernfid *kfid; 266 1.26 pooka void *bounce; 267 1.26 pooka int rv; 268 1.26 pooka 269 1.26 pooka rv = 0; 270 1.26 pooka bounce = NULL; 271 1.26 pooka if (*fidsize) { 272 1.26 pooka bounce = malloc(*fidsize + FHANDLE_HEADERLEN); 273 1.26 pooka if (!bounce) 274 1.26 pooka return ENOMEM; 275 1.26 pooka *fidsize += FHANDLE_HEADERLEN; 276 1.26 pooka } 277 1.26 pooka if (getfh(PNPATH(pn), bounce, fidsize) == -1) 278 1.26 pooka rv = errno; 279 1.26 pooka else 280 1.26 pooka memcpy(fid, (uint8_t *)bounce + FHANDLE_HEADERLEN, 281 1.26 pooka *fidsize - FHANDLE_HEADERLEN); 282 1.26 pooka kfid = fid; 283 1.26 pooka if (rv == 0) { 284 1.26 pooka *fidsize = kfid->fid_len; 285 1.26 pooka pn->pn_data = malloc(*fidsize); 286 1.26 pooka if (pn->pn_data == NULL) 287 1.26 pooka abort(); /* lazy */ 288 1.26 pooka memcpy(pn->pn_data, fid, *fidsize); 289 1.26 pooka } else { 290 1.26 pooka *fidsize -= FHANDLE_HEADERLEN; 291 1.26 pooka } 292 1.26 pooka free(bounce); 293 1.26 pooka 294 1.26 pooka return rv; 295 1.26 pooka } 296 1.26 pooka 297 1.1 pooka int 298 1.25 pooka puffs_null_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 299 1.21 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn) 300 1.1 pooka { 301 1.1 pooka struct puffs_node *pn = opc, *pn_res; 302 1.1 pooka struct stat sb; 303 1.1 pooka int rv; 304 1.1 pooka 305 1.1 pooka assert(pn->pn_va.va_type == VDIR); 306 1.1 pooka 307 1.6 pooka /* 308 1.6 pooka * Note to whoever is copypasting this: you must first check 309 1.6 pooka * if the node is there and only then do nodewalk. Alternatively 310 1.6 pooka * you could make sure that you don't return unlinked/rmdir'd 311 1.6 pooka * nodes in some other fashion 312 1.6 pooka */ 313 1.6 pooka rv = lstat(PCNPATH(pcn), &sb); 314 1.1 pooka if (rv) 315 1.10 pooka return errno; 316 1.1 pooka 317 1.6 pooka /* XXX2: nodewalk is a bit too slow here */ 318 1.9 pooka pn_res = puffs_pn_nodewalk(pu, inodecmp, &sb.st_ino); 319 1.1 pooka 320 1.6 pooka if (pn_res == NULL) { 321 1.6 pooka pn_res = puffs_pn_new(pu, NULL); 322 1.6 pooka if (pn_res == NULL) 323 1.6 pooka return ENOMEM; 324 1.6 pooka puffs_stat2vattr(&pn_res->pn_va, &sb); 325 1.6 pooka } 326 1.1 pooka 327 1.21 pooka puffs_newinfo_setcookie(pni, pn_res); 328 1.21 pooka puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type); 329 1.21 pooka puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size); 330 1.21 pooka puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev); 331 1.1 pooka 332 1.1 pooka return 0; 333 1.1 pooka } 334 1.1 pooka 335 1.1 pooka /*ARGSUSED*/ 336 1.1 pooka int 337 1.25 pooka puffs_null_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 338 1.21 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 339 1.21 pooka const struct vattr *va) 340 1.1 pooka { 341 1.1 pooka int fd, rv; 342 1.1 pooka 343 1.4 pooka fd = open(PCNPATH(pcn), O_RDWR | O_CREAT | O_TRUNC); 344 1.1 pooka if (fd == -1) 345 1.1 pooka return errno; 346 1.1 pooka close(fd); 347 1.1 pooka 348 1.21 pooka rv = makenode(pu, pni, pcn, va, 1); 349 1.19 pooka if (rv) 350 1.4 pooka unlink(PCNPATH(pcn)); 351 1.19 pooka return rv; 352 1.1 pooka } 353 1.1 pooka 354 1.1 pooka /*ARGSUSED*/ 355 1.1 pooka int 356 1.25 pooka puffs_null_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc, 357 1.21 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 358 1.21 pooka const struct vattr *va) 359 1.1 pooka { 360 1.11 pooka mode_t mode; 361 1.1 pooka int rv; 362 1.1 pooka 363 1.11 pooka mode = puffs_addvtype2mode(va->va_mode, va->va_type); 364 1.11 pooka if (mknod(PCNPATH(pcn), mode, va->va_rdev) == -1) 365 1.1 pooka return errno; 366 1.1 pooka 367 1.21 pooka rv = makenode(pu, pni, pcn, va, 0); 368 1.19 pooka if (rv) 369 1.4 pooka unlink(PCNPATH(pcn)); 370 1.19 pooka return rv; 371 1.1 pooka } 372 1.1 pooka 373 1.1 pooka /*ARGSUSED*/ 374 1.1 pooka int 375 1.25 pooka puffs_null_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 376 1.25 pooka struct vattr *va, const struct puffs_cred *pcred) 377 1.1 pooka { 378 1.1 pooka struct puffs_node *pn = opc; 379 1.1 pooka struct stat sb; 380 1.1 pooka 381 1.4 pooka if (lstat(PNPATH(pn), &sb) == -1) 382 1.1 pooka return errno; 383 1.1 pooka puffs_stat2vattr(va, &sb); 384 1.1 pooka 385 1.1 pooka return 0; 386 1.1 pooka } 387 1.1 pooka 388 1.1 pooka /*ARGSUSED*/ 389 1.1 pooka int 390 1.25 pooka puffs_null_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 391 1.23 pooka const struct vattr *va, const struct puffs_cred *pcred) 392 1.1 pooka { 393 1.1 pooka struct puffs_node *pn = opc; 394 1.1 pooka int rv; 395 1.1 pooka 396 1.4 pooka rv = processvattr(PNPATH(pn), va, pn->pn_va.va_type == VREG); 397 1.1 pooka if (rv) 398 1.1 pooka return rv; 399 1.1 pooka 400 1.1 pooka puffs_setvattr(&pn->pn_va, va); 401 1.1 pooka 402 1.1 pooka return 0; 403 1.1 pooka } 404 1.1 pooka 405 1.1 pooka /*ARGSUSED*/ 406 1.1 pooka int 407 1.25 pooka puffs_null_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc, 408 1.3 pooka const struct puffs_cred *pcred, int how, 409 1.23 pooka off_t offlo, off_t offhi) 410 1.3 pooka { 411 1.3 pooka struct puffs_node *pn = opc; 412 1.3 pooka int fd, rv; 413 1.3 pooka int fflags; 414 1.29 manu struct stat sb; 415 1.35 tnn DIR *dirp; 416 1.3 pooka 417 1.3 pooka rv = 0; 418 1.29 manu if (stat(PNPATH(pn), &sb) == -1) 419 1.3 pooka return errno; 420 1.29 manu if (S_ISDIR(sb.st_mode)) { 421 1.35 tnn if ((dirp = opendir(PNPATH(pn))) == NULL) 422 1.29 manu return errno; 423 1.29 manu fd = dirfd(dirp); 424 1.35 tnn if (fd == -1) { 425 1.35 tnn rv = errno; 426 1.35 tnn closedir(dirp); 427 1.35 tnn return rv; 428 1.35 tnn } 429 1.3 pooka 430 1.29 manu if (fsync(fd) == -1) 431 1.29 manu rv = errno; 432 1.35 tnn 433 1.35 tnn closedir(dirp); 434 1.29 manu } else { 435 1.29 manu fd = writeableopen(PNPATH(pn)); 436 1.29 manu if (fd == -1) 437 1.29 manu return errno; 438 1.29 manu 439 1.29 manu if (how & PUFFS_FSYNC_DATAONLY) 440 1.29 manu fflags = FDATASYNC; 441 1.29 manu else 442 1.29 manu fflags = FFILESYNC; 443 1.29 manu if (how & PUFFS_FSYNC_CACHE) 444 1.29 manu fflags |= FDISKSYNC; 445 1.3 pooka 446 1.29 manu if (fsync_range(fd, fflags, offlo, offhi - offlo) == -1) 447 1.29 manu rv = errno; 448 1.35 tnn 449 1.35 tnn close(fd); 450 1.29 manu } 451 1.3 pooka 452 1.3 pooka return rv; 453 1.3 pooka } 454 1.3 pooka 455 1.3 pooka /*ARGSUSED*/ 456 1.3 pooka int 457 1.25 pooka puffs_null_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 458 1.25 pooka puffs_cookie_t targ, const struct puffs_cn *pcn) 459 1.1 pooka { 460 1.1 pooka struct puffs_node *pn_targ = targ; 461 1.1 pooka 462 1.33 manu if (unlink(PNPATH(pn_targ)) == -1) 463 1.1 pooka return errno; 464 1.16 pooka puffs_pn_remove(pn_targ); 465 1.1 pooka 466 1.1 pooka return 0; 467 1.1 pooka } 468 1.1 pooka 469 1.1 pooka /*ARGSUSED*/ 470 1.1 pooka int 471 1.25 pooka puffs_null_node_link(struct puffs_usermount *pu, puffs_cookie_t opc, 472 1.25 pooka puffs_cookie_t targ, const struct puffs_cn *pcn) 473 1.1 pooka { 474 1.1 pooka struct puffs_node *pn_targ = targ; 475 1.1 pooka 476 1.4 pooka if (link(PNPATH(pn_targ), PCNPATH(pcn)) == -1) 477 1.1 pooka return errno; 478 1.1 pooka 479 1.1 pooka return 0; 480 1.1 pooka } 481 1.1 pooka 482 1.1 pooka /*ARGSUSED*/ 483 1.1 pooka int 484 1.25 pooka puffs_null_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc, 485 1.25 pooka puffs_cookie_t src, const struct puffs_cn *pcn_src, 486 1.25 pooka puffs_cookie_t targ_dir, puffs_cookie_t targ, 487 1.1 pooka const struct puffs_cn *pcn_targ) 488 1.1 pooka { 489 1.31 manu struct puffs_node *pn_targ = targ; 490 1.1 pooka 491 1.4 pooka if (rename(PCNPATH(pcn_src), PCNPATH(pcn_targ)) == -1) 492 1.1 pooka return errno; 493 1.1 pooka 494 1.31 manu if (pn_targ) 495 1.31 manu puffs_pn_remove(pn_targ); 496 1.31 manu 497 1.1 pooka return 0; 498 1.1 pooka } 499 1.1 pooka 500 1.1 pooka /*ARGSUSED*/ 501 1.1 pooka int 502 1.25 pooka puffs_null_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 503 1.21 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 504 1.21 pooka const struct vattr *va) 505 1.1 pooka { 506 1.1 pooka int rv; 507 1.1 pooka 508 1.4 pooka if (mkdir(PCNPATH(pcn), va->va_mode) == -1) 509 1.1 pooka return errno; 510 1.1 pooka 511 1.21 pooka rv = makenode(pu, pni, pcn, va, 0); 512 1.19 pooka if (rv) 513 1.5 agc rmdir(PCNPATH(pcn)); 514 1.19 pooka return rv; 515 1.1 pooka } 516 1.1 pooka 517 1.1 pooka /*ARGSUSED*/ 518 1.1 pooka int 519 1.25 pooka puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 520 1.25 pooka puffs_cookie_t targ, const struct puffs_cn *pcn) 521 1.1 pooka { 522 1.1 pooka struct puffs_node *pn_targ = targ; 523 1.1 pooka 524 1.33 manu if (rmdir(PNPATH(pn_targ)) == -1) 525 1.1 pooka return errno; 526 1.16 pooka puffs_pn_remove(pn_targ); 527 1.1 pooka 528 1.1 pooka return 0; 529 1.1 pooka } 530 1.1 pooka 531 1.1 pooka /*ARGSUSED*/ 532 1.1 pooka int 533 1.25 pooka puffs_null_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 534 1.21 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn, 535 1.21 pooka const struct vattr *va, const char *linkname) 536 1.1 pooka { 537 1.1 pooka int rv; 538 1.1 pooka 539 1.4 pooka if (symlink(linkname, PCNPATH(pcn)) == -1) 540 1.1 pooka return errno; 541 1.1 pooka 542 1.21 pooka rv = makenode(pu, pni, pcn, va, 0); 543 1.19 pooka if (rv) 544 1.4 pooka unlink(PCNPATH(pcn)); 545 1.19 pooka return rv; 546 1.1 pooka } 547 1.1 pooka 548 1.1 pooka /*ARGSUSED*/ 549 1.1 pooka int 550 1.25 pooka puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 551 1.1 pooka const struct puffs_cred *pcred, char *linkname, size_t *linklen) 552 1.1 pooka { 553 1.1 pooka struct puffs_node *pn = opc; 554 1.1 pooka ssize_t rv; 555 1.1 pooka 556 1.4 pooka rv = readlink(PNPATH(pn), linkname, *linklen); 557 1.1 pooka if (rv == -1) 558 1.1 pooka return errno; 559 1.1 pooka 560 1.8 pooka *linklen = rv; 561 1.1 pooka return 0; 562 1.1 pooka } 563 1.1 pooka 564 1.1 pooka /*ARGSUSED*/ 565 1.1 pooka int 566 1.25 pooka puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 567 1.24 pooka struct dirent *de, off_t *off, size_t *reslen, 568 1.24 pooka const struct puffs_cred *pcred, int *eofflag, off_t *cookies, 569 1.24 pooka size_t *ncookies) 570 1.1 pooka { 571 1.1 pooka struct puffs_node *pn = opc; 572 1.1 pooka struct dirent entry, *result; 573 1.1 pooka DIR *dp; 574 1.1 pooka off_t i; 575 1.1 pooka int rv; 576 1.1 pooka 577 1.26 pooka *ncookies = 0; 578 1.4 pooka dp = opendir(PNPATH(pn)); 579 1.1 pooka if (dp == NULL) 580 1.1 pooka return errno; 581 1.1 pooka 582 1.1 pooka rv = 0; 583 1.1 pooka i = *off; 584 1.1 pooka 585 1.1 pooka /* 586 1.1 pooka * XXX: need to do trickery here, telldir/seekdir would be nice, but 587 1.1 pooka * then we'd need to keep state, which I'm too lazy to keep 588 1.1 pooka */ 589 1.1 pooka while (i--) { 590 1.1 pooka rv = readdir_r(dp, &entry, &result); 591 1.30 manu if (rv != 0) 592 1.30 manu goto out; 593 1.30 manu 594 1.30 manu if (!result) { 595 1.30 manu *eofflag = 1; 596 1.1 pooka goto out; 597 1.30 manu } 598 1.1 pooka } 599 1.1 pooka 600 1.1 pooka for (;;) { 601 1.1 pooka rv = readdir_r(dp, &entry, &result); 602 1.1 pooka if (rv != 0) 603 1.1 pooka goto out; 604 1.1 pooka 605 1.26 pooka if (!result) { 606 1.26 pooka *eofflag = 1; 607 1.1 pooka goto out; 608 1.26 pooka } 609 1.1 pooka 610 1.1 pooka if (_DIRENT_SIZE(result) > *reslen) 611 1.1 pooka goto out; 612 1.1 pooka 613 1.1 pooka *de = *result; 614 1.1 pooka *reslen -= _DIRENT_SIZE(result); 615 1.1 pooka de = _DIRENT_NEXT(de); 616 1.1 pooka 617 1.1 pooka (*off)++; 618 1.26 pooka PUFFS_STORE_DCOOKIE(cookies, ncookies, *off); 619 1.1 pooka } 620 1.1 pooka 621 1.1 pooka out: 622 1.1 pooka closedir(dp); 623 1.1 pooka return 0; 624 1.1 pooka } 625 1.1 pooka 626 1.1 pooka /*ARGSUSED*/ 627 1.1 pooka int 628 1.25 pooka puffs_null_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 629 1.25 pooka uint8_t *buf, off_t offset, size_t *buflen, 630 1.25 pooka const struct puffs_cred *pcred, int ioflag) 631 1.1 pooka { 632 1.1 pooka struct puffs_node *pn = opc; 633 1.1 pooka ssize_t n; 634 1.1 pooka off_t off; 635 1.1 pooka int fd, rv; 636 1.1 pooka 637 1.1 pooka rv = 0; 638 1.4 pooka fd = open(PNPATH(pn), O_RDONLY); 639 1.1 pooka if (fd == -1) 640 1.1 pooka return errno; 641 1.1 pooka off = lseek(fd, offset, SEEK_SET); 642 1.1 pooka if (off == -1) { 643 1.1 pooka rv = errno; 644 1.1 pooka goto out; 645 1.1 pooka } 646 1.1 pooka 647 1.1 pooka n = read(fd, buf, *buflen); 648 1.1 pooka if (n == -1) 649 1.1 pooka rv = errno; 650 1.1 pooka else 651 1.1 pooka *buflen -= n; 652 1.1 pooka 653 1.1 pooka out: 654 1.1 pooka close(fd); 655 1.1 pooka return rv; 656 1.1 pooka } 657 1.1 pooka 658 1.1 pooka /*ARGSUSED*/ 659 1.1 pooka int 660 1.25 pooka puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 661 1.25 pooka uint8_t *buf, off_t offset, size_t *buflen, 662 1.25 pooka const struct puffs_cred *pcred, int ioflag) 663 1.1 pooka { 664 1.1 pooka struct puffs_node *pn = opc; 665 1.1 pooka ssize_t n; 666 1.1 pooka off_t off; 667 1.1 pooka int fd, rv; 668 1.1 pooka 669 1.1 pooka rv = 0; 670 1.4 pooka fd = writeableopen(PNPATH(pn)); 671 1.3 pooka if (fd == -1) 672 1.3 pooka return errno; 673 1.2 pooka 674 1.1 pooka off = lseek(fd, offset, SEEK_SET); 675 1.1 pooka if (off == -1) { 676 1.1 pooka rv = errno; 677 1.1 pooka goto out; 678 1.1 pooka } 679 1.1 pooka 680 1.1 pooka n = write(fd, buf, *buflen); 681 1.1 pooka if (n == -1) 682 1.1 pooka rv = errno; 683 1.1 pooka else 684 1.1 pooka *buflen -= n; 685 1.1 pooka 686 1.1 pooka out: 687 1.1 pooka close(fd); 688 1.1 pooka return rv; 689 1.1 pooka } 690