1*dca252d8Spooka /* $NetBSD: node.c,v 1.7 2007/05/07 17:20:58 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*dca252d8Spooka __RCSID("$NetBSD: node.c,v 1.7 2007/05/07 17:20:58 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 p9pbuf_put_1(pb, P9PROTO_T_WALK); 67e73a712fSpooka p9pbuf_put_2(pb, tag); 68e73a712fSpooka p9pbuf_put_4(pb, p9n_dir->fid_base); 69e73a712fSpooka p9pbuf_put_4(pb, tfid); 70e73a712fSpooka p9pbuf_put_2(pb, 1); 71e73a712fSpooka p9pbuf_put_str(pb, pcn->pcn_name); 720e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 73e73a712fSpooka 74e73a712fSpooka rv = proto_expect_walk_nqids(pb, &nqid); 75e73a712fSpooka if (rv) { 76e73a712fSpooka rv = ENOENT; 77e73a712fSpooka goto out; 78e73a712fSpooka } 790e7bdfc1Spooka if (nqid != 1) { 80e73a712fSpooka rv = EPROTO; 81e73a712fSpooka goto out; 82e73a712fSpooka } 830e7bdfc1Spooka if ((rv = proto_getqid(pb, &newqid))) 840e7bdfc1Spooka goto out; 85e73a712fSpooka 86e73a712fSpooka pn = puffs_pn_nodewalk(pu, nodecmp, &newqid); 87e73a712fSpooka if (pn == NULL) 88e73a712fSpooka pn = newp9pnode_qid(pu, &newqid, tfid); 89e73a712fSpooka else 90e73a712fSpooka proto_cc_clunkfid(pcc, tfid, 0); 91e73a712fSpooka 92e73a712fSpooka *newnode = pn; 93e73a712fSpooka *newtype = pn->pn_va.va_type; 94e73a712fSpooka *newsize = pn->pn_va.va_size; 95e73a712fSpooka *newrdev = pn->pn_va.va_rdev; 96e73a712fSpooka 97e73a712fSpooka out: 98e73a712fSpooka RETURN(rv); 99e73a712fSpooka } 100e73a712fSpooka 101e73a712fSpooka /* 102e73a712fSpooka * Problem is that 9P doesn't allow seeking into a directory. So we 103e73a712fSpooka * maintain a list of active fids for any given directory. They 104e73a712fSpooka * start living at the first read and exist either until the directory 105e73a712fSpooka * is closed or until they reach the end. 106e73a712fSpooka */ 107e73a712fSpooka int 108e73a712fSpooka puffs9p_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent, 109e73a712fSpooka off_t *readoff, size_t *reslen, const struct puffs_cred *pcr, 110e73a712fSpooka int *eofflag, off_t *cookies, size_t *ncookies) 111e73a712fSpooka { 112e73a712fSpooka AUTOVAR(pcc); 113e73a712fSpooka struct puffs_node *pn = opc; 114e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 115e73a712fSpooka struct vattr va; 116e73a712fSpooka struct dirfid *dfp; 117e73a712fSpooka char *name; 118e73a712fSpooka uint32_t count; 119e73a712fSpooka uint16_t statsize; 120e73a712fSpooka 121e73a712fSpooka rv = getdfwithoffset(pcc, p9n, *readoff, &dfp); 122e73a712fSpooka if (rv) 123e73a712fSpooka goto out; 124e73a712fSpooka 125e73a712fSpooka tag = NEXTTAG(p9p); 126e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 127e73a712fSpooka p9pbuf_put_2(pb, tag); 128e73a712fSpooka p9pbuf_put_4(pb, dfp->fid); 129e73a712fSpooka p9pbuf_put_8(pb, *readoff); 130e73a712fSpooka p9pbuf_put_4(pb, *reslen); /* XXX */ 1310e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 132e73a712fSpooka 133e73a712fSpooka p9pbuf_get_4(pb, &count); 134e73a712fSpooka 135e73a712fSpooka /* 136e73a712fSpooka * if count is 0, assume we at end-of-dir. dfp is no longer 137e73a712fSpooka * useful, so nuke it 138e73a712fSpooka */ 139e73a712fSpooka if (count == 0) { 140e73a712fSpooka *eofflag = 1; 141e73a712fSpooka releasedf(pcc, dfp); 142e73a712fSpooka goto out; 143e73a712fSpooka } 144e73a712fSpooka 145e73a712fSpooka while (count > 0) { 1460e7bdfc1Spooka if ((rv = proto_getstat(pb, &va, &name, &statsize))) 147e73a712fSpooka goto out; 148e73a712fSpooka 149e73a712fSpooka puffs_nextdent(&dent, name, va.va_fileid, 150e73a712fSpooka puffs_vtype2dt(va.va_type), reslen); 151e73a712fSpooka 152e73a712fSpooka count -= statsize; 153e73a712fSpooka *readoff += statsize; 154e73a712fSpooka dfp->seekoff += statsize; 155e73a712fSpooka } 156e73a712fSpooka 157e73a712fSpooka storedf(p9n, dfp); 158e73a712fSpooka 159e73a712fSpooka out: 160e73a712fSpooka RETURN(rv); 161e73a712fSpooka } 162e73a712fSpooka 163e73a712fSpooka int 164e73a712fSpooka puffs9p_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *vap, 165e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 166e73a712fSpooka { 167e73a712fSpooka AUTOVAR(pcc); 168e73a712fSpooka struct puffs_node *pn = opc; 169e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 170e73a712fSpooka 171e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 172e73a712fSpooka p9pbuf_put_2(pb, tag); 173e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 1740e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 175e73a712fSpooka 176e73a712fSpooka rv = proto_expect_stat(pb, &pn->pn_va); 177e73a712fSpooka if (rv) 178e73a712fSpooka goto out; 179e73a712fSpooka 180e73a712fSpooka memcpy(vap, &pn->pn_va, sizeof(struct vattr)); 181e73a712fSpooka 182e73a712fSpooka out: 183e73a712fSpooka RETURN(rv); 184e73a712fSpooka } 185e73a712fSpooka 186e73a712fSpooka int 187e73a712fSpooka puffs9p_node_setattr(struct puffs_cc *pcc, void *opc, 188e73a712fSpooka const struct vattr *va, const struct puffs_cred *pcr, pid_t pid) 189e73a712fSpooka { 190e73a712fSpooka AUTOVAR(pcc); 191e73a712fSpooka struct puffs_node *pn = opc; 192e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 193e73a712fSpooka 194e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 195e73a712fSpooka p9pbuf_put_2(pb, tag); 196e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 1973ac2e6b4Spooka proto_make_stat(pb, va, NULL, pn->pn_va.va_type); 1980e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 199e73a712fSpooka 2000e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 201e73a712fSpooka rv = EPROTO; 202e73a712fSpooka 203e73a712fSpooka RETURN(rv); 204e73a712fSpooka } 205e73a712fSpooka 206e73a712fSpooka /* 207e73a712fSpooka * Ok, time to get clever. There are two possible cases: we are 208e73a712fSpooka * opening a file or we are opening a directory. 209e73a712fSpooka * 210e73a712fSpooka * If it's a directory, don't bother opening it here, but rather 211e73a712fSpooka * wait until readdir, since it's probable we need to be able to 212e73a712fSpooka * open a directory there in any case. 213e73a712fSpooka * 214436cfd0dSpooka * If it's a regular file, open it here with whatever credentials 215436cfd0dSpooka * we happen to have. Let the upper layers of the kernel worry 216436cfd0dSpooka * about permission control. 217e73a712fSpooka */ 218e73a712fSpooka int 219e73a712fSpooka puffs9p_node_open(struct puffs_cc *pcc, void *opc, int mode, 220e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 221e73a712fSpooka { 222e73a712fSpooka struct puffs9p *p9p = puffs_cc_getspecific(pcc); 223e73a712fSpooka struct puffs_node *pn = opc; 224e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 225e73a712fSpooka p9pfid_t nfid; 226e73a712fSpooka int error = 0; 227e73a712fSpooka 228*dca252d8Spooka puffs_setback(pcc, PUFFS_SETBACK_INACT_N1); 229436cfd0dSpooka if (pn->pn_va.va_type != VDIR) { 230436cfd0dSpooka if (mode & FREAD && p9n->fid_read == P9P_INVALFID) { 231e73a712fSpooka nfid = NEXTFID(p9p); 232e73a712fSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 233436cfd0dSpooka P9PROTO_OMODE_READ); 234e73a712fSpooka if (error) 235e73a712fSpooka return error; 236436cfd0dSpooka p9n->fid_read = nfid; 237436cfd0dSpooka } 238436cfd0dSpooka if (mode & FWRITE && p9n->fid_write == P9P_INVALFID) { 239436cfd0dSpooka nfid = NEXTFID(p9p); 240436cfd0dSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 241436cfd0dSpooka P9PROTO_OMODE_WRITE); 242436cfd0dSpooka if (error) 243436cfd0dSpooka return error; 244436cfd0dSpooka p9n->fid_write = nfid; 245436cfd0dSpooka } 246e73a712fSpooka } 247e73a712fSpooka 248e73a712fSpooka return 0; 249e73a712fSpooka } 250e73a712fSpooka 251e73a712fSpooka int 252afa0f0e2Spooka puffs9p_node_inactive(struct puffs_cc *pcc, void *opc, pid_t pid, 253afa0f0e2Spooka int *refcount) 254e73a712fSpooka { 255e73a712fSpooka struct puffs_node *pn = opc; 256e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 257e73a712fSpooka 258436cfd0dSpooka if (pn->pn_va.va_type == VDIR) { 259e73a712fSpooka nukealldf(pcc, p9n); 260436cfd0dSpooka } else { 261436cfd0dSpooka if (p9n->fid_read != P9P_INVALFID) { 262436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_read, 0); 263436cfd0dSpooka p9n->fid_read = P9P_INVALFID; 264436cfd0dSpooka } 265436cfd0dSpooka if (p9n->fid_write != P9P_INVALFID) { 266436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_write, 0); 267436cfd0dSpooka p9n->fid_write = P9P_INVALFID; 268436cfd0dSpooka } 269436cfd0dSpooka } 270e73a712fSpooka 271afa0f0e2Spooka *refcount = 1; 272e73a712fSpooka return 0; 273e73a712fSpooka } 274e73a712fSpooka 275e73a712fSpooka int 276e73a712fSpooka puffs9p_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf, 277e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *pcr, 278e73a712fSpooka int ioflag) 279e73a712fSpooka { 280e73a712fSpooka AUTOVAR(pcc); 281e73a712fSpooka struct puffs_node *pn = opc; 282e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 283e73a712fSpooka uint32_t count; 284e73a712fSpooka size_t nread; 285e73a712fSpooka 286e73a712fSpooka nread = 0; 287e73a712fSpooka while (*resid > 0) { 288e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 289e73a712fSpooka p9pbuf_put_2(pb, tag); 290436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_read); 291e73a712fSpooka p9pbuf_put_8(pb, offset+nread); 292e73a712fSpooka p9pbuf_put_4(pb, MIN((uint32_t)*resid,p9p->maxreq-24)); 2930e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 294e73a712fSpooka 2950e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_READ) { 296e73a712fSpooka rv = EPROTO; 297e73a712fSpooka break; 298e73a712fSpooka } 299e73a712fSpooka 300e73a712fSpooka p9pbuf_get_4(pb, &count); 3010e7bdfc1Spooka if ((rv = p9pbuf_read_data(pb, buf + nread, count))) 302e73a712fSpooka break; 303e73a712fSpooka 304e73a712fSpooka *resid -= count; 305e73a712fSpooka nread += count; 306e73a712fSpooka 3070e7bdfc1Spooka p9pbuf_recycleout(pb); 308e73a712fSpooka } 309e73a712fSpooka 310e73a712fSpooka RETURN(rv); 311e73a712fSpooka } 312e73a712fSpooka 313e73a712fSpooka int 314e73a712fSpooka puffs9p_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf, 315e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *cred, 316e73a712fSpooka int ioflag) 317e73a712fSpooka { 318e73a712fSpooka AUTOVAR(pcc); 319e73a712fSpooka struct puffs_node *pn = opc; 320e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 321e73a712fSpooka uint32_t chunk, count; 322e73a712fSpooka size_t nwrite; 323e73a712fSpooka 324e73a712fSpooka if (ioflag & PUFFS_IO_APPEND) 325e73a712fSpooka offset = pn->pn_va.va_size; 326e73a712fSpooka 327e73a712fSpooka nwrite = 0; 328e73a712fSpooka while (*resid > 0) { 329e73a712fSpooka chunk = MIN(*resid, p9p->maxreq-32); 330e73a712fSpooka 331e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WRITE); 332e73a712fSpooka p9pbuf_put_2(pb, tag); 333436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_write); 334e73a712fSpooka p9pbuf_put_8(pb, offset+nwrite); 335e73a712fSpooka p9pbuf_put_4(pb, chunk); 336e73a712fSpooka p9pbuf_write_data(pb, buf+nwrite, chunk); 3370e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 338e73a712fSpooka 3390e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WRITE) { 340e73a712fSpooka rv = EPROTO; 341e73a712fSpooka break; 342e73a712fSpooka } 343e73a712fSpooka 344e73a712fSpooka p9pbuf_get_4(pb, &count); 345e73a712fSpooka *resid -= count; 346e73a712fSpooka nwrite += count; 347e73a712fSpooka 348e73a712fSpooka if (count != chunk) { 349e73a712fSpooka rv = EPROTO; 350e73a712fSpooka break; 351e73a712fSpooka } 352e73a712fSpooka 3530e7bdfc1Spooka p9pbuf_recycleout(pb); 354e73a712fSpooka } 355e73a712fSpooka 356e73a712fSpooka RETURN(rv); 357e73a712fSpooka } 358e73a712fSpooka 359e73a712fSpooka static int 360e73a712fSpooka nodecreate(struct puffs_cc *pcc, struct puffs_node *pn, void **newnode, 361e73a712fSpooka const char *name, const struct vattr *vap, uint32_t dirbit) 362e73a712fSpooka { 363e73a712fSpooka AUTOVAR(pcc); 364e73a712fSpooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 365e73a712fSpooka struct puffs_node *pn_new; 366e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 367e73a712fSpooka p9pfid_t nfid = NEXTFID(p9p); 368e73a712fSpooka struct qid9p nqid; 369e73a712fSpooka int tries = 0; 370e73a712fSpooka 371e73a712fSpooka again: 372e73a712fSpooka if (++tries > 5) { 373e73a712fSpooka rv = EPROTO; 374e73a712fSpooka goto out; 375e73a712fSpooka } 376e73a712fSpooka 377e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, nfid); 378e73a712fSpooka if (rv) 379e73a712fSpooka goto out; 380e73a712fSpooka 381e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_CREATE); 382e73a712fSpooka p9pbuf_put_2(pb, tag); 383e73a712fSpooka p9pbuf_put_4(pb, nfid); 384e73a712fSpooka p9pbuf_put_str(pb, name); 385e73a712fSpooka p9pbuf_put_4(pb, dirbit | (vap->va_mode & 0777)); 386e73a712fSpooka p9pbuf_put_1(pb, 0); 3870e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 388e73a712fSpooka 389e73a712fSpooka rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid); 390e73a712fSpooka if (rv) 391e73a712fSpooka goto out; 392e73a712fSpooka 393e73a712fSpooka /* 394e73a712fSpooka * Now, little problem here: create returns an *open* fid. 395e73a712fSpooka * So, clunk it and walk the parent directory to get a fid 396e73a712fSpooka * which is not open for I/O yet. 397e73a712fSpooka */ 398e73a712fSpooka proto_cc_clunkfid(pcc, nfid, 0); 399e73a712fSpooka nfid = NEXTFID(p9p); 400e73a712fSpooka 4010e7bdfc1Spooka p9pbuf_recycleout(pb); 402e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 403e73a712fSpooka p9pbuf_put_2(pb, tag); 404e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 405e73a712fSpooka p9pbuf_put_4(pb, nfid); 406e73a712fSpooka p9pbuf_put_2(pb, 1); 407e73a712fSpooka p9pbuf_put_str(pb, name); 4080e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 409e73a712fSpooka 410e73a712fSpooka /* 411e73a712fSpooka * someone removed it already? try again 412e73a712fSpooka * note: this is kind of lose/lose 413e73a712fSpooka */ 4140e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 415e73a712fSpooka goto again; 416e73a712fSpooka 417e73a712fSpooka pn_new = newp9pnode_va(pu, vap, nfid); 418e73a712fSpooka qid2vattr(&pn_new->pn_va, &nqid); 419e73a712fSpooka *newnode = pn_new; 420e73a712fSpooka 421e73a712fSpooka out: 422e73a712fSpooka RETURN(rv); 423e73a712fSpooka } 424e73a712fSpooka 425e73a712fSpooka int 426e73a712fSpooka puffs9p_node_create(struct puffs_cc *pcc, void *opc, void **newnode, 427e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 428e73a712fSpooka { 429e73a712fSpooka 430e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, va, 0); 431e73a712fSpooka } 432e73a712fSpooka 433e73a712fSpooka int 434e73a712fSpooka puffs9p_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode, 435e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 436e73a712fSpooka { 437e73a712fSpooka 438e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, 439e73a712fSpooka va, P9PROTO_CPERM_DIR); 440e73a712fSpooka } 441e73a712fSpooka 442e73a712fSpooka /* 443e73a712fSpooka * Need to be a bit clever again: the fid is clunked no matter if 444e73a712fSpooka * the remove succeeds or not. Re-getting a fid would be way too 445e73a712fSpooka * difficult in case the remove failed for a valid reason (directory 446e73a712fSpooka * not empty etcetc.). So walk ourselves another fid to prod the 447e73a712fSpooka * ice with. 448e73a712fSpooka */ 449e73a712fSpooka static int 450e73a712fSpooka noderemove(struct puffs_cc *pcc, struct p9pnode *p9n) 451e73a712fSpooka { 452e73a712fSpooka AUTOVAR(pcc); 453e73a712fSpooka p9pfid_t testfid = NEXTFID(p9p); 454e73a712fSpooka 455e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, testfid); 456e73a712fSpooka 457e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_REMOVE); 458e73a712fSpooka p9pbuf_put_2(pb, tag); 459e73a712fSpooka p9pbuf_put_4(pb, testfid); 4600e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 461e73a712fSpooka 4620e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_REMOVE) { 463e73a712fSpooka rv = EPROTO; 464e73a712fSpooka } else { 465e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_base, 0); 466e73a712fSpooka p9n->fid_base = P9P_INVALFID; 467e73a712fSpooka } 468e73a712fSpooka 469e73a712fSpooka RETURN(rv); 470e73a712fSpooka } 471e73a712fSpooka 472e73a712fSpooka int 473e73a712fSpooka puffs9p_node_remove(struct puffs_cc *pcc, void *opc, void *targ, 474e73a712fSpooka const struct puffs_cn *pcn) 475e73a712fSpooka { 476e73a712fSpooka struct puffs_node *pn = targ; 477e73a712fSpooka 478e73a712fSpooka if (pn->pn_va.va_type == VDIR) 479e73a712fSpooka return EISDIR; 480e73a712fSpooka 481e73a712fSpooka return noderemove(pcc, pn->pn_data); 482e73a712fSpooka } 483e73a712fSpooka 484e73a712fSpooka int 485e73a712fSpooka puffs9p_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ, 486e73a712fSpooka const struct puffs_cn *pcn) 487e73a712fSpooka { 488e73a712fSpooka struct puffs_node *pn = targ; 489e73a712fSpooka 490e73a712fSpooka if (pn->pn_va.va_type != VDIR) 491e73a712fSpooka return ENOTDIR; 492e73a712fSpooka 493e73a712fSpooka return noderemove(pcc, pn->pn_data); 494e73a712fSpooka } 495e73a712fSpooka 496e73a712fSpooka /* 4973ac2e6b4Spooka * 9P supports renames only for files within a directory 498e73a712fSpooka * from what I could tell. So just support in-directory renames 499e73a712fSpooka * for now. 500e73a712fSpooka */ 501e73a712fSpooka int 502e73a712fSpooka puffs9p_node_rename(struct puffs_cc *pcc, void *opc, void *src, 503e73a712fSpooka const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 504e73a712fSpooka const struct puffs_cn *pcn_targ) 505e73a712fSpooka { 506e73a712fSpooka AUTOVAR(pcc); 507e73a712fSpooka struct puffs_node *pn_src = src; 508e73a712fSpooka struct p9pnode *p9n_src = pn_src->pn_data; 509e73a712fSpooka 510e73a712fSpooka if (opc != targ_dir) { 511e73a712fSpooka rv = EOPNOTSUPP; 512e73a712fSpooka goto out; 513e73a712fSpooka } 514e73a712fSpooka 515e73a712fSpooka /* 9P doesn't allow to overwrite in rename */ 516e73a712fSpooka if (targ) { 517e73a712fSpooka struct puffs_node *pn_targ = targ; 518e73a712fSpooka 519e73a712fSpooka rv = noderemove(pcc, pn_targ->pn_data); 520e73a712fSpooka if (rv) 521ff4087e2Spooka goto out; 522e73a712fSpooka } 523e73a712fSpooka 524e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 525e73a712fSpooka p9pbuf_put_2(pb, tag); 526e73a712fSpooka p9pbuf_put_4(pb, p9n_src->fid_base); 5273ac2e6b4Spooka proto_make_stat(pb, NULL, pcn_targ->pcn_name, pn_src->pn_va.va_type); 5280e7bdfc1Spooka puffs_framebuf_enqueue_cc(pcc, pb); 529e73a712fSpooka 5300e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 531e73a712fSpooka rv = EPROTO; 532e73a712fSpooka 533e73a712fSpooka out: 534e73a712fSpooka RETURN(rv); 535e73a712fSpooka } 536e73a712fSpooka 537e73a712fSpooka /* 538e73a712fSpooka * - "here's one" 539e73a712fSpooka * - "9P" 540e73a712fSpooka * ~ "i'm not dead" 541e73a712fSpooka * - "you're not fooling anyone you know, you'll be stone dead in a minute 542e73a712fSpooka * - "he says he's not quite dead" 543e73a712fSpooka * - "isn't there anything you could do?" 544e73a712fSpooka * - *clunk*! 545e73a712fSpooka * - "thanks" 546e73a712fSpooka */ 547e73a712fSpooka int 548e73a712fSpooka puffs9p_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid) 549e73a712fSpooka { 550e73a712fSpooka #if 0 551e73a712fSpooka if (p9n->fid_open != P9P_INVALFID) 552e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_open, 0); 553e73a712fSpooka #endif 554e73a712fSpooka 555e73a712fSpooka return 0; 556e73a712fSpooka } 557