1*436cfd0dSpooka /* $NetBSD: node.c,v 1.2 2007/04/22 18:10:48 pooka Exp $ */ 2e73a712fSpooka 3e73a712fSpooka /* 4e73a712fSpooka * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5e73a712fSpooka * 6e73a712fSpooka * Redistribution and use in source and binary forms, with or without 7e73a712fSpooka * modification, are permitted provided that the following conditions 8e73a712fSpooka * are met: 9e73a712fSpooka * 1. Redistributions of source code must retain the above copyright 10e73a712fSpooka * notice, this list of conditions and the following disclaimer. 11e73a712fSpooka * 2. Redistributions in binary form must reproduce the above copyright 12e73a712fSpooka * notice, this list of conditions and the following disclaimer in the 13e73a712fSpooka * documentation and/or other materials provided with the distribution. 14e73a712fSpooka * 15e73a712fSpooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16e73a712fSpooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17e73a712fSpooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18e73a712fSpooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e73a712fSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e73a712fSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21e73a712fSpooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e73a712fSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e73a712fSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e73a712fSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e73a712fSpooka * SUCH DAMAGE. 26e73a712fSpooka */ 27e73a712fSpooka 28e73a712fSpooka #include <sys/cdefs.h> 29e73a712fSpooka #ifndef lint 30*436cfd0dSpooka __RCSID("$NetBSD: node.c,v 1.2 2007/04/22 18:10:48 pooka Exp $"); 31e73a712fSpooka #endif /* !lint */ 32e73a712fSpooka 33e73a712fSpooka #include <assert.h> 34e73a712fSpooka #include <errno.h> 35e73a712fSpooka #include <puffs.h> 36e73a712fSpooka #include <stdio.h> 37e73a712fSpooka 38e73a712fSpooka #include "ninepuffs.h" 39e73a712fSpooka #include "nineproto.h" 40e73a712fSpooka 41e73a712fSpooka static void * 42e73a712fSpooka nodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 43e73a712fSpooka { 44e73a712fSpooka struct vattr *vap = &pn->pn_va; 45e73a712fSpooka struct qid9p *qid = arg; 46e73a712fSpooka 47e73a712fSpooka if (vap->va_fileid == qid->qidpath) 48e73a712fSpooka return pn; 49e73a712fSpooka 50e73a712fSpooka return NULL; 51e73a712fSpooka } 52e73a712fSpooka 53e73a712fSpooka int 54e73a712fSpooka puffs9p_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode, 55e73a712fSpooka enum vtype *newtype, voff_t *newsize, dev_t *newrdev, 56e73a712fSpooka const struct puffs_cn *pcn) 57e73a712fSpooka { 58e73a712fSpooka AUTOVAR(pcc); 59e73a712fSpooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 60e73a712fSpooka struct puffs_node *pn, *pn_dir = opc; 61e73a712fSpooka struct p9pnode *p9n_dir = pn_dir->pn_data; 62e73a712fSpooka p9ptag_t tfid = NEXTFID(p9p); 63e73a712fSpooka struct qid9p newqid; 64e73a712fSpooka uint16_t nqid; 65e73a712fSpooka 66e73a712fSpooka pb = p9pbuf_make(p9p->maxreq, P9PB_OUT); 67e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 68e73a712fSpooka p9pbuf_put_2(pb, tag); 69e73a712fSpooka p9pbuf_put_4(pb, p9n_dir->fid_base); 70e73a712fSpooka p9pbuf_put_4(pb, tfid); 71e73a712fSpooka p9pbuf_put_2(pb, 1); 72e73a712fSpooka p9pbuf_put_str(pb, pcn->pcn_name); 73e73a712fSpooka 74e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 75e73a712fSpooka puffs_cc_yield(pcc); 76e73a712fSpooka 77e73a712fSpooka rv = proto_expect_walk_nqids(pb, &nqid); 78e73a712fSpooka if (rv) { 79e73a712fSpooka rv = ENOENT; 80e73a712fSpooka goto out; 81e73a712fSpooka } 82e73a712fSpooka if (nqid != 1 || !proto_getqid(pb, &newqid)) { 83e73a712fSpooka rv = EPROTO; 84e73a712fSpooka goto out; 85e73a712fSpooka } 86e73a712fSpooka 87e73a712fSpooka pn = puffs_pn_nodewalk(pu, nodecmp, &newqid); 88e73a712fSpooka if (pn == NULL) 89e73a712fSpooka pn = newp9pnode_qid(pu, &newqid, tfid); 90e73a712fSpooka else 91e73a712fSpooka proto_cc_clunkfid(pcc, tfid, 0); 92e73a712fSpooka 93e73a712fSpooka *newnode = pn; 94e73a712fSpooka *newtype = pn->pn_va.va_type; 95e73a712fSpooka *newsize = pn->pn_va.va_size; 96e73a712fSpooka *newrdev = pn->pn_va.va_rdev; 97e73a712fSpooka 98e73a712fSpooka out: 99e73a712fSpooka RETURN(rv); 100e73a712fSpooka } 101e73a712fSpooka 102e73a712fSpooka /* 103e73a712fSpooka * Problem is that 9P doesn't allow seeking into a directory. So we 104e73a712fSpooka * maintain a list of active fids for any given directory. They 105e73a712fSpooka * start living at the first read and exist either until the directory 106e73a712fSpooka * is closed or until they reach the end. 107e73a712fSpooka */ 108e73a712fSpooka int 109e73a712fSpooka puffs9p_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent, 110e73a712fSpooka off_t *readoff, size_t *reslen, const struct puffs_cred *pcr, 111e73a712fSpooka int *eofflag, off_t *cookies, size_t *ncookies) 112e73a712fSpooka { 113e73a712fSpooka AUTOVAR(pcc); 114e73a712fSpooka struct puffs_node *pn = opc; 115e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 116e73a712fSpooka struct vattr va; 117e73a712fSpooka struct dirfid *dfp; 118e73a712fSpooka char *name; 119e73a712fSpooka uint32_t count; 120e73a712fSpooka uint16_t statsize; 121e73a712fSpooka 122e73a712fSpooka rv = getdfwithoffset(pcc, p9n, *readoff, &dfp); 123e73a712fSpooka if (rv) 124e73a712fSpooka goto out; 125e73a712fSpooka 126e73a712fSpooka tag = NEXTTAG(p9p); 127e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 128e73a712fSpooka p9pbuf_put_2(pb, tag); 129e73a712fSpooka p9pbuf_put_4(pb, dfp->fid); 130e73a712fSpooka p9pbuf_put_8(pb, *readoff); 131e73a712fSpooka p9pbuf_put_4(pb, *reslen); /* XXX */ 132e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 133e73a712fSpooka 134e73a712fSpooka puffs_cc_yield(pcc); 135e73a712fSpooka 136e73a712fSpooka p9pbuf_get_4(pb, &count); 137e73a712fSpooka 138e73a712fSpooka /* 139e73a712fSpooka * if count is 0, assume we at end-of-dir. dfp is no longer 140e73a712fSpooka * useful, so nuke it 141e73a712fSpooka */ 142e73a712fSpooka if (count == 0) { 143e73a712fSpooka *eofflag = 1; 144e73a712fSpooka releasedf(pcc, dfp); 145e73a712fSpooka goto out; 146e73a712fSpooka } 147e73a712fSpooka 148e73a712fSpooka while (count > 0) { 149e73a712fSpooka if (!proto_getstat(pb, &va, &name, &statsize)) { 150e73a712fSpooka rv = EINVAL; 151e73a712fSpooka goto out; 152e73a712fSpooka } 153e73a712fSpooka 154e73a712fSpooka puffs_nextdent(&dent, name, va.va_fileid, 155e73a712fSpooka puffs_vtype2dt(va.va_type), reslen); 156e73a712fSpooka 157e73a712fSpooka count -= statsize; 158e73a712fSpooka *readoff += statsize; 159e73a712fSpooka dfp->seekoff += statsize; 160e73a712fSpooka } 161e73a712fSpooka 162e73a712fSpooka storedf(p9n, dfp); 163e73a712fSpooka 164e73a712fSpooka out: 165e73a712fSpooka RETURN(rv); 166e73a712fSpooka } 167e73a712fSpooka 168e73a712fSpooka int 169e73a712fSpooka puffs9p_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *vap, 170e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 171e73a712fSpooka { 172e73a712fSpooka AUTOVAR(pcc); 173e73a712fSpooka struct puffs_node *pn = opc; 174e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 175e73a712fSpooka 176e73a712fSpooka pb = p9pbuf_make(p9p->maxreq, P9PB_OUT); 177e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 178e73a712fSpooka p9pbuf_put_2(pb, tag); 179e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 180e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 181e73a712fSpooka puffs_cc_yield(pcc); 182e73a712fSpooka 183e73a712fSpooka rv = proto_expect_stat(pb, &pn->pn_va); 184e73a712fSpooka if (rv) 185e73a712fSpooka goto out; 186e73a712fSpooka 187e73a712fSpooka memcpy(vap, &pn->pn_va, sizeof(struct vattr)); 188e73a712fSpooka 189e73a712fSpooka out: 190e73a712fSpooka RETURN(rv); 191e73a712fSpooka } 192e73a712fSpooka 193e73a712fSpooka int 194e73a712fSpooka puffs9p_node_setattr(struct puffs_cc *pcc, void *opc, 195e73a712fSpooka const struct vattr *va, const struct puffs_cred *pcr, pid_t pid) 196e73a712fSpooka { 197e73a712fSpooka AUTOVAR(pcc); 198e73a712fSpooka struct puffs_node *pn = opc; 199e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 200e73a712fSpooka 201e73a712fSpooka pb = p9pbuf_make(p9p->maxreq, P9PB_OUT); 202e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 203e73a712fSpooka p9pbuf_put_2(pb, tag); 204e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 205e73a712fSpooka proto_make_stat(pb, va, NULL); 206e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 207e73a712fSpooka puffs_cc_yield(pcc); 208e73a712fSpooka 209e73a712fSpooka if (pb->type != P9PROTO_R_WSTAT) 210e73a712fSpooka rv = EPROTO; 211e73a712fSpooka 212e73a712fSpooka RETURN(rv); 213e73a712fSpooka } 214e73a712fSpooka 215e73a712fSpooka /* 216e73a712fSpooka * Ok, time to get clever. There are two possible cases: we are 217e73a712fSpooka * opening a file or we are opening a directory. 218e73a712fSpooka * 219e73a712fSpooka * If it's a directory, don't bother opening it here, but rather 220e73a712fSpooka * wait until readdir, since it's probable we need to be able to 221e73a712fSpooka * open a directory there in any case. 222e73a712fSpooka * 223*436cfd0dSpooka * If it's a regular file, open it here with whatever credentials 224*436cfd0dSpooka * we happen to have. Let the upper layers of the kernel worry 225*436cfd0dSpooka * about permission control. 226e73a712fSpooka * 227*436cfd0dSpooka * XXX: this does not work fully for the mmap case 228e73a712fSpooka */ 229e73a712fSpooka int 230e73a712fSpooka puffs9p_node_open(struct puffs_cc *pcc, void *opc, int mode, 231e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 232e73a712fSpooka { 233e73a712fSpooka struct puffs9p *p9p = puffs_cc_getspecific(pcc); 234e73a712fSpooka struct puffs_node *pn = opc; 235e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 236e73a712fSpooka p9pfid_t nfid; 237e73a712fSpooka int error = 0; 238e73a712fSpooka 239e73a712fSpooka p9n->opencount++; 240*436cfd0dSpooka if (pn->pn_va.va_type != VDIR) { 241*436cfd0dSpooka if (mode & FREAD && p9n->fid_read == P9P_INVALFID) { 242e73a712fSpooka nfid = NEXTFID(p9p); 243e73a712fSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 244*436cfd0dSpooka P9PROTO_OMODE_READ); 245e73a712fSpooka if (error) 246e73a712fSpooka return error; 247*436cfd0dSpooka p9n->fid_read = nfid; 248*436cfd0dSpooka } 249*436cfd0dSpooka if (mode & FWRITE && p9n->fid_write == P9P_INVALFID) { 250*436cfd0dSpooka nfid = NEXTFID(p9p); 251*436cfd0dSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 252*436cfd0dSpooka P9PROTO_OMODE_WRITE); 253*436cfd0dSpooka if (error) 254*436cfd0dSpooka return error; 255*436cfd0dSpooka p9n->fid_write = nfid; 256*436cfd0dSpooka } 257e73a712fSpooka } 258e73a712fSpooka 259e73a712fSpooka return 0; 260e73a712fSpooka } 261e73a712fSpooka 262e73a712fSpooka int 263e73a712fSpooka puffs9p_node_close(struct puffs_cc *pcc, void *opc, int flags, 264e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 265e73a712fSpooka { 266e73a712fSpooka struct puffs_node *pn = opc; 267e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 268e73a712fSpooka 269*436cfd0dSpooka if (--p9n->opencount == 0) { 270*436cfd0dSpooka if (pn->pn_va.va_type == VDIR) { 271e73a712fSpooka nukealldf(pcc, p9n); 272*436cfd0dSpooka } else { 273*436cfd0dSpooka if (p9n->fid_read != P9P_INVALFID) { 274*436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_read, 0); 275*436cfd0dSpooka p9n->fid_read = P9P_INVALFID; 276*436cfd0dSpooka } 277*436cfd0dSpooka if (p9n->fid_write != P9P_INVALFID) { 278*436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_write, 0); 279*436cfd0dSpooka p9n->fid_write = P9P_INVALFID; 280*436cfd0dSpooka } 281*436cfd0dSpooka } 282*436cfd0dSpooka } 283e73a712fSpooka 284e73a712fSpooka return 0; 285e73a712fSpooka } 286e73a712fSpooka 287e73a712fSpooka int 288e73a712fSpooka puffs9p_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf, 289e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *pcr, 290e73a712fSpooka int ioflag) 291e73a712fSpooka { 292e73a712fSpooka AUTOVAR(pcc); 293e73a712fSpooka struct puffs_node *pn = opc; 294e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 295e73a712fSpooka uint32_t count; 296e73a712fSpooka size_t nread; 297e73a712fSpooka 298e73a712fSpooka nread = 0; 299e73a712fSpooka while (*resid > 0) { 300e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 301e73a712fSpooka p9pbuf_put_2(pb, tag); 302*436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_read); 303e73a712fSpooka p9pbuf_put_8(pb, offset+nread); 304e73a712fSpooka p9pbuf_put_4(pb, MIN((uint32_t)*resid,p9p->maxreq-24)); 305e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 306e73a712fSpooka puffs_cc_yield(pcc); 307e73a712fSpooka 308e73a712fSpooka if (pb->type != P9PROTO_R_READ) { 309e73a712fSpooka rv = EPROTO; 310e73a712fSpooka break; 311e73a712fSpooka } 312e73a712fSpooka 313e73a712fSpooka p9pbuf_get_4(pb, &count); 314e73a712fSpooka if (!p9pbuf_read_data(pb, buf + nread, count)) { 315e73a712fSpooka rv = EPROTO; 316e73a712fSpooka break; 317e73a712fSpooka } 318e73a712fSpooka 319e73a712fSpooka *resid -= count; 320e73a712fSpooka nread += count; 321e73a712fSpooka 322e73a712fSpooka p9pbuf_recycle(pb, P9PB_OUT); 323e73a712fSpooka } 324e73a712fSpooka 325e73a712fSpooka RETURN(rv); 326e73a712fSpooka } 327e73a712fSpooka 328e73a712fSpooka int 329e73a712fSpooka puffs9p_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf, 330e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *cred, 331e73a712fSpooka int ioflag) 332e73a712fSpooka { 333e73a712fSpooka AUTOVAR(pcc); 334e73a712fSpooka struct puffs_node *pn = opc; 335e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 336e73a712fSpooka uint32_t chunk, count; 337e73a712fSpooka size_t nwrite; 338e73a712fSpooka 339e73a712fSpooka if (ioflag & PUFFS_IO_APPEND) 340e73a712fSpooka offset = pn->pn_va.va_size; 341e73a712fSpooka 342e73a712fSpooka nwrite = 0; 343e73a712fSpooka while (*resid > 0) { 344e73a712fSpooka chunk = MIN(*resid, p9p->maxreq-32); 345e73a712fSpooka 346e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WRITE); 347e73a712fSpooka p9pbuf_put_2(pb, tag); 348*436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_write); 349e73a712fSpooka p9pbuf_put_8(pb, offset+nwrite); 350e73a712fSpooka p9pbuf_put_4(pb, chunk); 351e73a712fSpooka p9pbuf_write_data(pb, buf+nwrite, chunk); 352e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 353e73a712fSpooka puffs_cc_yield(pcc); 354e73a712fSpooka 355e73a712fSpooka if (pb->type != P9PROTO_R_WRITE) { 356e73a712fSpooka rv = EPROTO; 357e73a712fSpooka break; 358e73a712fSpooka } 359e73a712fSpooka 360e73a712fSpooka p9pbuf_get_4(pb, &count); 361e73a712fSpooka *resid -= count; 362e73a712fSpooka nwrite += count; 363e73a712fSpooka 364e73a712fSpooka if (count != chunk) { 365e73a712fSpooka rv = EPROTO; 366e73a712fSpooka break; 367e73a712fSpooka } 368e73a712fSpooka 369e73a712fSpooka p9pbuf_recycle(pb, P9PB_OUT); 370e73a712fSpooka } 371e73a712fSpooka 372e73a712fSpooka RETURN(rv); 373e73a712fSpooka } 374e73a712fSpooka 375e73a712fSpooka static int 376e73a712fSpooka nodecreate(struct puffs_cc *pcc, struct puffs_node *pn, void **newnode, 377e73a712fSpooka const char *name, const struct vattr *vap, uint32_t dirbit) 378e73a712fSpooka { 379e73a712fSpooka AUTOVAR(pcc); 380e73a712fSpooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 381e73a712fSpooka struct puffs_node *pn_new; 382e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 383e73a712fSpooka p9pfid_t nfid = NEXTFID(p9p); 384e73a712fSpooka struct qid9p nqid; 385e73a712fSpooka int tries = 0; 386e73a712fSpooka 387e73a712fSpooka again: 388e73a712fSpooka if (++tries > 5) { 389e73a712fSpooka rv = EPROTO; 390e73a712fSpooka goto out; 391e73a712fSpooka } 392e73a712fSpooka 393e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, nfid); 394e73a712fSpooka if (rv) 395e73a712fSpooka goto out; 396e73a712fSpooka 397e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_CREATE); 398e73a712fSpooka p9pbuf_put_2(pb, tag); 399e73a712fSpooka p9pbuf_put_4(pb, nfid); 400e73a712fSpooka p9pbuf_put_str(pb, name); 401e73a712fSpooka p9pbuf_put_4(pb, dirbit | (vap->va_mode & 0777)); 402e73a712fSpooka p9pbuf_put_1(pb, 0); 403e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 404e73a712fSpooka puffs_cc_yield(pcc); 405e73a712fSpooka 406e73a712fSpooka rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid); 407e73a712fSpooka if (rv) 408e73a712fSpooka goto out; 409e73a712fSpooka 410e73a712fSpooka /* 411e73a712fSpooka * Now, little problem here: create returns an *open* fid. 412e73a712fSpooka * So, clunk it and walk the parent directory to get a fid 413e73a712fSpooka * which is not open for I/O yet. 414e73a712fSpooka */ 415e73a712fSpooka proto_cc_clunkfid(pcc, nfid, 0); 416e73a712fSpooka nfid = NEXTFID(p9p); 417e73a712fSpooka 418e73a712fSpooka p9pbuf_recycle(pb, P9PB_OUT); 419e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 420e73a712fSpooka p9pbuf_put_2(pb, tag); 421e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 422e73a712fSpooka p9pbuf_put_4(pb, nfid); 423e73a712fSpooka p9pbuf_put_2(pb, 1); 424e73a712fSpooka p9pbuf_put_str(pb, name); 425e73a712fSpooka 426e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 427e73a712fSpooka puffs_cc_yield(pcc); 428e73a712fSpooka 429e73a712fSpooka /* 430e73a712fSpooka * someone removed it already? try again 431e73a712fSpooka * note: this is kind of lose/lose 432e73a712fSpooka */ 433e73a712fSpooka if (pb->type != P9PROTO_R_WALK) 434e73a712fSpooka goto again; 435e73a712fSpooka 436e73a712fSpooka pn_new = newp9pnode_va(pu, vap, nfid); 437e73a712fSpooka qid2vattr(&pn_new->pn_va, &nqid); 438e73a712fSpooka *newnode = pn_new; 439e73a712fSpooka 440e73a712fSpooka out: 441e73a712fSpooka RETURN(rv); 442e73a712fSpooka } 443e73a712fSpooka 444e73a712fSpooka int 445e73a712fSpooka puffs9p_node_create(struct puffs_cc *pcc, void *opc, void **newnode, 446e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 447e73a712fSpooka { 448e73a712fSpooka 449e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, va, 0); 450e73a712fSpooka } 451e73a712fSpooka 452e73a712fSpooka int 453e73a712fSpooka puffs9p_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode, 454e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 455e73a712fSpooka { 456e73a712fSpooka 457e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, 458e73a712fSpooka va, P9PROTO_CPERM_DIR); 459e73a712fSpooka } 460e73a712fSpooka 461e73a712fSpooka /* 462e73a712fSpooka * Need to be a bit clever again: the fid is clunked no matter if 463e73a712fSpooka * the remove succeeds or not. Re-getting a fid would be way too 464e73a712fSpooka * difficult in case the remove failed for a valid reason (directory 465e73a712fSpooka * not empty etcetc.). So walk ourselves another fid to prod the 466e73a712fSpooka * ice with. 467e73a712fSpooka */ 468e73a712fSpooka static int 469e73a712fSpooka noderemove(struct puffs_cc *pcc, struct p9pnode *p9n) 470e73a712fSpooka { 471e73a712fSpooka AUTOVAR(pcc); 472e73a712fSpooka p9pfid_t testfid = NEXTFID(p9p); 473e73a712fSpooka 474e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, testfid); 475e73a712fSpooka 476e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_REMOVE); 477e73a712fSpooka p9pbuf_put_2(pb, tag); 478e73a712fSpooka p9pbuf_put_4(pb, testfid); 479e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 480e73a712fSpooka puffs_cc_yield(pcc); 481e73a712fSpooka 482e73a712fSpooka if (pb->type != P9PROTO_R_REMOVE) { 483e73a712fSpooka rv = EPROTO; 484e73a712fSpooka } else { 485e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_base, 0); 486e73a712fSpooka p9n->fid_base = P9P_INVALFID; 487e73a712fSpooka } 488e73a712fSpooka 489e73a712fSpooka RETURN(rv); 490e73a712fSpooka } 491e73a712fSpooka 492e73a712fSpooka int 493e73a712fSpooka puffs9p_node_remove(struct puffs_cc *pcc, void *opc, void *targ, 494e73a712fSpooka const struct puffs_cn *pcn) 495e73a712fSpooka { 496e73a712fSpooka struct puffs_node *pn = targ; 497e73a712fSpooka 498e73a712fSpooka if (pn->pn_va.va_type == VDIR) 499e73a712fSpooka return EISDIR; 500e73a712fSpooka 501e73a712fSpooka return noderemove(pcc, pn->pn_data); 502e73a712fSpooka } 503e73a712fSpooka 504e73a712fSpooka int 505e73a712fSpooka puffs9p_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ, 506e73a712fSpooka const struct puffs_cn *pcn) 507e73a712fSpooka { 508e73a712fSpooka struct puffs_node *pn = targ; 509e73a712fSpooka 510e73a712fSpooka if (pn->pn_va.va_type != VDIR) 511e73a712fSpooka return ENOTDIR; 512e73a712fSpooka 513e73a712fSpooka return noderemove(pcc, pn->pn_data); 514e73a712fSpooka } 515e73a712fSpooka 516e73a712fSpooka /* 517e73a712fSpooka * 9P supports renames only for regular files within a directory 518e73a712fSpooka * from what I could tell. So just support in-directory renames 519e73a712fSpooka * for now. 520e73a712fSpooka */ 521e73a712fSpooka int 522e73a712fSpooka puffs9p_node_rename(struct puffs_cc *pcc, void *opc, void *src, 523e73a712fSpooka const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 524e73a712fSpooka const struct puffs_cn *pcn_targ) 525e73a712fSpooka { 526e73a712fSpooka AUTOVAR(pcc); 527e73a712fSpooka struct puffs_node *pn_src = src; 528e73a712fSpooka struct p9pnode *p9n_src = pn_src->pn_data; 529e73a712fSpooka 530e73a712fSpooka if (opc != targ_dir) { 531e73a712fSpooka rv = EOPNOTSUPP; 532e73a712fSpooka goto out; 533e73a712fSpooka } 534e73a712fSpooka 535e73a712fSpooka /* 9P doesn't allow to overwrite in rename */ 536e73a712fSpooka if (targ) { 537e73a712fSpooka struct puffs_node *pn_targ = targ; 538e73a712fSpooka 539e73a712fSpooka rv = noderemove(pcc, pn_targ->pn_data); 540e73a712fSpooka if (rv) 541e73a712fSpooka return rv; 542e73a712fSpooka } 543e73a712fSpooka 544e73a712fSpooka pb = p9pbuf_make(p9p->maxreq, P9PB_OUT); 545e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 546e73a712fSpooka p9pbuf_put_2(pb, tag); 547e73a712fSpooka p9pbuf_put_4(pb, p9n_src->fid_base); 548e73a712fSpooka proto_make_stat(pb, NULL, pcn_targ->pcn_name); 549e73a712fSpooka outbuf_enqueue(p9p, pb, pcc, tag); 550e73a712fSpooka puffs_cc_yield(pcc); 551e73a712fSpooka 552e73a712fSpooka if (pb->type != P9PROTO_R_WSTAT) 553e73a712fSpooka rv = EPROTO; 554e73a712fSpooka 555e73a712fSpooka out: 556e73a712fSpooka RETURN(rv); 557e73a712fSpooka } 558e73a712fSpooka 559e73a712fSpooka /* 560e73a712fSpooka * - "here's one" 561e73a712fSpooka * - "9P" 562e73a712fSpooka * ~ "i'm not dead" 563e73a712fSpooka * - "you're not fooling anyone you know, you'll be stone dead in a minute 564e73a712fSpooka * - "he says he's not quite dead" 565e73a712fSpooka * - "isn't there anything you could do?" 566e73a712fSpooka * - *clunk*! 567e73a712fSpooka * - "thanks" 568e73a712fSpooka */ 569e73a712fSpooka int 570e73a712fSpooka puffs9p_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid) 571e73a712fSpooka { 572e73a712fSpooka #if 0 573e73a712fSpooka if (p9n->fid_open != P9P_INVALFID) 574e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_open, 0); 575e73a712fSpooka #endif 576e73a712fSpooka 577e73a712fSpooka return 0; 578e73a712fSpooka } 579