1272343Sngie/* $NetBSD: dtfs_vnops.c,v 1.10 2013/10/19 17:45:00 christos Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * Copyright (c) 2006 Antti Kantee. All Rights Reserved. 5272343Sngie * 6272343Sngie * Redistribution and use in source and binary forms, with or without 7272343Sngie * modification, are permitted provided that the following conditions 8272343Sngie * are met: 9272343Sngie * 1. Redistributions of source code must retain the above copyright 10272343Sngie * notice, this list of conditions and the following disclaimer. 11272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie * notice, this list of conditions and the following disclaimer in the 13272343Sngie * documentation and/or other materials provided with the distribution. 14272343Sngie * 15272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16272343Sngie * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17272343Sngie * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18272343Sngie * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21272343Sngie * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25272343Sngie * SUCH DAMAGE. 26272343Sngie */ 27272343Sngie 28272343Sngie#include <sys/types.h> 29272343Sngie#include <sys/poll.h> 30272343Sngie 31272343Sngie#include <assert.h> 32272343Sngie#include <errno.h> 33272343Sngie#include <puffs.h> 34272343Sngie#include <stdio.h> 35272343Sngie#include <stdlib.h> 36272343Sngie#include <string.h> 37272343Sngie#include <unistd.h> 38272343Sngie#include <util.h> 39272343Sngie 40272343Sngie#include "dtfs.h" 41272343Sngie 42272343Sngieint 43272343Sngiedtfs_node_lookup(struct puffs_usermount *pu, void *opc, 44272343Sngie struct puffs_newinfo *pni, const struct puffs_cn *pcn) 45272343Sngie{ 46272343Sngie struct puffs_node *pn_dir = opc; 47272343Sngie struct dtfs_file *df = DTFS_CTOF(opc); 48272343Sngie struct dtfs_dirent *dfd; 49272343Sngie extern int straightflush; 50272343Sngie int rv; 51272343Sngie 52272343Sngie /* parent dir? */ 53272343Sngie if (PCNISDOTDOT(pcn)) { 54272343Sngie if (df->df_dotdot == NULL) 55272343Sngie return ENOENT; 56272343Sngie 57272343Sngie assert(df->df_dotdot->pn_va.va_type == VDIR); 58272343Sngie puffs_newinfo_setcookie(pni, df->df_dotdot); 59272343Sngie puffs_newinfo_setvtype(pni, df->df_dotdot->pn_va.va_type); 60272343Sngie 61272343Sngie return 0; 62272343Sngie } 63272343Sngie 64272343Sngie dfd = dtfs_dirgetbyname(df, pcn->pcn_name, pcn->pcn_namelen); 65272343Sngie if (dfd) { 66272343Sngie if ((pcn->pcn_flags & NAMEI_ISLASTCN) && 67272343Sngie (pcn->pcn_nameiop == NAMEI_DELETE)) { 68272343Sngie rv = puffs_access(VDIR, pn_dir->pn_va.va_mode, 69272343Sngie pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid, 70272343Sngie PUFFS_VWRITE, pcn->pcn_cred); 71272343Sngie if (rv) 72272343Sngie return rv; 73272343Sngie } 74272343Sngie puffs_newinfo_setcookie(pni, dfd->dfd_node); 75272343Sngie puffs_newinfo_setvtype(pni, dfd->dfd_node->pn_va.va_type); 76272343Sngie puffs_newinfo_setsize(pni, dfd->dfd_node->pn_va.va_size); 77272343Sngie puffs_newinfo_setrdev(pni, dfd->dfd_node->pn_va.va_rdev); 78272343Sngie 79272343Sngie if (straightflush) 80272343Sngie puffs_flush_pagecache_node(pu, dfd->dfd_node); 81272343Sngie 82272343Sngie return 0; 83272343Sngie } 84272343Sngie 85272343Sngie if ((pcn->pcn_flags & NAMEI_ISLASTCN) 86272343Sngie && (pcn->pcn_nameiop == NAMEI_CREATE || 87272343Sngie pcn->pcn_nameiop == NAMEI_RENAME)) { 88272343Sngie rv = puffs_access(VDIR, pn_dir->pn_va.va_mode, 89272343Sngie pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid, 90272343Sngie PUFFS_VWRITE, pcn->pcn_cred); 91272343Sngie if (rv) 92272343Sngie return rv; 93272343Sngie } 94272343Sngie 95272343Sngie return ENOENT; 96272343Sngie} 97272343Sngie 98272343Sngieint 99272343Sngiedtfs_node_access(struct puffs_usermount *pu, void *opc, int acc_mode, 100272343Sngie const struct puffs_cred *pcr) 101272343Sngie{ 102272343Sngie struct puffs_node *pn = opc; 103272343Sngie 104272343Sngie return puffs_access(pn->pn_va.va_type, pn->pn_va.va_mode, 105272343Sngie pn->pn_va.va_uid, pn->pn_va.va_gid, acc_mode, pcr); 106272343Sngie} 107272343Sngie 108272343Sngieint 109272343Sngiedtfs_node_setattr(struct puffs_usermount *pu, void *opc, 110272343Sngie const struct vattr *va, const struct puffs_cred *pcr) 111272343Sngie{ 112272343Sngie struct puffs_node *pn = opc; 113272343Sngie int rv; 114272343Sngie 115272343Sngie /* check permissions */ 116272343Sngie if (va->va_flags != PUFFS_VNOVAL) 117272343Sngie return EOPNOTSUPP; 118272343Sngie 119272343Sngie if (va->va_uid != PUFFS_VNOVAL || va->va_gid != PUFFS_VNOVAL) { 120272343Sngie rv = puffs_access_chown(pn->pn_va.va_uid, pn->pn_va.va_gid, 121272343Sngie va->va_uid, va->va_gid, pcr); 122272343Sngie if (rv) 123272343Sngie return rv; 124272343Sngie } 125272343Sngie 126272343Sngie if (va->va_mode != PUFFS_VNOVAL) { 127272343Sngie rv = puffs_access_chmod(pn->pn_va.va_uid, pn->pn_va.va_gid, 128272343Sngie pn->pn_va.va_type, va->va_mode, pcr); 129272343Sngie if (rv) 130272343Sngie return rv; 131272343Sngie } 132272343Sngie 133272343Sngie if ((va->va_atime.tv_sec != PUFFS_VNOVAL 134272343Sngie && va->va_atime.tv_nsec != PUFFS_VNOVAL) 135272343Sngie || (va->va_mtime.tv_sec != PUFFS_VNOVAL 136272343Sngie && va->va_mtime.tv_nsec != PUFFS_VNOVAL)) { 137272343Sngie rv = puffs_access_times(pn->pn_va.va_uid, pn->pn_va.va_gid, 138272343Sngie pn->pn_va.va_mode, va->va_vaflags & VA_UTIMES_NULL, pcr); 139272343Sngie if (rv) 140272343Sngie return rv; 141272343Sngie } 142272343Sngie 143272343Sngie if (va->va_size != PUFFS_VNOVAL) { 144272343Sngie switch (pn->pn_va.va_type) { 145272343Sngie case VREG: 146272343Sngie dtfs_setsize(pn, va->va_size); 147272343Sngie pn->pn_va.va_bytes = va->va_size; 148272343Sngie break; 149272343Sngie case VBLK: 150272343Sngie case VCHR: 151272343Sngie case VFIFO: 152272343Sngie break; 153272343Sngie case VDIR: 154272343Sngie return EISDIR; 155272343Sngie default: 156272343Sngie return EOPNOTSUPP; 157272343Sngie } 158272343Sngie } 159272343Sngie 160272343Sngie puffs_setvattr(&pn->pn_va, va); 161272343Sngie 162272343Sngie return 0; 163272343Sngie} 164272343Sngie 165272343Sngie/* create a new node in the parent directory specified by opc */ 166272343Sngieint 167272343Sngiedtfs_node_create(struct puffs_usermount *pu, void *opc, 168272343Sngie struct puffs_newinfo *pni, const struct puffs_cn *pcn, 169272343Sngie const struct vattr *va) 170272343Sngie{ 171272343Sngie struct puffs_node *pn_parent = opc; 172272343Sngie struct puffs_node *pn_new; 173272343Sngie 174272343Sngie if (!(va->va_type == VREG || va->va_type == VSOCK)) 175272343Sngie return ENODEV; 176272343Sngie 177272343Sngie pn_new = dtfs_genfile(pn_parent, pcn, va->va_type); 178272343Sngie puffs_setvattr(&pn_new->pn_va, va); 179272343Sngie 180272343Sngie puffs_newinfo_setcookie(pni, pn_new); 181272343Sngie 182272343Sngie return 0; 183272343Sngie} 184272343Sngie 185272343Sngieint 186272343Sngiedtfs_node_remove(struct puffs_usermount *pu, void *opc, void *targ, 187272343Sngie const struct puffs_cn *pcn) 188272343Sngie{ 189272343Sngie struct puffs_node *pn_parent = opc; 190272343Sngie struct puffs_node *pn = targ; 191272343Sngie 192272343Sngie if (pn->pn_va.va_type == VDIR) 193272343Sngie return EPERM; 194272343Sngie 195272343Sngie dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen); 196272343Sngie 197272343Sngie if (pn->pn_va.va_nlink == 0) 198272343Sngie puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 199272343Sngie 200272343Sngie return 0; 201272343Sngie} 202272343Sngie 203272343Sngieint 204272343Sngiedtfs_node_mkdir(struct puffs_usermount *pu, void *opc, 205272343Sngie struct puffs_newinfo *pni, const struct puffs_cn *pcn, 206272343Sngie const struct vattr *va) 207272343Sngie{ 208272343Sngie struct puffs_node *pn_parent = opc; 209272343Sngie struct puffs_node *pn_new; 210272343Sngie 211272343Sngie pn_new = dtfs_genfile(pn_parent, pcn, VDIR); 212272343Sngie puffs_setvattr(&pn_new->pn_va, va); 213272343Sngie 214272343Sngie puffs_newinfo_setcookie(pni, pn_new); 215272343Sngie 216272343Sngie return 0; 217272343Sngie} 218272343Sngie 219272343Sngieint 220272343Sngiedtfs_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ, 221272343Sngie const struct puffs_cn *pcn) 222272343Sngie{ 223272343Sngie struct puffs_node *pn_parent = opc; 224272343Sngie struct dtfs_file *df = DTFS_CTOF(targ); 225272343Sngie 226272343Sngie if (!LIST_EMPTY(&df->df_dirents)) 227272343Sngie return ENOTEMPTY; 228272343Sngie 229272343Sngie dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen); 230272343Sngie puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 231272343Sngie 232272343Sngie return 0; 233272343Sngie} 234272343Sngie 235272343Sngieint 236272343Sngiedtfs_node_readdir(struct puffs_usermount *pu, void *opc, 237272343Sngie struct dirent *dent, off_t *readoff, size_t *reslen, 238272343Sngie const struct puffs_cred *pcr, 239272343Sngie int *eofflag, off_t *cookies, size_t *ncookies) 240272343Sngie{ 241272343Sngie struct puffs_node *pn = opc; 242272343Sngie struct puffs_node *pn_nth; 243272343Sngie struct dtfs_dirent *dfd_nth; 244272343Sngie 245272343Sngie if (pn->pn_va.va_type != VDIR) 246272343Sngie return ENOTDIR; 247272343Sngie 248272343Sngie dtfs_updatetimes(pn, 1, 0, 0); 249272343Sngie 250272343Sngie *ncookies = 0; 251272343Sngie again: 252272343Sngie if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) { 253272343Sngie puffs_gendotdent(&dent, pn->pn_va.va_fileid, *readoff, reslen); 254272343Sngie (*readoff)++; 255272343Sngie PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff); 256272343Sngie goto again; 257272343Sngie } 258272343Sngie 259272343Sngie for (;;) { 260272343Sngie dfd_nth = dtfs_dirgetnth(pn->pn_data, DENT_ADJ(*readoff)); 261272343Sngie if (!dfd_nth) { 262272343Sngie *eofflag = 1; 263272343Sngie break; 264272343Sngie } 265272343Sngie pn_nth = dfd_nth->dfd_node; 266272343Sngie 267272343Sngie if (!puffs_nextdent(&dent, dfd_nth->dfd_name, 268272343Sngie pn_nth->pn_va.va_fileid, 269272343Sngie puffs_vtype2dt(pn_nth->pn_va.va_type), 270272343Sngie reslen)) 271272343Sngie break; 272272343Sngie 273272343Sngie (*readoff)++; 274272343Sngie PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff); 275272343Sngie } 276272343Sngie 277272343Sngie return 0; 278272343Sngie} 279272343Sngie 280272343Sngieint 281272343Sngiedtfs_node_poll(struct puffs_usermount *pu, void *opc, int *events) 282272343Sngie{ 283272343Sngie struct dtfs_mount *dtm = puffs_getspecific(pu); 284272343Sngie struct dtfs_poll dp; 285272343Sngie struct itimerval it; 286272343Sngie 287272343Sngie memset(&it, 0, sizeof(struct itimerval)); 288272343Sngie it.it_value.tv_sec = 4; 289272343Sngie if (setitimer(ITIMER_REAL, &it, NULL) == -1) 290272343Sngie return errno; 291272343Sngie 292272343Sngie dp.dp_pcc = puffs_cc_getcc(pu); 293272343Sngie LIST_INSERT_HEAD(&dtm->dtm_pollent, &dp, dp_entries); 294272343Sngie puffs_cc_yield(dp.dp_pcc); 295272343Sngie 296272343Sngie *events = *events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 297272343Sngie return 0; 298272343Sngie} 299272343Sngie 300272343Sngieint 301272343Sngiedtfs_node_mmap(struct puffs_usermount *pu, void *opc, vm_prot_t prot, 302272343Sngie const struct puffs_cred *pcr) 303272343Sngie{ 304272343Sngie struct dtfs_mount *dtm = puffs_getspecific(pu); 305272343Sngie 306272343Sngie if ((dtm->dtm_allowprot & prot) != prot) 307272343Sngie return EACCES; 308272343Sngie 309272343Sngie return 0; 310272343Sngie} 311272343Sngie 312272343Sngieint 313272343Sngiedtfs_node_rename(struct puffs_usermount *pu, void *opc, void *src, 314272343Sngie const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 315272343Sngie const struct puffs_cn *pcn_targ) 316272343Sngie{ 317272343Sngie struct dtfs_dirent *dfd_src; 318272343Sngie struct dtfs_file *df_targ; 319272343Sngie struct puffs_node *pn_sdir = opc; 320272343Sngie struct puffs_node *pn_sfile = src; 321272343Sngie struct puffs_node *pn_tdir = targ_dir; 322272343Sngie struct puffs_node *pn_tfile = targ; 323272343Sngie 324272343Sngie /* check that we don't do the old amigados trick */ 325272343Sngie if (pn_sfile->pn_va.va_type == VDIR) { 326272343Sngie if (dtfs_isunder(pn_tdir, pn_sfile)) 327272343Sngie return EINVAL; 328272343Sngie 329272343Sngie if ((pcn_src->pcn_namelen == 1 && pcn_src->pcn_name[0]=='.') || 330272343Sngie opc == src || 331272343Sngie PCNISDOTDOT(pcn_src) || 332272343Sngie PCNISDOTDOT(pcn_targ)) { 333272343Sngie return EINVAL; 334272343Sngie } 335272343Sngie } 336272343Sngie 337272343Sngie dfd_src = dtfs_dirgetbyname(DTFS_PTOF(pn_sdir), 338272343Sngie pcn_src->pcn_name, pcn_src->pcn_namelen); 339272343Sngie 340272343Sngie /* does it still exist, or did someone race us here? */ 341272343Sngie if (dfd_src == NULL) { 342272343Sngie return ENOENT; 343272343Sngie } 344272343Sngie 345272343Sngie /* if there's a target file, nuke it for atomic replacement */ 346272343Sngie if (pn_tfile) { 347272343Sngie if (pn_tfile->pn_va.va_type == VDIR) { 348272343Sngie df_targ = DTFS_CTOF(pn_tfile); 349272343Sngie if (!LIST_EMPTY(&df_targ->df_dirents)) 350272343Sngie return ENOTEMPTY; 351272343Sngie } 352272343Sngie dtfs_nukenode(pn_tfile, pn_tdir, 353272343Sngie pcn_targ->pcn_name, pcn_targ->pcn_namelen); 354272343Sngie } 355272343Sngie 356272343Sngie /* out with the old */ 357272343Sngie dtfs_removedent(pn_sdir, dfd_src); 358272343Sngie /* and in with the new */ 359272343Sngie dtfs_adddent(pn_tdir, dfd_src); 360272343Sngie 361272343Sngie /* update name */ 362272343Sngie free(dfd_src->dfd_name); 363272343Sngie dfd_src->dfd_name = estrndup(pcn_targ->pcn_name,pcn_targ->pcn_namelen); 364272343Sngie dfd_src->dfd_namelen = strlen(dfd_src->dfd_name); 365272343Sngie 366272343Sngie dtfs_updatetimes(src, 0, 1, 0); 367272343Sngie 368272343Sngie return 0; 369272343Sngie} 370272343Sngie 371272343Sngieint 372272343Sngiedtfs_node_link(struct puffs_usermount *pu, void *opc, void *targ, 373272343Sngie const struct puffs_cn *pcn) 374272343Sngie{ 375272343Sngie struct puffs_node *pn_dir = opc; 376272343Sngie struct dtfs_dirent *dfd; 377272343Sngie 378272343Sngie dfd = emalloc(sizeof(struct dtfs_dirent)); 379272343Sngie dfd->dfd_node = targ; 380272343Sngie dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen); 381272343Sngie dfd->dfd_namelen = strlen(dfd->dfd_name); 382272343Sngie dtfs_adddent(pn_dir, dfd); 383272343Sngie 384272343Sngie dtfs_updatetimes(targ, 0, 1, 0); 385272343Sngie 386272343Sngie return 0; 387272343Sngie} 388272343Sngie 389272343Sngieint 390272343Sngiedtfs_node_symlink(struct puffs_usermount *pu, void *opc, 391272343Sngie struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, 392272343Sngie const struct vattr *va, const char *link_target) 393272343Sngie{ 394272343Sngie struct puffs_node *pn_parent = opc; 395272343Sngie struct puffs_node *pn_new; 396272343Sngie struct dtfs_file *df_new; 397272343Sngie 398272343Sngie if (va->va_type != VLNK) 399272343Sngie return ENODEV; 400272343Sngie 401272343Sngie pn_new = dtfs_genfile(pn_parent, pcn_src, VLNK); 402272343Sngie puffs_setvattr(&pn_new->pn_va, va); 403272343Sngie df_new = DTFS_PTOF(pn_new); 404272343Sngie df_new->df_linktarget = estrdup(link_target); 405272343Sngie pn_new->pn_va.va_size = strlen(df_new->df_linktarget); 406272343Sngie 407272343Sngie puffs_newinfo_setcookie(pni, pn_new); 408272343Sngie 409272343Sngie return 0; 410272343Sngie} 411272343Sngie 412272343Sngieint 413272343Sngiedtfs_node_readlink(struct puffs_usermount *pu, void *opc, 414272343Sngie const struct puffs_cred *cred, char *linkname, size_t *linklen) 415272343Sngie{ 416272343Sngie struct dtfs_file *df = DTFS_CTOF(opc); 417272343Sngie struct puffs_node *pn = opc; 418272343Sngie 419272343Sngie assert(pn->pn_va.va_type == VLNK); 420272343Sngie strlcpy(linkname, df->df_linktarget, *linklen); 421272343Sngie *linklen = strlen(linkname); 422272343Sngie 423272343Sngie return 0; 424272343Sngie} 425272343Sngie 426272343Sngieint 427272343Sngiedtfs_node_mknod(struct puffs_usermount *pu, void *opc, 428272343Sngie struct puffs_newinfo *pni, const struct puffs_cn *pcn, 429272343Sngie const struct vattr *va) 430272343Sngie{ 431272343Sngie struct puffs_node *pn_parent = opc; 432272343Sngie struct puffs_node *pn_new; 433272343Sngie 434272343Sngie if (!(va->va_type == VBLK || va->va_type == VCHR 435272343Sngie || va->va_type == VFIFO)) 436272343Sngie return EINVAL; 437272343Sngie 438272343Sngie pn_new = dtfs_genfile(pn_parent, pcn, va->va_type); 439272343Sngie puffs_setvattr(&pn_new->pn_va, va); 440272343Sngie 441272343Sngie puffs_newinfo_setcookie(pni, pn_new); 442272343Sngie 443272343Sngie return 0; 444272343Sngie} 445272343Sngie 446272343Sngie#define BLOCKOFF(a,b) ((a) & ((b)-1)) 447272343Sngie#define BLOCKLEFT(a,b) ((b) - BLOCKOFF(a,b)) 448272343Sngie 449272343Sngie/* 450272343Sngie * Read operation, used both for VOP_READ and VOP_GETPAGES 451272343Sngie */ 452272343Sngieint 453272343Sngiedtfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf, 454272343Sngie off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag) 455272343Sngie{ 456272343Sngie struct puffs_node *pn = opc; 457272343Sngie struct dtfs_file *df = DTFS_CTOF(opc); 458272343Sngie quad_t xfer, origxfer; 459272343Sngie uint8_t *src, *dest; 460272343Sngie size_t copylen; 461272343Sngie 462272343Sngie if (pn->pn_va.va_type != VREG) 463272343Sngie return EISDIR; 464272343Sngie 465272343Sngie xfer = MIN(*resid, df->df_datalen - offset); 466272343Sngie if (xfer < 0) 467272343Sngie return EINVAL; 468272343Sngie 469272343Sngie dest = buf; 470272343Sngie origxfer = xfer; 471272343Sngie while (xfer > 0) { 472272343Sngie copylen = MIN(xfer, BLOCKLEFT(offset, DTFS_BLOCKSIZE)); 473272343Sngie src = df->df_blocks[BLOCKNUM(offset, DTFS_BLOCKSHIFT)] 474272343Sngie + BLOCKOFF(offset, DTFS_BLOCKSIZE); 475272343Sngie memcpy(dest, src, copylen); 476272343Sngie offset += copylen; 477272343Sngie dest += copylen; 478272343Sngie xfer -= copylen; 479272343Sngie } 480272343Sngie *resid -= origxfer; 481272343Sngie 482272343Sngie dtfs_updatetimes(pn, 1, 0, 0); 483272343Sngie 484272343Sngie return 0; 485272343Sngie} 486272343Sngie 487272343Sngie/* 488272343Sngie * write operation on the wing 489272343Sngie */ 490272343Sngieint 491272343Sngiedtfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf, 492272343Sngie off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag) 493272343Sngie{ 494272343Sngie struct puffs_node *pn = opc; 495272343Sngie struct dtfs_file *df = DTFS_CTOF(opc); 496272343Sngie uint8_t *src, *dest; 497272343Sngie size_t copylen; 498272343Sngie 499272343Sngie if (pn->pn_va.va_type != VREG) 500272343Sngie return EISDIR; 501272343Sngie 502272343Sngie if (ioflag & PUFFS_IO_APPEND) 503272343Sngie offset = pn->pn_va.va_size; 504272343Sngie 505272343Sngie if (*resid + offset > pn->pn_va.va_size) 506272343Sngie dtfs_setsize(pn, *resid + offset); 507272343Sngie 508272343Sngie src = buf; 509272343Sngie while (*resid > 0) { 510272343Sngie int i; 511272343Sngie copylen = MIN(*resid, BLOCKLEFT(offset, DTFS_BLOCKSIZE)); 512272343Sngie i = BLOCKNUM(offset, DTFS_BLOCKSHIFT); 513272343Sngie dest = df->df_blocks[i] 514272343Sngie + BLOCKOFF(offset, DTFS_BLOCKSIZE); 515272343Sngie memcpy(dest, src, copylen); 516272343Sngie offset += copylen; 517272343Sngie dest += copylen; 518272343Sngie *resid -= copylen; 519272343Sngie } 520272343Sngie 521272343Sngie dtfs_updatetimes(pn, 0, 1, 1); 522272343Sngie 523272343Sngie return 0; 524272343Sngie} 525272343Sngie 526272343Sngieint 527272343Sngiedtfs_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc, 528272343Sngie int name, register_t *retval) 529272343Sngie{ 530272343Sngie 531272343Sngie switch (name) { 532272343Sngie case _PC_LINK_MAX: 533272343Sngie *retval = LINK_MAX; 534272343Sngie return 0; 535272343Sngie case _PC_NAME_MAX: 536272343Sngie *retval = NAME_MAX; 537272343Sngie return 0; 538272343Sngie case _PC_PATH_MAX: 539272343Sngie *retval = PATH_MAX; 540272343Sngie return 0; 541272343Sngie case _PC_PIPE_BUF: 542272343Sngie *retval = PIPE_BUF; 543272343Sngie return 0; 544272343Sngie case _PC_CHOWN_RESTRICTED: 545272343Sngie *retval = 1; 546272343Sngie return 0; 547272343Sngie case _PC_NO_TRUNC: 548272343Sngie *retval = 1; 549272343Sngie return 0; 550272343Sngie case _PC_SYNC_IO: 551272343Sngie *retval = 1; 552272343Sngie return 0; 553272343Sngie case _PC_FILESIZEBITS: 554272343Sngie *retval = 43; /* this one goes to 11 */ 555272343Sngie return 0; 556272343Sngie case _PC_SYMLINK_MAX: 557272343Sngie *retval = MAXPATHLEN; 558272343Sngie return 0; 559272343Sngie case _PC_2_SYMLINKS: 560272343Sngie *retval = 1; 561272343Sngie return 0; 562272343Sngie default: 563272343Sngie return EINVAL; 564272343Sngie } 565272343Sngie} 566272343Sngie 567272343Sngieint 568272343Sngiedtfs_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 569272343Sngie{ 570272343Sngie struct puffs_node *pn = opc; 571272343Sngie 572272343Sngie if (pn->pn_va.va_nlink == 0) 573272343Sngie puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 574272343Sngie return 0; 575272343Sngie} 576272343Sngie 577272343Sngieint 578272343Sngiedtfs_node_reclaim(struct puffs_usermount *pu, void *opc) 579272343Sngie{ 580272343Sngie struct puffs_node *pn = opc; 581272343Sngie 582272343Sngie if (pn->pn_va.va_nlink == 0) 583272343Sngie dtfs_freenode(pn); 584272343Sngie 585272343Sngie return 0; 586272343Sngie} 587