1*5252a3b0Spooka /* $NetBSD: node.c,v 1.9 2007/05/15 13:56:00 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*5252a3b0Spooka __RCSID("$NetBSD: node.c,v 1.9 2007/05/15 13:56:00 pooka Exp $"); 31e73a712fSpooka #endif /* !lint */ 32e73a712fSpooka 33e73a712fSpooka #include <assert.h> 34e73a712fSpooka #include <errno.h> 35e73a712fSpooka #include <puffs.h> 36e73a712fSpooka #include <stdio.h> 37*5252a3b0Spooka #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 48e73a712fSpooka if (vap->va_fileid == qid->qidpath) 49e73a712fSpooka return pn; 50e73a712fSpooka 51e73a712fSpooka return NULL; 52e73a712fSpooka } 53e73a712fSpooka 54e73a712fSpooka int 55e73a712fSpooka puffs9p_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode, 56e73a712fSpooka enum vtype *newtype, voff_t *newsize, dev_t *newrdev, 57e73a712fSpooka const struct puffs_cn *pcn) 58e73a712fSpooka { 59e73a712fSpooka AUTOVAR(pcc); 60e73a712fSpooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 61e73a712fSpooka struct puffs_node *pn, *pn_dir = opc; 62e73a712fSpooka struct p9pnode *p9n_dir = pn_dir->pn_data; 63e73a712fSpooka p9ptag_t tfid = NEXTFID(p9p); 64e73a712fSpooka struct qid9p newqid; 65e73a712fSpooka uint16_t nqid; 66e73a712fSpooka 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); 735069b5dfSpooka GETRESPONSE(pb); 74e73a712fSpooka 75e73a712fSpooka rv = proto_expect_walk_nqids(pb, &nqid); 76e73a712fSpooka if (rv) { 77e73a712fSpooka rv = ENOENT; 78e73a712fSpooka goto out; 79e73a712fSpooka } 800e7bdfc1Spooka if (nqid != 1) { 81e73a712fSpooka rv = EPROTO; 82e73a712fSpooka goto out; 83e73a712fSpooka } 840e7bdfc1Spooka if ((rv = proto_getqid(pb, &newqid))) 850e7bdfc1Spooka goto out; 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 */ 1325069b5dfSpooka GETRESPONSE(pb); 133e73a712fSpooka 134e73a712fSpooka p9pbuf_get_4(pb, &count); 135e73a712fSpooka 136e73a712fSpooka /* 137e73a712fSpooka * if count is 0, assume we at end-of-dir. dfp is no longer 138e73a712fSpooka * useful, so nuke it 139e73a712fSpooka */ 140e73a712fSpooka if (count == 0) { 141e73a712fSpooka *eofflag = 1; 142e73a712fSpooka releasedf(pcc, dfp); 143e73a712fSpooka goto out; 144e73a712fSpooka } 145e73a712fSpooka 146e73a712fSpooka while (count > 0) { 1470e7bdfc1Spooka if ((rv = proto_getstat(pb, &va, &name, &statsize))) 148e73a712fSpooka goto out; 149e73a712fSpooka 150e73a712fSpooka puffs_nextdent(&dent, name, va.va_fileid, 151e73a712fSpooka puffs_vtype2dt(va.va_type), reslen); 152e73a712fSpooka 153e73a712fSpooka count -= statsize; 154e73a712fSpooka *readoff += statsize; 155e73a712fSpooka dfp->seekoff += statsize; 156*5252a3b0Spooka free(name); 157e73a712fSpooka } 158e73a712fSpooka 159e73a712fSpooka storedf(p9n, dfp); 160e73a712fSpooka 161e73a712fSpooka out: 162e73a712fSpooka RETURN(rv); 163e73a712fSpooka } 164e73a712fSpooka 165e73a712fSpooka int 166e73a712fSpooka puffs9p_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *vap, 167e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 168e73a712fSpooka { 169e73a712fSpooka AUTOVAR(pcc); 170e73a712fSpooka struct puffs_node *pn = opc; 171e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 172e73a712fSpooka 173e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT); 174e73a712fSpooka p9pbuf_put_2(pb, tag); 175e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 1765069b5dfSpooka GETRESPONSE(pb); 177e73a712fSpooka 178e73a712fSpooka rv = proto_expect_stat(pb, &pn->pn_va); 179e73a712fSpooka if (rv) 180e73a712fSpooka goto out; 181e73a712fSpooka 182e73a712fSpooka memcpy(vap, &pn->pn_va, sizeof(struct vattr)); 183e73a712fSpooka 184e73a712fSpooka out: 185e73a712fSpooka RETURN(rv); 186e73a712fSpooka } 187e73a712fSpooka 188e73a712fSpooka int 189e73a712fSpooka puffs9p_node_setattr(struct puffs_cc *pcc, void *opc, 190e73a712fSpooka const struct vattr *va, const struct puffs_cred *pcr, pid_t pid) 191e73a712fSpooka { 192e73a712fSpooka AUTOVAR(pcc); 193e73a712fSpooka struct puffs_node *pn = opc; 194e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 195e73a712fSpooka 196e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 197e73a712fSpooka p9pbuf_put_2(pb, tag); 198e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 1993ac2e6b4Spooka proto_make_stat(pb, va, NULL, pn->pn_va.va_type); 2005069b5dfSpooka GETRESPONSE(pb); 201e73a712fSpooka 2020e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 203e73a712fSpooka rv = EPROTO; 204e73a712fSpooka 205e73a712fSpooka RETURN(rv); 206e73a712fSpooka } 207e73a712fSpooka 208e73a712fSpooka /* 209e73a712fSpooka * Ok, time to get clever. There are two possible cases: we are 210e73a712fSpooka * opening a file or we are opening a directory. 211e73a712fSpooka * 212e73a712fSpooka * If it's a directory, don't bother opening it here, but rather 213e73a712fSpooka * wait until readdir, since it's probable we need to be able to 214e73a712fSpooka * open a directory there in any case. 215e73a712fSpooka * 216436cfd0dSpooka * If it's a regular file, open it here with whatever credentials 217436cfd0dSpooka * we happen to have. Let the upper layers of the kernel worry 218436cfd0dSpooka * about permission control. 219e73a712fSpooka */ 220e73a712fSpooka int 221e73a712fSpooka puffs9p_node_open(struct puffs_cc *pcc, void *opc, int mode, 222e73a712fSpooka const struct puffs_cred *pcr, pid_t pid) 223e73a712fSpooka { 224e73a712fSpooka struct puffs9p *p9p = puffs_cc_getspecific(pcc); 225e73a712fSpooka struct puffs_node *pn = opc; 226e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 227e73a712fSpooka p9pfid_t nfid; 228e73a712fSpooka int error = 0; 229e73a712fSpooka 230dca252d8Spooka puffs_setback(pcc, PUFFS_SETBACK_INACT_N1); 231436cfd0dSpooka if (pn->pn_va.va_type != VDIR) { 232436cfd0dSpooka if (mode & FREAD && p9n->fid_read == P9P_INVALFID) { 233e73a712fSpooka nfid = NEXTFID(p9p); 234e73a712fSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 235436cfd0dSpooka P9PROTO_OMODE_READ); 236e73a712fSpooka if (error) 237e73a712fSpooka return error; 238436cfd0dSpooka p9n->fid_read = nfid; 239436cfd0dSpooka } 240436cfd0dSpooka if (mode & FWRITE && p9n->fid_write == P9P_INVALFID) { 241436cfd0dSpooka nfid = NEXTFID(p9p); 242436cfd0dSpooka error = proto_cc_open(pcc, p9n->fid_base, nfid, 243436cfd0dSpooka P9PROTO_OMODE_WRITE); 244436cfd0dSpooka if (error) 245436cfd0dSpooka return error; 246436cfd0dSpooka p9n->fid_write = nfid; 247436cfd0dSpooka } 248e73a712fSpooka } 249e73a712fSpooka 250e73a712fSpooka return 0; 251e73a712fSpooka } 252e73a712fSpooka 253e73a712fSpooka int 254afa0f0e2Spooka puffs9p_node_inactive(struct puffs_cc *pcc, void *opc, pid_t pid, 255afa0f0e2Spooka int *refcount) 256e73a712fSpooka { 257e73a712fSpooka struct puffs_node *pn = opc; 258e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 259e73a712fSpooka 260436cfd0dSpooka if (pn->pn_va.va_type == VDIR) { 261e73a712fSpooka nukealldf(pcc, p9n); 262436cfd0dSpooka } else { 263436cfd0dSpooka if (p9n->fid_read != P9P_INVALFID) { 264436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_read, 0); 265436cfd0dSpooka p9n->fid_read = P9P_INVALFID; 266436cfd0dSpooka } 267436cfd0dSpooka if (p9n->fid_write != P9P_INVALFID) { 268436cfd0dSpooka proto_cc_clunkfid(pcc, p9n->fid_write, 0); 269436cfd0dSpooka p9n->fid_write = P9P_INVALFID; 270436cfd0dSpooka } 271436cfd0dSpooka } 272e73a712fSpooka 273afa0f0e2Spooka *refcount = 1; 274e73a712fSpooka return 0; 275e73a712fSpooka } 276e73a712fSpooka 277e73a712fSpooka int 278e73a712fSpooka puffs9p_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf, 279e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *pcr, 280e73a712fSpooka int ioflag) 281e73a712fSpooka { 282e73a712fSpooka AUTOVAR(pcc); 283e73a712fSpooka struct puffs_node *pn = opc; 284e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 285e73a712fSpooka uint32_t count; 286e73a712fSpooka size_t nread; 287e73a712fSpooka 288e73a712fSpooka nread = 0; 289e73a712fSpooka while (*resid > 0) { 290e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_READ); 291e73a712fSpooka p9pbuf_put_2(pb, tag); 292436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_read); 293e73a712fSpooka p9pbuf_put_8(pb, offset+nread); 294e73a712fSpooka p9pbuf_put_4(pb, MIN((uint32_t)*resid,p9p->maxreq-24)); 2955069b5dfSpooka GETRESPONSE(pb); 296e73a712fSpooka 2970e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_READ) { 298e73a712fSpooka rv = EPROTO; 299e73a712fSpooka break; 300e73a712fSpooka } 301e73a712fSpooka 302e73a712fSpooka p9pbuf_get_4(pb, &count); 3030e7bdfc1Spooka if ((rv = p9pbuf_read_data(pb, buf + nread, count))) 304e73a712fSpooka break; 305e73a712fSpooka 306e73a712fSpooka *resid -= count; 307e73a712fSpooka nread += count; 308e73a712fSpooka 3090e7bdfc1Spooka p9pbuf_recycleout(pb); 310e73a712fSpooka } 311e73a712fSpooka 312e73a712fSpooka RETURN(rv); 313e73a712fSpooka } 314e73a712fSpooka 315e73a712fSpooka int 316e73a712fSpooka puffs9p_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf, 317e73a712fSpooka off_t offset, size_t *resid, const struct puffs_cred *cred, 318e73a712fSpooka int ioflag) 319e73a712fSpooka { 320e73a712fSpooka AUTOVAR(pcc); 321e73a712fSpooka struct puffs_node *pn = opc; 322e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 323e73a712fSpooka uint32_t chunk, count; 324e73a712fSpooka size_t nwrite; 325e73a712fSpooka 326e73a712fSpooka if (ioflag & PUFFS_IO_APPEND) 327e73a712fSpooka offset = pn->pn_va.va_size; 328e73a712fSpooka 329e73a712fSpooka nwrite = 0; 330e73a712fSpooka while (*resid > 0) { 331e73a712fSpooka chunk = MIN(*resid, p9p->maxreq-32); 332e73a712fSpooka 333e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WRITE); 334e73a712fSpooka p9pbuf_put_2(pb, tag); 335436cfd0dSpooka p9pbuf_put_4(pb, p9n->fid_write); 336e73a712fSpooka p9pbuf_put_8(pb, offset+nwrite); 337e73a712fSpooka p9pbuf_put_4(pb, chunk); 338e73a712fSpooka p9pbuf_write_data(pb, buf+nwrite, chunk); 3395069b5dfSpooka GETRESPONSE(pb); 340e73a712fSpooka 3410e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WRITE) { 342e73a712fSpooka rv = EPROTO; 343e73a712fSpooka break; 344e73a712fSpooka } 345e73a712fSpooka 346e73a712fSpooka p9pbuf_get_4(pb, &count); 347e73a712fSpooka *resid -= count; 348e73a712fSpooka nwrite += count; 349e73a712fSpooka 350e73a712fSpooka if (count != chunk) { 351e73a712fSpooka rv = EPROTO; 352e73a712fSpooka break; 353e73a712fSpooka } 354e73a712fSpooka 3550e7bdfc1Spooka p9pbuf_recycleout(pb); 356e73a712fSpooka } 357e73a712fSpooka 358e73a712fSpooka RETURN(rv); 359e73a712fSpooka } 360e73a712fSpooka 361e73a712fSpooka static int 362e73a712fSpooka nodecreate(struct puffs_cc *pcc, struct puffs_node *pn, void **newnode, 363e73a712fSpooka const char *name, const struct vattr *vap, uint32_t dirbit) 364e73a712fSpooka { 365e73a712fSpooka AUTOVAR(pcc); 366e73a712fSpooka struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 367e73a712fSpooka struct puffs_node *pn_new; 368e73a712fSpooka struct p9pnode *p9n = pn->pn_data; 369e73a712fSpooka p9pfid_t nfid = NEXTFID(p9p); 370e73a712fSpooka struct qid9p nqid; 371e73a712fSpooka int tries = 0; 372e73a712fSpooka 373e73a712fSpooka again: 374e73a712fSpooka if (++tries > 5) { 375e73a712fSpooka rv = EPROTO; 376e73a712fSpooka goto out; 377e73a712fSpooka } 378e73a712fSpooka 379e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, nfid); 380e73a712fSpooka if (rv) 381e73a712fSpooka goto out; 382e73a712fSpooka 383e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_CREATE); 384e73a712fSpooka p9pbuf_put_2(pb, tag); 385e73a712fSpooka p9pbuf_put_4(pb, nfid); 386e73a712fSpooka p9pbuf_put_str(pb, name); 387e73a712fSpooka p9pbuf_put_4(pb, dirbit | (vap->va_mode & 0777)); 388e73a712fSpooka p9pbuf_put_1(pb, 0); 3895069b5dfSpooka GETRESPONSE(pb); 390e73a712fSpooka 391e73a712fSpooka rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid); 392e73a712fSpooka if (rv) 393e73a712fSpooka goto out; 394e73a712fSpooka 395e73a712fSpooka /* 396e73a712fSpooka * Now, little problem here: create returns an *open* fid. 397e73a712fSpooka * So, clunk it and walk the parent directory to get a fid 398e73a712fSpooka * which is not open for I/O yet. 399e73a712fSpooka */ 400e73a712fSpooka proto_cc_clunkfid(pcc, nfid, 0); 401e73a712fSpooka nfid = NEXTFID(p9p); 402e73a712fSpooka 4030e7bdfc1Spooka p9pbuf_recycleout(pb); 404e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WALK); 405e73a712fSpooka p9pbuf_put_2(pb, tag); 406e73a712fSpooka p9pbuf_put_4(pb, p9n->fid_base); 407e73a712fSpooka p9pbuf_put_4(pb, nfid); 408e73a712fSpooka p9pbuf_put_2(pb, 1); 409e73a712fSpooka p9pbuf_put_str(pb, name); 4105069b5dfSpooka GETRESPONSE(pb); 411e73a712fSpooka 412e73a712fSpooka /* 413e73a712fSpooka * someone removed it already? try again 414e73a712fSpooka * note: this is kind of lose/lose 415e73a712fSpooka */ 4160e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 417e73a712fSpooka goto again; 418e73a712fSpooka 419e73a712fSpooka pn_new = newp9pnode_va(pu, vap, nfid); 420e73a712fSpooka qid2vattr(&pn_new->pn_va, &nqid); 421e73a712fSpooka *newnode = pn_new; 422e73a712fSpooka 423e73a712fSpooka out: 424e73a712fSpooka RETURN(rv); 425e73a712fSpooka } 426e73a712fSpooka 427e73a712fSpooka int 428e73a712fSpooka puffs9p_node_create(struct puffs_cc *pcc, void *opc, void **newnode, 429e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 430e73a712fSpooka { 431e73a712fSpooka 432e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, va, 0); 433e73a712fSpooka } 434e73a712fSpooka 435e73a712fSpooka int 436e73a712fSpooka puffs9p_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode, 437e73a712fSpooka const struct puffs_cn *pcn, const struct vattr *va) 438e73a712fSpooka { 439e73a712fSpooka 440e73a712fSpooka return nodecreate(pcc, opc, newnode, pcn->pcn_name, 441e73a712fSpooka va, P9PROTO_CPERM_DIR); 442e73a712fSpooka } 443e73a712fSpooka 444e73a712fSpooka /* 445e73a712fSpooka * Need to be a bit clever again: the fid is clunked no matter if 446e73a712fSpooka * the remove succeeds or not. Re-getting a fid would be way too 447e73a712fSpooka * difficult in case the remove failed for a valid reason (directory 448e73a712fSpooka * not empty etcetc.). So walk ourselves another fid to prod the 449e73a712fSpooka * ice with. 450e73a712fSpooka */ 451e73a712fSpooka static int 452e73a712fSpooka noderemove(struct puffs_cc *pcc, struct p9pnode *p9n) 453e73a712fSpooka { 454e73a712fSpooka AUTOVAR(pcc); 455e73a712fSpooka p9pfid_t testfid = NEXTFID(p9p); 456e73a712fSpooka 457e73a712fSpooka rv = proto_cc_dupfid(pcc, p9n->fid_base, testfid); 458e73a712fSpooka 459e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_REMOVE); 460e73a712fSpooka p9pbuf_put_2(pb, tag); 461e73a712fSpooka p9pbuf_put_4(pb, testfid); 4625069b5dfSpooka GETRESPONSE(pb); 463e73a712fSpooka 4640e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_REMOVE) { 465e73a712fSpooka rv = EPROTO; 466e73a712fSpooka } else { 467e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_base, 0); 468e73a712fSpooka p9n->fid_base = P9P_INVALFID; 469e73a712fSpooka } 470e73a712fSpooka 471e73a712fSpooka RETURN(rv); 472e73a712fSpooka } 473e73a712fSpooka 474e73a712fSpooka int 475e73a712fSpooka puffs9p_node_remove(struct puffs_cc *pcc, void *opc, void *targ, 476e73a712fSpooka const struct puffs_cn *pcn) 477e73a712fSpooka { 478e73a712fSpooka struct puffs_node *pn = targ; 479e73a712fSpooka 480e73a712fSpooka if (pn->pn_va.va_type == VDIR) 481e73a712fSpooka return EISDIR; 482e73a712fSpooka 483e73a712fSpooka return noderemove(pcc, pn->pn_data); 484e73a712fSpooka } 485e73a712fSpooka 486e73a712fSpooka int 487e73a712fSpooka puffs9p_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ, 488e73a712fSpooka const struct puffs_cn *pcn) 489e73a712fSpooka { 490e73a712fSpooka struct puffs_node *pn = targ; 491e73a712fSpooka 492e73a712fSpooka if (pn->pn_va.va_type != VDIR) 493e73a712fSpooka return ENOTDIR; 494e73a712fSpooka 495e73a712fSpooka return noderemove(pcc, pn->pn_data); 496e73a712fSpooka } 497e73a712fSpooka 498e73a712fSpooka /* 4993ac2e6b4Spooka * 9P supports renames only for files within a directory 500e73a712fSpooka * from what I could tell. So just support in-directory renames 501e73a712fSpooka * for now. 502e73a712fSpooka */ 503e73a712fSpooka int 504e73a712fSpooka puffs9p_node_rename(struct puffs_cc *pcc, void *opc, void *src, 505e73a712fSpooka const struct puffs_cn *pcn_src, void *targ_dir, void *targ, 506e73a712fSpooka const struct puffs_cn *pcn_targ) 507e73a712fSpooka { 508e73a712fSpooka AUTOVAR(pcc); 509e73a712fSpooka struct puffs_node *pn_src = src; 510e73a712fSpooka struct p9pnode *p9n_src = pn_src->pn_data; 511e73a712fSpooka 512e73a712fSpooka if (opc != targ_dir) { 513e73a712fSpooka rv = EOPNOTSUPP; 514e73a712fSpooka goto out; 515e73a712fSpooka } 516e73a712fSpooka 517e73a712fSpooka /* 9P doesn't allow to overwrite in rename */ 518e73a712fSpooka if (targ) { 519e73a712fSpooka struct puffs_node *pn_targ = targ; 520e73a712fSpooka 521e73a712fSpooka rv = noderemove(pcc, pn_targ->pn_data); 522e73a712fSpooka if (rv) 523ff4087e2Spooka goto out; 524e73a712fSpooka } 525e73a712fSpooka 526e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_WSTAT); 527e73a712fSpooka p9pbuf_put_2(pb, tag); 528e73a712fSpooka p9pbuf_put_4(pb, p9n_src->fid_base); 5293ac2e6b4Spooka proto_make_stat(pb, NULL, pcn_targ->pcn_name, pn_src->pn_va.va_type); 5305069b5dfSpooka GETRESPONSE(pb); 531e73a712fSpooka 5320e7bdfc1Spooka if (p9pbuf_get_type(pb) != P9PROTO_R_WSTAT) 533e73a712fSpooka rv = EPROTO; 534e73a712fSpooka 535e73a712fSpooka out: 536e73a712fSpooka RETURN(rv); 537e73a712fSpooka } 538e73a712fSpooka 539e73a712fSpooka /* 540e73a712fSpooka * - "here's one" 541e73a712fSpooka * - "9P" 542e73a712fSpooka * ~ "i'm not dead" 543e73a712fSpooka * - "you're not fooling anyone you know, you'll be stone dead in a minute 544e73a712fSpooka * - "he says he's not quite dead" 545e73a712fSpooka * - "isn't there anything you could do?" 546e73a712fSpooka * - *clunk*! 547e73a712fSpooka * - "thanks" 548e73a712fSpooka */ 549e73a712fSpooka int 550e73a712fSpooka puffs9p_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid) 551e73a712fSpooka { 552e73a712fSpooka #if 0 553e73a712fSpooka if (p9n->fid_open != P9P_INVALFID) 554e73a712fSpooka proto_cc_clunkfid(pcc, p9n->fid_open, 0); 555e73a712fSpooka #endif 556e73a712fSpooka 557e73a712fSpooka return 0; 558e73a712fSpooka } 559