1*30c29b1bSpooka /* $NetBSD: node.c,v 1.20 2008/08/22 17:44:14 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*30c29b1bSpooka __RCSID("$NetBSD: node.c,v 1.20 2008/08/22 17:44:14 pooka Exp $"); 31e73a712fSpooka #endif /* !lint */ 32e73a712fSpooka 33e73a712fSpooka #include <assert.h> 34e73a712fSpooka #include <errno.h> 35e73a712fSpooka #include <puffs.h> 36e73a712fSpooka #include <stdio.h> 375252a3b0Spooka #include <stdlib.h> 38e73a712fSpooka 39e73a712fSpooka #include "ninepuffs.h" 40e73a712fSpooka #include "nineproto.h" 41e73a712fSpooka 42e73a712fSpooka static void * 43e73a712fSpooka nodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 44e73a712fSpooka { 45e73a712fSpooka struct vattr *vap = &pn->pn_va; 46e73a712fSpooka struct qid9p *qid = arg; 47e73a712fSpooka 48*30c29b1bSpooka if (vap->va_fileid == qid->qidpath && vap->va_gen == qid->qidvers) 49e73a712fSpooka return pn; 50e73a712fSpooka 51e73a712fSpooka return NULL; 52e73a712fSpooka } 53e73a712fSpooka 546360ca31Spooka static int 5521913eabSpooka do_getattr(struct puffs_usermount *pu, struct puffs_node *pn, struct vattr *vap) 566360ca31Spooka { 5721913eabSpooka AUTOVAR(pu); 586360ca31Spooka struct p9pnode *p9n = pn->pn_data; 596360ca31Spooka 606360ca31Spooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 616360ca31Spooka p9pbuf_put_2(pb, tag); 626360ca31Spooka p9pbuf_put_4(pb, p9n->fid_base); 636360ca31Spooka GETRESPONSE(pb); 646360ca31Spooka 656360ca31Spooka rv = proto_expect_stat(pb, vap); 666360ca31Spooka 676360ca31Spooka out: 686360ca31Spooka RETURN(rv); 696360ca31Spooka } 706360ca31Spooka 716360ca31Spooka int 7221913eabSpooka puffs9p_node_getattr(struct puffs_usermount *pu, void *opc, struct vattr *vap, 736a3d9a18Spooka const struct puffs_cred *pcr) 746360ca31Spooka { 756360ca31Spooka struct puffs_node *pn = opc; 766360ca31Spooka int rv; 776360ca31Spooka 7821913eabSpooka rv = do_getattr(pu, pn, &pn->pn_va); 796360ca31Spooka if (rv == 0) 806360ca31Spooka memcpy(vap, &pn->pn_va, sizeof(struct vattr)); 816360ca31Spooka return rv; 826360ca31Spooka } 836360ca31Spooka 84e73a712fSpooka int 8521913eabSpooka puffs9p_node_lookup(struct puffs_usermount *pu, void *opc, struct puffs_newinfo *pni, 86e73a712fSpooka const struct puffs_cn *pcn) 87e73a712fSpooka { 8821913eabSpooka AUTOVAR(pu); 89*30c29b1bSpooka struct vattr va; 90e73a712fSpooka struct puffs_node *pn, *pn_dir = opc; 91e73a712fSpooka struct p9pnode *p9n_dir = pn_dir->pn_data; 92e73a712fSpooka p9ptag_t tfid = NEXTFID(p9p); 93e73a712fSpooka struct qid9p newqid; 94e73a712fSpooka uint16_t nqid; 95e73a712fSpooka 96e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 97e73a712fSpooka p9pbuf_put_2(pb, tag); 98e73a712fSpooka p9pbuf_put_4(pb, p9n_dir->fid_base); 99e73a712fSpooka p9pbuf_put_4(pb, tfid); 100e73a712fSpooka p9pbuf_put_2(pb, 1); 101e73a712fSpooka p9pbuf_put_str(pb, pcn->pcn_name); 1025069b5dfSpooka GETRESPONSE(pb); 103e73a712fSpooka 104e73a712fSpooka rv = proto_expect_walk_nqids(pb, &nqid); 105e73a712fSpooka if (rv) { 106e73a712fSpooka rv = ENOENT; 107e73a712fSpooka goto out; 108e73a712fSpooka } 1090e7bdfc1Spooka if (nqid != 1) { 110e73a712fSpooka rv = EPROTO; 111e73a712fSpooka goto out; 112e73a712fSpooka } 1130e7bdfc1Spooka if ((rv = proto_getqid(pb, &newqid))) 1140e7bdfc1Spooka goto out; 115e73a712fSpooka 116*30c29b1bSpooka /* we get the parent vers in walk(?) compensate */ 117*30c29b1bSpooka p9pbuf_recycleout(pb); 118*30c29b1bSpooka tag = NEXTTAG(p9p); 119*30c29b1bSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 120*30c29b1bSpooka p9pbuf_put_2(pb, tag); 121*30c29b1bSpooka p9pbuf_put_4(pb, tfid); 122*30c29b1bSpooka GETRESPONSE(pb); 123*30c29b1bSpooka if ((rv = proto_expect_stat(pb, &va)) != 0) { 124*30c29b1bSpooka proto_cc_clunkfid(pu, tfid, 0); 125*30c29b1bSpooka rv = ENOENT; 126*30c29b1bSpooka goto out; 127*30c29b1bSpooka } 128*30c29b1bSpooka if (newqid.qidpath != va.va_fileid) { 129*30c29b1bSpooka proto_cc_clunkfid(pu, tfid, 0); 130*30c29b1bSpooka rv = EPROTO; 131*30c29b1bSpooka goto out; 132*30c29b1bSpooka } 133*30c29b1bSpooka newqid.qidvers = va.va_gen; 134*30c29b1bSpooka 135e73a712fSpooka pn = puffs_pn_nodewalk(pu, nodecmp, &newqid); 136e73a712fSpooka if (pn == NULL) 137e73a712fSpooka pn = newp9pnode_qid(pu, &newqid, tfid); 138e73a712fSpooka else 13921913eabSpooka proto_cc_clunkfid(pu, tfid, 0); 140*30c29b1bSpooka /* assert pn */ 141*30c29b1bSpooka memcpy(&pn->pn_va, &va, sizeof(va)); 1426360ca31Spooka 1436596e0c9Spooka puffs_newinfo_setcookie(pni, pn); 1446596e0c9Spooka puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 1456596e0c9Spooka puffs_newinfo_setsize(pni, pn->pn_va.va_size); 1466596e0c9Spooka puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 147e73a712fSpooka 148e73a712fSpooka out: 149e73a712fSpooka RETURN(rv); 150e73a712fSpooka } 151e73a712fSpooka 152e73a712fSpooka /* 153e73a712fSpooka * Problem is that 9P doesn't allow seeking into a directory. So we 154e73a712fSpooka * maintain a list of active fids for any given directory. They 155e73a712fSpooka * start living at the first read and exist either until the directory 156e73a712fSpooka * is closed or until they reach the end. 157e73a712fSpooka */ 158e73a712fSpooka int 15921913eabSpooka puffs9p_node_readdir(struct puffs_usermount *pu, void *opc, struct dirent *dent, 160e73a712fSpooka off_t *readoff, size_t *reslen, const struct puffs_cred *pcr, 161e73a712fSpooka int *eofflag, off_t *cookies, size_t *ncookies) 162e73a712fSpooka { 16321913eabSpooka AUTOVAR(pu); 164e73a712fSpooka struct puffs_node *pn = opc; 165e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 166e73a712fSpooka struct vattr va; 167e73a712fSpooka struct dirfid *dfp; 168e73a712fSpooka char *name; 169e73a712fSpooka uint32_t count; 170e73a712fSpooka uint16_t statsize; 171e73a712fSpooka 17221913eabSpooka rv = getdfwithoffset(pu, p9n, *readoff, &dfp); 173e73a712fSpooka if (rv) 174e73a712fSpooka goto out; 175e73a712fSpooka 176e73a712fSpooka tag = NEXTTAG(p9p); 177e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 178e73a712fSpooka p9pbuf_put_2(pb, tag); 179e73a712fSpooka p9pbuf_put_4(pb, dfp->fid); 180e73a712fSpooka p9pbuf_put_8(pb, *readoff); 181e73a712fSpooka p9pbuf_put_4(pb, *reslen); /* XXX */ 1825069b5dfSpooka GETRESPONSE(pb); 183e73a712fSpooka 184e73a712fSpooka p9pbuf_get_4(pb, &count); 185e73a712fSpooka 186e73a712fSpooka /* 187e73a712fSpooka * if count is 0, assume we at end-of-dir. dfp is no longer 188e73a712fSpooka * useful, so nuke it 189e73a712fSpooka */ 190e73a712fSpooka if (count == 0) { 191e73a712fSpooka *eofflag = 1; 19221913eabSpooka releasedf(pu, dfp); 193e73a712fSpooka goto out; 194e73a712fSpooka } 195e73a712fSpooka 196e73a712fSpooka while (count > 0) { 1979fec8114Spooka if ((rv = proto_getstat(pb, &va, &name, &statsize))) { 1989fec8114Spooka /* 1999fec8114Spooka * If there was an error, it's unlikely we'll be 2009fec8114Spooka * coming back, so just nuke the dfp. If we do 2019fec8114Spooka * come back for some strange reason, we'll just 2029fec8114Spooka * regen it. 2039fec8114Spooka */ 20421913eabSpooka releasedf(pu, dfp); 205e73a712fSpooka goto out; 2069fec8114Spooka } 207e73a712fSpooka 208e73a712fSpooka puffs_nextdent(&dent, name, va.va_fileid, 209e73a712fSpooka puffs_vtype2dt(va.va_type), reslen); 210e73a712fSpooka 211e73a712fSpooka count -= statsize; 212e73a712fSpooka *readoff += statsize; 213e73a712fSpooka dfp->seekoff += statsize; 2145252a3b0Spooka free(name); 215e73a712fSpooka } 216e73a712fSpooka 217e73a712fSpooka storedf(p9n, dfp); 218e73a712fSpooka 219e73a712fSpooka out: 220e73a712fSpooka RETURN(rv); 221e73a712fSpooka } 222e73a712fSpooka 223e73a712fSpooka int 22421913eabSpooka puffs9p_node_setattr(struct puffs_usermount *pu, void *opc, 2256a3d9a18Spooka const struct vattr *va, const struct puffs_cred *pcr) 226e73a712fSpooka { 22721913eabSpooka AUTOVAR(pu); 228e73a712fSpooka struct puffs_node *pn = opc; 229e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 230e73a712fSpooka 231e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 232e73a712fSpooka p9pbuf_put_2(pb, tag); 233e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 2343ac2e6b4Spooka proto_make_stat(pb, va, NULL, pn->pn_va.va_type); 2355069b5dfSpooka GETRESPONSE(pb); 236e73a712fSpooka 2370e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 238e73a712fSpooka rv = EPROTO; 239e73a712fSpooka 2400b0e609bSpooka out: 241e73a712fSpooka RETURN(rv); 242e73a712fSpooka } 243e73a712fSpooka 244e73a712fSpooka /* 245e73a712fSpooka * Ok, time to get clever. There are two possible cases: we are 246e73a712fSpooka * opening a file or we are opening a directory. 247e73a712fSpooka * 248e73a712fSpooka * If it's a directory, don't bother opening it here, but rather 249e73a712fSpooka * wait until readdir, since it's probable we need to be able to 250e73a712fSpooka * open a directory there in any case. 251e73a712fSpooka * 252436cfd0dSpooka * If it's a regular file, open it here with whatever credentials 253436cfd0dSpooka * we happen to have. Let the upper layers of the kernel worry 254436cfd0dSpooka * about permission control. 255e73a712fSpooka */ 256e73a712fSpooka int 25721913eabSpooka puffs9p_node_open(struct puffs_usermount *pu, void *opc, int mode, 2586a3d9a18Spooka const struct puffs_cred *pcr) 259e73a712fSpooka { 26021913eabSpooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 26121913eabSpooka struct puffs9p *p9p = puffs_getspecific(pu); 262e73a712fSpooka struct puffs_node *pn = opc; 263e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 264e73a712fSpooka p9pfid_t nfid; 265e73a712fSpooka int error = 0; 266e73a712fSpooka 267dca252d8Spooka puffs_setback(pcc, PUFFS_SETBACK_INACT_N1); 268436cfd0dSpooka if (pn->pn_va.va_type != VDIR) { 269436cfd0dSpooka if (mode & FREAD && p9n->fid_read == P9P_INVALFID) { 270e73a712fSpooka nfid = NEXTFID(p9p); 27121913eabSpooka error = proto_cc_open(pu, p9n->fid_base, nfid, 272436cfd0dSpooka P9PROTO_OMODE_READ); 273e73a712fSpooka if (error) 274e73a712fSpooka return error; 275436cfd0dSpooka p9n->fid_read = nfid; 276436cfd0dSpooka } 277436cfd0dSpooka if (mode & FWRITE && p9n->fid_write == P9P_INVALFID) { 278436cfd0dSpooka nfid = NEXTFID(p9p); 27921913eabSpooka error = proto_cc_open(pu, p9n->fid_base, nfid, 280436cfd0dSpooka P9PROTO_OMODE_WRITE); 281436cfd0dSpooka if (error) 282436cfd0dSpooka return error; 283436cfd0dSpooka p9n->fid_write = nfid; 284436cfd0dSpooka } 285e73a712fSpooka } 286e73a712fSpooka 287e73a712fSpooka return 0; 288e73a712fSpooka } 289e73a712fSpooka 290e73a712fSpooka int 29121913eabSpooka puffs9p_node_inactive(struct puffs_usermount *pu, void *opc) 292e73a712fSpooka { 293e73a712fSpooka struct puffs_node *pn = opc; 294e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 295e73a712fSpooka 296436cfd0dSpooka if (pn->pn_va.va_type == VDIR) { 29721913eabSpooka nukealldf(pu, p9n); 298436cfd0dSpooka } else { 299436cfd0dSpooka if (p9n->fid_read != P9P_INVALFID) { 30021913eabSpooka proto_cc_clunkfid(pu, p9n->fid_read, 0); 301436cfd0dSpooka p9n->fid_read = P9P_INVALFID; 302436cfd0dSpooka } 303436cfd0dSpooka if (p9n->fid_write != P9P_INVALFID) { 30421913eabSpooka proto_cc_clunkfid(pu, p9n->fid_write, 0); 305436cfd0dSpooka p9n->fid_write = P9P_INVALFID; 306436cfd0dSpooka } 307436cfd0dSpooka } 308e73a712fSpooka 309e73a712fSpooka return 0; 310e73a712fSpooka } 311e73a712fSpooka 312e73a712fSpooka int 31321913eabSpooka puffs9p_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf, 314e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *pcr, 315e73a712fSpooka int ioflag) 316e73a712fSpooka { 31721913eabSpooka AUTOVAR(pu); 318e73a712fSpooka struct puffs_node *pn = opc; 319e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 320e73a712fSpooka uint32_t count; 321e73a712fSpooka size_t nread; 322e73a712fSpooka 323e73a712fSpooka nread = 0; 324*30c29b1bSpooka while (*resid > 0 && offset+nread < pn->pn_va.va_size) { 325e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 326e73a712fSpooka p9pbuf_put_2(pb, tag); 327436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_read); 328e73a712fSpooka p9pbuf_put_8(pb, offset+nread); 329e73a712fSpooka p9pbuf_put_4(pb, MIN((uint32_t)*resid,p9p->maxreq-24)); 3305069b5dfSpooka GETRESPONSE(pb); 331e73a712fSpooka 3320e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_READ) { 333e73a712fSpooka rv = EPROTO; 334e73a712fSpooka break; 335e73a712fSpooka } 336e73a712fSpooka 337e73a712fSpooka p9pbuf_get_4(pb, &count); 3380e7bdfc1Spooka if ((rv = p9pbuf_read_data(pb, buf + nread, count))) 339e73a712fSpooka break; 340e73a712fSpooka 341*30c29b1bSpooka if (count == 0) 342*30c29b1bSpooka break; 343*30c29b1bSpooka 344e73a712fSpooka *resid -= count; 345e73a712fSpooka nread += count; 346e73a712fSpooka 3470e7bdfc1Spooka p9pbuf_recycleout(pb); 348e73a712fSpooka } 349e73a712fSpooka 3500b0e609bSpooka out: 351e73a712fSpooka RETURN(rv); 352e73a712fSpooka } 353e73a712fSpooka 354e73a712fSpooka int 35521913eabSpooka puffs9p_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf, 356e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *cred, 357e73a712fSpooka int ioflag) 358e73a712fSpooka { 35921913eabSpooka AUTOVAR(pu); 360e73a712fSpooka struct puffs_node *pn = opc; 361e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 362e73a712fSpooka uint32_t chunk, count; 363e73a712fSpooka size_t nwrite; 364e73a712fSpooka 365e73a712fSpooka if (ioflag & PUFFS_IO_APPEND) 366e73a712fSpooka offset = pn->pn_va.va_size; 367e73a712fSpooka 368e73a712fSpooka nwrite = 0; 369e73a712fSpooka while (*resid > 0) { 370e73a712fSpooka chunk = MIN(*resid, p9p->maxreq-32); 371e73a712fSpooka 372e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WRITE); 373e73a712fSpooka p9pbuf_put_2(pb, tag); 374436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_write); 375e73a712fSpooka p9pbuf_put_8(pb, offset+nwrite); 376e73a712fSpooka p9pbuf_put_4(pb, chunk); 377e73a712fSpooka p9pbuf_write_data(pb, buf+nwrite, chunk); 3785069b5dfSpooka GETRESPONSE(pb); 379e73a712fSpooka 3800e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WRITE) { 381e73a712fSpooka rv = EPROTO; 382e73a712fSpooka break; 383e73a712fSpooka } 384e73a712fSpooka 385e73a712fSpooka p9pbuf_get_4(pb, &count); 386e73a712fSpooka *resid -= count; 387e73a712fSpooka nwrite += count; 388e73a712fSpooka 389e73a712fSpooka if (count != chunk) { 390e73a712fSpooka rv = EPROTO; 391e73a712fSpooka break; 392e73a712fSpooka } 393e73a712fSpooka 3940e7bdfc1Spooka p9pbuf_recycleout(pb); 395e73a712fSpooka } 396e73a712fSpooka 3970b0e609bSpooka out: 398e73a712fSpooka RETURN(rv); 399e73a712fSpooka } 400e73a712fSpooka 401e73a712fSpooka static int 40221913eabSpooka nodecreate(struct puffs_usermount *pu, struct puffs_node *pn, 4036596e0c9Spooka struct puffs_newinfo *pni, const char *name, 4046596e0c9Spooka const struct vattr *vap, uint32_t dirbit) 405e73a712fSpooka { 40621913eabSpooka AUTOVAR(pu); 407e73a712fSpooka struct puffs_node *pn_new; 408e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 409e73a712fSpooka p9pfid_t nfid = NEXTFID(p9p); 410e73a712fSpooka struct qid9p nqid; 411e73a712fSpooka int tries = 0; 412e73a712fSpooka 413e73a712fSpooka again: 414e73a712fSpooka if (++tries > 5) { 415e73a712fSpooka rv = EPROTO; 416e73a712fSpooka goto out; 417e73a712fSpooka } 418e73a712fSpooka 41921913eabSpooka rv = proto_cc_dupfid(pu, p9n->fid_base, nfid); 420e73a712fSpooka if (rv) 421e73a712fSpooka goto out; 422e73a712fSpooka 423e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_CREATE); 424e73a712fSpooka p9pbuf_put_2(pb, tag); 425e73a712fSpooka p9pbuf_put_4(pb, nfid); 426e73a712fSpooka p9pbuf_put_str(pb, name); 427e73a712fSpooka p9pbuf_put_4(pb, dirbit | (vap->va_mode & 0777)); 428e73a712fSpooka p9pbuf_put_1(pb, 0); 4295069b5dfSpooka GETRESPONSE(pb); 430e73a712fSpooka 431e73a712fSpooka rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid); 432e73a712fSpooka if (rv) 433e73a712fSpooka goto out; 434e73a712fSpooka 435e73a712fSpooka /* 436e73a712fSpooka * Now, little problem here: create returns an *open* fid. 437e73a712fSpooka * So, clunk it and walk the parent directory to get a fid 438e73a712fSpooka * which is not open for I/O yet. 439e73a712fSpooka */ 44021913eabSpooka proto_cc_clunkfid(pu, nfid, 0); 441e73a712fSpooka nfid = NEXTFID(p9p); 442e73a712fSpooka 4430e7bdfc1Spooka p9pbuf_recycleout(pb); 444e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 445e73a712fSpooka p9pbuf_put_2(pb, tag); 446e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 447e73a712fSpooka p9pbuf_put_4(pb, nfid); 448e73a712fSpooka p9pbuf_put_2(pb, 1); 449e73a712fSpooka p9pbuf_put_str(pb, name); 4505069b5dfSpooka GETRESPONSE(pb); 451e73a712fSpooka 452e73a712fSpooka /* 453e73a712fSpooka * someone removed it already? try again 454e73a712fSpooka * note: this is kind of lose/lose 455e73a712fSpooka */ 4560e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 457e73a712fSpooka goto again; 458e73a712fSpooka 459e73a712fSpooka pn_new = newp9pnode_va(pu, vap, nfid); 460e73a712fSpooka qid2vattr(&pn_new->pn_va, &nqid); 4616596e0c9Spooka puffs_newinfo_setcookie(pni, pn_new); 462e73a712fSpooka 463e73a712fSpooka out: 464e73a712fSpooka RETURN(rv); 465e73a712fSpooka } 466e73a712fSpooka 467e73a712fSpooka int 46821913eabSpooka puffs9p_node_create(struct puffs_usermount *pu, void *opc, struct puffs_newinfo *pni, 469e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 470e73a712fSpooka { 471e73a712fSpooka 47221913eabSpooka return nodecreate(pu, opc, pni, pcn->pcn_name, va, 0); 473e73a712fSpooka } 474e73a712fSpooka 475e73a712fSpooka int 47621913eabSpooka puffs9p_node_mkdir(struct puffs_usermount *pu, void *opc, struct puffs_newinfo *pni, 477e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 478e73a712fSpooka { 479e73a712fSpooka 48021913eabSpooka return nodecreate(pu, opc, pni, pcn->pcn_name, 481e73a712fSpooka va, P9PROTO_CPERM_DIR); 482e73a712fSpooka } 483e73a712fSpooka 484e73a712fSpooka /* 485e73a712fSpooka * Need to be a bit clever again: the fid is clunked no matter if 486e73a712fSpooka * the remove succeeds or not. Re-getting a fid would be way too 487e73a712fSpooka * difficult in case the remove failed for a valid reason (directory 488e73a712fSpooka * not empty etcetc.). So walk ourselves another fid to prod the 489e73a712fSpooka * ice with. 490e73a712fSpooka */ 491e73a712fSpooka static int 49221913eabSpooka noderemove(struct puffs_usermount *pu, struct puffs_node *pn) 493e73a712fSpooka { 49421913eabSpooka AUTOVAR(pu); 49591629617Spooka struct p9pnode *p9n = pn->pn_data; 496e73a712fSpooka p9pfid_t testfid = NEXTFID(p9p); 497e73a712fSpooka 49821913eabSpooka rv = proto_cc_dupfid(pu, p9n->fid_base, testfid); 4990b0e609bSpooka if (rv) 5000b0e609bSpooka goto out; 501e73a712fSpooka 502e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_REMOVE); 503e73a712fSpooka p9pbuf_put_2(pb, tag); 504e73a712fSpooka p9pbuf_put_4(pb, testfid); 5050b0e609bSpooka 5060b0e609bSpooka /* 5070b0e609bSpooka * XXX: error handling isn't very robust, but doom is impending 5080b0e609bSpooka * anyway, so just accept we're going belly up and play dead 5090b0e609bSpooka */ 5105069b5dfSpooka GETRESPONSE(pb); 511e73a712fSpooka 5120e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_REMOVE) { 513e73a712fSpooka rv = EPROTO; 514e73a712fSpooka } else { 51521913eabSpooka proto_cc_clunkfid(pu, p9n->fid_base, 0); 516e73a712fSpooka p9n->fid_base = P9P_INVALFID; 51791629617Spooka puffs_pn_remove(pn); 518e73a712fSpooka } 519e73a712fSpooka 5200b0e609bSpooka out: 521b283afddSpooka if (rv == 0) 522b283afddSpooka puffs_setback(pcc, PUFFS_SETBACK_NOREF_N2); 523b283afddSpooka 524e73a712fSpooka RETURN(rv); 525e73a712fSpooka } 526e73a712fSpooka 527e73a712fSpooka int 52821913eabSpooka puffs9p_node_remove(struct puffs_usermount *pu, void *opc, void *targ, 529e73a712fSpooka const struct puffs_cn *pcn) 530e73a712fSpooka { 531e73a712fSpooka struct puffs_node *pn = targ; 532e73a712fSpooka 533e73a712fSpooka if (pn->pn_va.va_type == VDIR) 534e73a712fSpooka return EISDIR; 535e73a712fSpooka 53621913eabSpooka return noderemove(pu, pn); 537e73a712fSpooka } 538e73a712fSpooka 539e73a712fSpooka int 54021913eabSpooka puffs9p_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ, 541e73a712fSpooka const struct puffs_cn *pcn) 542e73a712fSpooka { 543e73a712fSpooka struct puffs_node *pn = targ; 544e73a712fSpooka 545e73a712fSpooka if (pn->pn_va.va_type != VDIR) 546e73a712fSpooka return ENOTDIR; 547e73a712fSpooka 54821913eabSpooka return noderemove(pu, pn); 549e73a712fSpooka } 550e73a712fSpooka 551e73a712fSpooka /* 5523ac2e6b4Spooka * 9P supports renames only for files within a directory 553e73a712fSpooka * from what I could tell. So just support in-directory renames 554e73a712fSpooka * for now. 555e73a712fSpooka */ 556e73a712fSpooka int 55721913eabSpooka puffs9p_node_rename(struct puffs_usermount *pu, void *opc, void *src, 558e73a712fSpooka const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 559e73a712fSpooka const struct puffs_cn *pcn_targ) 560e73a712fSpooka { 56121913eabSpooka AUTOVAR(pu); 562e73a712fSpooka struct puffs_node *pn_src = src; 563e73a712fSpooka struct p9pnode *p9n_src = pn_src->pn_data; 564e73a712fSpooka 565e73a712fSpooka if (opc != targ_dir) { 566e73a712fSpooka rv = EOPNOTSUPP; 567e73a712fSpooka goto out; 568e73a712fSpooka } 569e73a712fSpooka 570e73a712fSpooka /* 9P doesn't allow to overwrite in rename */ 571e73a712fSpooka if (targ) { 572e73a712fSpooka struct puffs_node *pn_targ = targ; 573e73a712fSpooka 57421913eabSpooka rv = noderemove(pu, pn_targ->pn_data); 575e73a712fSpooka if (rv) 576ff4087e2Spooka goto out; 577e73a712fSpooka } 578e73a712fSpooka 579e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 580e73a712fSpooka p9pbuf_put_2(pb, tag); 581e73a712fSpooka p9pbuf_put_4(pb, p9n_src->fid_base); 5823ac2e6b4Spooka proto_make_stat(pb, NULL, pcn_targ->pcn_name, pn_src->pn_va.va_type); 5835069b5dfSpooka GETRESPONSE(pb); 584e73a712fSpooka 5850e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 586e73a712fSpooka rv = EPROTO; 587e73a712fSpooka 588e73a712fSpooka out: 589e73a712fSpooka RETURN(rv); 590e73a712fSpooka } 591e73a712fSpooka 592e73a712fSpooka /* 593e73a712fSpooka * - "here's one" 594e73a712fSpooka * - "9P" 595e73a712fSpooka * ~ "i'm not dead" 596e73a712fSpooka * - "you're not fooling anyone you know, you'll be stone dead in a minute 597e73a712fSpooka * - "he says he's not quite dead" 598e73a712fSpooka * - "isn't there anything you could do?" 599e73a712fSpooka * - *clunk*! 600e73a712fSpooka * - "thanks" 601e73a712fSpooka */ 602e73a712fSpooka int 60321913eabSpooka puffs9p_node_reclaim(struct puffs_usermount *pu, void *opc) 604e73a712fSpooka { 605b283afddSpooka struct puffs_node *pn = opc; 606b283afddSpooka struct p9pnode *p9n = pn->pn_data; 607b283afddSpooka 608b283afddSpooka assert(LIST_EMPTY(&p9n->dir_openlist)); 609b283afddSpooka assert(p9n->fid_read == P9P_INVALFID && p9n->fid_write == P9P_INVALFID); 610b283afddSpooka 61121913eabSpooka proto_cc_clunkfid(pu, p9n->fid_base, 0); 612b283afddSpooka free(p9n); 613b283afddSpooka puffs_pn_put(pn); 614e73a712fSpooka 615e73a712fSpooka return 0; 616e73a712fSpooka } 617