1*26721651Sozaki-r /* $NetBSD: node.c,v 1.22 2019/05/17 08:48:04 ozaki-r 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*26721651Sozaki-r __RCSID("$NetBSD: node.c,v 1.22 2019/05/17 08:48:04 ozaki-r 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 4830c29b1bSpooka 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 65*26721651Sozaki-r rv = proto_expect_stat(pu, 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); 8930c29b1bSpooka 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 11630c29b1bSpooka /* we get the parent vers in walk(?) compensate */ 11730c29b1bSpooka p9pbuf_recycleout(pb); 11830c29b1bSpooka tag = NEXTTAG(p9p); 11930c29b1bSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 12030c29b1bSpooka p9pbuf_put_2(pb, tag); 12130c29b1bSpooka p9pbuf_put_4(pb, tfid); 12230c29b1bSpooka GETRESPONSE(pb); 123*26721651Sozaki-r if ((rv = proto_expect_stat(pu, pb, &va)) != 0) { 12430c29b1bSpooka proto_cc_clunkfid(pu, tfid, 0); 12530c29b1bSpooka rv = ENOENT; 12630c29b1bSpooka goto out; 12730c29b1bSpooka } 12830c29b1bSpooka if (newqid.qidpath != va.va_fileid) { 12930c29b1bSpooka proto_cc_clunkfid(pu, tfid, 0); 13030c29b1bSpooka rv = EPROTO; 13130c29b1bSpooka goto out; 13230c29b1bSpooka } 13330c29b1bSpooka newqid.qidvers = va.va_gen; 13430c29b1bSpooka 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); 14030c29b1bSpooka /* assert pn */ 14130c29b1bSpooka 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) { 197*26721651Sozaki-r if ((rv = proto_getstat(pu, 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); 234*26721651Sozaki-r proto_make_stat(pu, 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; 3243cafe960Slukem while (*resid > 0 && (uint64_t)(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 34130c29b1bSpooka if (count == 0) 34230c29b1bSpooka break; 34330c29b1bSpooka 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); 429*26721651Sozaki-r if (p9p->protover == P9PROTO_VERSION_U) 430*26721651Sozaki-r p9pbuf_put_str(pb, ""); /* extension[s] */ 4315069b5dfSpooka GETRESPONSE(pb); 432e73a712fSpooka 433e73a712fSpooka rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid); 434e73a712fSpooka if (rv) 435e73a712fSpooka goto out; 436e73a712fSpooka 437e73a712fSpooka /* 438e73a712fSpooka * Now, little problem here: create returns an *open* fid. 439e73a712fSpooka * So, clunk it and walk the parent directory to get a fid 440e73a712fSpooka * which is not open for I/O yet. 441e73a712fSpooka */ 44221913eabSpooka proto_cc_clunkfid(pu, nfid, 0); 443e73a712fSpooka nfid = NEXTFID(p9p); 444e73a712fSpooka 4450e7bdfc1Spooka p9pbuf_recycleout(pb); 446e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 447e73a712fSpooka p9pbuf_put_2(pb, tag); 448e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 449e73a712fSpooka p9pbuf_put_4(pb, nfid); 450e73a712fSpooka p9pbuf_put_2(pb, 1); 451e73a712fSpooka p9pbuf_put_str(pb, name); 4525069b5dfSpooka GETRESPONSE(pb); 453e73a712fSpooka 454e73a712fSpooka /* 455e73a712fSpooka * someone removed it already? try again 456e73a712fSpooka * note: this is kind of lose/lose 457e73a712fSpooka */ 4580e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 459e73a712fSpooka goto again; 460e73a712fSpooka 461e73a712fSpooka pn_new = newp9pnode_va(pu, vap, nfid); 462e73a712fSpooka qid2vattr(&pn_new->pn_va, &nqid); 4636596e0c9Spooka puffs_newinfo_setcookie(pni, pn_new); 464e73a712fSpooka 465e73a712fSpooka out: 466e73a712fSpooka RETURN(rv); 467e73a712fSpooka } 468e73a712fSpooka 469e73a712fSpooka int 47021913eabSpooka puffs9p_node_create(struct puffs_usermount *pu, void *opc, struct puffs_newinfo *pni, 471e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 472e73a712fSpooka { 473e73a712fSpooka 47421913eabSpooka return nodecreate(pu, opc, pni, pcn->pcn_name, va, 0); 475e73a712fSpooka } 476e73a712fSpooka 477e73a712fSpooka int 47821913eabSpooka puffs9p_node_mkdir(struct puffs_usermount *pu, void *opc, struct puffs_newinfo *pni, 479e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 480e73a712fSpooka { 481e73a712fSpooka 48221913eabSpooka return nodecreate(pu, opc, pni, pcn->pcn_name, 483e73a712fSpooka va, P9PROTO_CPERM_DIR); 484e73a712fSpooka } 485e73a712fSpooka 486e73a712fSpooka /* 487e73a712fSpooka * Need to be a bit clever again: the fid is clunked no matter if 488e73a712fSpooka * the remove succeeds or not. Re-getting a fid would be way too 489e73a712fSpooka * difficult in case the remove failed for a valid reason (directory 490e73a712fSpooka * not empty etcetc.). So walk ourselves another fid to prod the 491e73a712fSpooka * ice with. 492e73a712fSpooka */ 493e73a712fSpooka static int 49421913eabSpooka noderemove(struct puffs_usermount *pu, struct puffs_node *pn) 495e73a712fSpooka { 49621913eabSpooka AUTOVAR(pu); 49791629617Spooka struct p9pnode *p9n = pn->pn_data; 498e73a712fSpooka p9pfid_t testfid = NEXTFID(p9p); 499e73a712fSpooka 50021913eabSpooka rv = proto_cc_dupfid(pu, p9n->fid_base, testfid); 5010b0e609bSpooka if (rv) 5020b0e609bSpooka goto out; 503e73a712fSpooka 504e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_REMOVE); 505e73a712fSpooka p9pbuf_put_2(pb, tag); 506e73a712fSpooka p9pbuf_put_4(pb, testfid); 5070b0e609bSpooka 5080b0e609bSpooka /* 5090b0e609bSpooka * XXX: error handling isn't very robust, but doom is impending 5100b0e609bSpooka * anyway, so just accept we're going belly up and play dead 5110b0e609bSpooka */ 5125069b5dfSpooka GETRESPONSE(pb); 513e73a712fSpooka 5140e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_REMOVE) { 515e73a712fSpooka rv = EPROTO; 516e73a712fSpooka } else { 51721913eabSpooka proto_cc_clunkfid(pu, p9n->fid_base, 0); 518e73a712fSpooka p9n->fid_base = P9P_INVALFID; 51991629617Spooka puffs_pn_remove(pn); 520e73a712fSpooka } 521e73a712fSpooka 5220b0e609bSpooka out: 523b283afddSpooka if (rv == 0) 524b283afddSpooka puffs_setback(pcc, PUFFS_SETBACK_NOREF_N2); 525b283afddSpooka 526e73a712fSpooka RETURN(rv); 527e73a712fSpooka } 528e73a712fSpooka 529e73a712fSpooka int 53021913eabSpooka puffs9p_node_remove(struct puffs_usermount *pu, void *opc, void *targ, 531e73a712fSpooka const struct puffs_cn *pcn) 532e73a712fSpooka { 533e73a712fSpooka struct puffs_node *pn = targ; 534e73a712fSpooka 535e73a712fSpooka if (pn->pn_va.va_type == VDIR) 536e73a712fSpooka return EISDIR; 537e73a712fSpooka 53821913eabSpooka return noderemove(pu, pn); 539e73a712fSpooka } 540e73a712fSpooka 541e73a712fSpooka int 54221913eabSpooka puffs9p_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ, 543e73a712fSpooka const struct puffs_cn *pcn) 544e73a712fSpooka { 545e73a712fSpooka struct puffs_node *pn = targ; 546e73a712fSpooka 547e73a712fSpooka if (pn->pn_va.va_type != VDIR) 548e73a712fSpooka return ENOTDIR; 549e73a712fSpooka 55021913eabSpooka return noderemove(pu, pn); 551e73a712fSpooka } 552e73a712fSpooka 553e73a712fSpooka /* 5543ac2e6b4Spooka * 9P supports renames only for files within a directory 555e73a712fSpooka * from what I could tell. So just support in-directory renames 556e73a712fSpooka * for now. 557e73a712fSpooka */ 558e73a712fSpooka int 55921913eabSpooka puffs9p_node_rename(struct puffs_usermount *pu, void *opc, void *src, 560e73a712fSpooka const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 561e73a712fSpooka const struct puffs_cn *pcn_targ) 562e73a712fSpooka { 56321913eabSpooka AUTOVAR(pu); 564e73a712fSpooka struct puffs_node *pn_src = src; 565e73a712fSpooka struct p9pnode *p9n_src = pn_src->pn_data; 566e73a712fSpooka 567e73a712fSpooka if (opc != targ_dir) { 568e73a712fSpooka rv = EOPNOTSUPP; 569e73a712fSpooka goto out; 570e73a712fSpooka } 571e73a712fSpooka 572e73a712fSpooka /* 9P doesn't allow to overwrite in rename */ 573e73a712fSpooka if (targ) { 574e73a712fSpooka struct puffs_node *pn_targ = targ; 575e73a712fSpooka 57621913eabSpooka rv = noderemove(pu, pn_targ->pn_data); 577e73a712fSpooka if (rv) 578ff4087e2Spooka goto out; 579e73a712fSpooka } 580e73a712fSpooka 581e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 582e73a712fSpooka p9pbuf_put_2(pb, tag); 583e73a712fSpooka p9pbuf_put_4(pb, p9n_src->fid_base); 584*26721651Sozaki-r proto_make_stat(pu, pb, NULL, pcn_targ->pcn_name, pn_src->pn_va.va_type); 5855069b5dfSpooka GETRESPONSE(pb); 586e73a712fSpooka 5870e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 588e73a712fSpooka rv = EPROTO; 589e73a712fSpooka 590e73a712fSpooka out: 591e73a712fSpooka RETURN(rv); 592e73a712fSpooka } 593e73a712fSpooka 594e73a712fSpooka /* 595e73a712fSpooka * - "here's one" 596e73a712fSpooka * - "9P" 597e73a712fSpooka * ~ "i'm not dead" 598e73a712fSpooka * - "you're not fooling anyone you know, you'll be stone dead in a minute 599e73a712fSpooka * - "he says he's not quite dead" 600e73a712fSpooka * - "isn't there anything you could do?" 601e73a712fSpooka * - *clunk*! 602e73a712fSpooka * - "thanks" 603e73a712fSpooka */ 604e73a712fSpooka int 60521913eabSpooka puffs9p_node_reclaim(struct puffs_usermount *pu, void *opc) 606e73a712fSpooka { 607b283afddSpooka struct puffs_node *pn = opc; 608b283afddSpooka struct p9pnode *p9n = pn->pn_data; 609b283afddSpooka 610b283afddSpooka assert(LIST_EMPTY(&p9n->dir_openlist)); 611b283afddSpooka assert(p9n->fid_read == P9P_INVALFID && p9n->fid_write == P9P_INVALFID); 612b283afddSpooka 61321913eabSpooka proto_cc_clunkfid(pu, p9n->fid_base, 0); 614b283afddSpooka free(p9n); 615b283afddSpooka puffs_pn_put(pn); 616e73a712fSpooka 617e73a712fSpooka return 0; 618e73a712fSpooka } 619