mount_9p: mount a file server using the Plan9 file sharing protocol
Works, but lots of little things to nibble on: * fix permissions to work better * limit the amount of open files required * do constant folding with psshfs code * support authentication etcetc.
This commit is contained in:
parent
caf05d897b
commit
e73a712f80
|
@ -0,0 +1,12 @@
|
||||||
|
# $NetBSD: Makefile,v 1.1 2007/04/21 14:21:42 pooka Exp $
|
||||||
|
#
|
||||||
|
|
||||||
|
PROG= mount_9p
|
||||||
|
SRCS= ninepuffs.c ninebuf.c nineproto.c fs.c node.c subr.c
|
||||||
|
LDADD+= -lpuffs -lutil
|
||||||
|
WARNS= 4
|
||||||
|
DBG=-g -O0
|
||||||
|
|
||||||
|
MAN= mount_9p.8
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
|
@ -0,0 +1,227 @@
|
||||||
|
/* $NetBSD: fs.c,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: fs.c,v 1.1 2007/04/21 14:21:43 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
#include "nineproto.h"
|
||||||
|
|
||||||
|
struct puffs_node *
|
||||||
|
p9p_handshake(struct puffs_usermount *pu, const char *username)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_getspecific(pu);
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
struct puffs_node *pn;
|
||||||
|
struct vattr rootva;
|
||||||
|
uint32_t maxreq;
|
||||||
|
uint16_t dummy;
|
||||||
|
p9ptag_t tagid;
|
||||||
|
int rv, x = 1;
|
||||||
|
|
||||||
|
/* send initial handshake */
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_VERSION);
|
||||||
|
p9pbuf_put_2(pb, P9PROTO_NOTAG);
|
||||||
|
p9pbuf_put_4(pb, p9p->maxreq);
|
||||||
|
p9pbuf_put_str(pb, P9PROTO_VERSION);
|
||||||
|
while ((rv = p9pbuf_write(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Tversion send failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_IN);
|
||||||
|
while ((rv = p9pbuf_read(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Rversion receive failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_VERSION) {
|
||||||
|
warnx("server invalid response to Tversion: %d", pb->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pb->tagid != P9PROTO_NOTAG) {
|
||||||
|
warnx("server invalid tag: %d vs. %d\n",
|
||||||
|
P9PROTO_NOTAG, pb->tagid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!p9pbuf_get_4(pb, &maxreq)) {
|
||||||
|
warnx("server invalid response: no request length");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (maxreq < P9P_MINREQLEN) {
|
||||||
|
warnx("server request length below minimum accepted: %d vs. %d",
|
||||||
|
P9P_MINREQLEN, maxreq);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p9p->maxreq = maxreq;
|
||||||
|
|
||||||
|
/* tell the server we don't support authentication */
|
||||||
|
tagid = NEXTTAG(p9p);
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_AUTH);
|
||||||
|
p9pbuf_put_2(pb, tagid);
|
||||||
|
p9pbuf_put_4(pb, P9PROTO_NOFID);
|
||||||
|
p9pbuf_put_str(pb, username);
|
||||||
|
p9pbuf_put_str(pb, "");
|
||||||
|
while ((rv = p9pbuf_write(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Tauth send failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_IN);
|
||||||
|
while ((rv = p9pbuf_read(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Rauth receive failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assume all Rerror is "no auth" */
|
||||||
|
if (pb->type != P9PROTO_R_ERROR) {
|
||||||
|
warnx("mount_9p supports only NO auth");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pb->tagid != tagid) {
|
||||||
|
warnx("server invalid tag: %d vs. %d\n", tagid, pb->tagid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build attach message */
|
||||||
|
tagid = NEXTTAG(p9p);
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_ATTACH);
|
||||||
|
p9pbuf_put_2(pb, tagid);
|
||||||
|
p9pbuf_put_4(pb, P9P_ROOTFID);
|
||||||
|
p9pbuf_put_4(pb, P9PROTO_NOFID);
|
||||||
|
p9pbuf_put_str(pb, username);
|
||||||
|
p9pbuf_put_str(pb, "");
|
||||||
|
while ((rv = p9pbuf_write(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Tattach send failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_IN);
|
||||||
|
while ((rv = p9pbuf_read(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Rattach receive failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_ATTACH) {
|
||||||
|
warnx("Rattach not received, got %d", pb->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pb->tagid != tagid) {
|
||||||
|
warnx("server invalid tag: %d vs. %d\n", tagid, pb->tagid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
if (!proto_getqid(pb, rqid)) {
|
||||||
|
warnx("cannot read root node qid");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* finally, stat the rootnode */
|
||||||
|
tagid = NEXTTAG(p9p);
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_STAT);
|
||||||
|
p9pbuf_put_2(pb, tagid);
|
||||||
|
p9pbuf_put_4(pb, P9P_ROOTFID);
|
||||||
|
while ((rv = p9pbuf_write(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Tstat send failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_IN);
|
||||||
|
while ((rv = p9pbuf_read(p9p, pb)) != 1) {
|
||||||
|
if (rv == -1) {
|
||||||
|
warn("Rstat receive failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_STAT) {
|
||||||
|
warnx("Rstat not received, got %d", pb->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pb->tagid != tagid) {
|
||||||
|
warnx("server invalid tag: %d vs. %d\n", tagid, pb->tagid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!p9pbuf_get_2(pb, &dummy)) {
|
||||||
|
warnx("couldn't get stat len parameter");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!proto_getstat(pb, &rootva, NULL, NULL)) {
|
||||||
|
warnx("could not parse root attributes");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
|
||||||
|
rootva.va_nlink = 0156; /* guess, will be fixed with first readdir */
|
||||||
|
pn = newp9pnode_va(pu, &rootva, P9P_ROOTFID);
|
||||||
|
|
||||||
|
if (ioctl(p9p->servsock, FIONBIO, &x) == -1) {
|
||||||
|
warnx("cannot set socket in nonblocking mode");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
|
||||||
|
{
|
||||||
|
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
||||||
|
struct puffs9p *p9p = puffs_getspecific(pu);
|
||||||
|
|
||||||
|
close(p9p->servsock);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
.\" $NetBSD: mount_9p.8,v 1.1 2007/04/21 14:21:43 pooka Exp $
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.Dd April 21, 2007
|
||||||
|
.Dt MOUNT_9P 8
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm mount_9p
|
||||||
|
.Nd mount a file server using the 9P resource sharing protocol
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Ar options
|
||||||
|
.Ar user
|
||||||
|
.Ar file_server
|
||||||
|
.Ar mount_point
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
program is used to mount a file hierarchy served with the Plan9
|
||||||
|
file sharing protocol: 9P.
|
||||||
|
After the file system is mounted, the files on the remote
|
||||||
|
.Ar file_server
|
||||||
|
will be accessed using the credentials of the user named
|
||||||
|
.Ar user
|
||||||
|
and whatever uid the user happens to have on the remote server.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr puffs 3 ,
|
||||||
|
.Xr puffs 4 ,
|
||||||
|
.Xr mount 8
|
||||||
|
.Sh HISTORY
|
||||||
|
The
|
||||||
|
.Nm
|
||||||
|
utility first appeared in
|
||||||
|
.Nx 5.0 .
|
||||||
|
.Sh CAVEATS
|
||||||
|
Permissions are not handled well.
|
||||||
|
.Pp
|
||||||
|
Authentication support is missing.
|
||||||
|
.Pp
|
||||||
|
Error code handling is missing.
|
||||||
|
.Pp
|
||||||
|
Under construction.
|
|
@ -0,0 +1,454 @@
|
||||||
|
/* $NetBSD: ninebuf.c,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: ninebuf.c,v 1.1 2007/04/21 14:21:43 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from my psshfs implementation. Maybe need to look into
|
||||||
|
* unifying these at some level, although there are minor variations.
|
||||||
|
*
|
||||||
|
* Such as the fact that 9P is a little endian protocol ....
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_read(struct puffs9p *p9p, struct p9pbuf *pb)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
assert(pb->state != P9PBUF_PUT);
|
||||||
|
|
||||||
|
again:
|
||||||
|
n = read(p9p->servsock, pb->buf+pb->offset, pb->remain);
|
||||||
|
switch (n) {
|
||||||
|
case 0:
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
case -1:
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
pb->offset += n;
|
||||||
|
pb->remain -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb->remain != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* ok, at least there's something to do */
|
||||||
|
assert(pb->state == P9PBUF_GETLEN || pb->state == P9PBUF_GETDATA);
|
||||||
|
|
||||||
|
if (pb->state == P9PBUF_GETLEN) {
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
memcpy(&len, pb->buf, 4);
|
||||||
|
pb->remain = le32toh(len) - 4;
|
||||||
|
assert(pb->remain <= pb->len); /* XXX */
|
||||||
|
pb->offset = 0;
|
||||||
|
|
||||||
|
pb->state = P9PBUF_GETDATA;
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
} else if (pb->state == P9PBUF_GETDATA) {
|
||||||
|
pb->remain = pb->offset;
|
||||||
|
pb->offset = 0;
|
||||||
|
|
||||||
|
pb->state = P9PBUF_GETREADY;
|
||||||
|
|
||||||
|
/* sloppy */
|
||||||
|
if (!p9pbuf_get_1(pb, &pb->type))
|
||||||
|
errx(1, "invalid server response, no type");
|
||||||
|
if (!p9pbuf_get_2(pb, &pb->tagid))
|
||||||
|
errx(1, "invalid server response, no tag");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; /* XXX: impossible */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_write(struct puffs9p *p9p, struct p9pbuf *pb)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if (pb->state == P9PBUF_PUT) {
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
len = htole32(pb->offset);
|
||||||
|
memcpy(pb->buf, &len, sizeof(len));
|
||||||
|
|
||||||
|
pb->remain = pb->offset;
|
||||||
|
pb->offset = 0;
|
||||||
|
|
||||||
|
pb->state = P9PBUF_PUTDONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUTDONE);
|
||||||
|
|
||||||
|
n = write(p9p->servsock, pb->buf + pb->offset, pb->remain);
|
||||||
|
if (n == 0) {
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pb->offset += n;
|
||||||
|
pb->remain -= n;
|
||||||
|
|
||||||
|
if (pb->remain == 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct p9pbuf *
|
||||||
|
p9pbuf_make(size_t reqsize, int incoming)
|
||||||
|
{
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
|
||||||
|
pb = emalloc(sizeof(struct p9pbuf));
|
||||||
|
memset(pb, 0, sizeof(struct p9pbuf));
|
||||||
|
pb->buf = emalloc(reqsize);
|
||||||
|
pb->len = reqsize;
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, incoming);
|
||||||
|
|
||||||
|
return pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
p9pbuf_destroy(struct p9pbuf *pb)
|
||||||
|
{
|
||||||
|
|
||||||
|
free(pb->buf);
|
||||||
|
free(pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
p9pbuf_recycle(struct p9pbuf *pb, int incoming)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (incoming) {
|
||||||
|
pb->offset = 0;
|
||||||
|
pb->remain = 4;
|
||||||
|
pb->state = P9PBUF_GETLEN;
|
||||||
|
} else {
|
||||||
|
/* save space for len */
|
||||||
|
pb->remain = pb->len - 4;
|
||||||
|
pb->offset = 4;
|
||||||
|
|
||||||
|
pb->state = P9PBUF_PUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* allow put 1,2,4,8 in the middle and do *not* adjust remain
|
||||||
|
* in that case. However, do check the extending is possible
|
||||||
|
* only from the end
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_1(struct p9pbuf *pb, uint8_t val)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, 1);
|
||||||
|
|
||||||
|
memcpy(pb->buf + pb->offset, &val, 1);
|
||||||
|
if (pb->offset + pb->remain == pb->len)
|
||||||
|
pb->remain -= 1;
|
||||||
|
pb->offset += 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_2(struct p9pbuf *pb, uint16_t val)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, 2);
|
||||||
|
|
||||||
|
HTOLE16(val);
|
||||||
|
memcpy(pb->buf + pb->offset, &val, 2);
|
||||||
|
if (pb->offset + pb->remain == pb->len)
|
||||||
|
pb->remain -= 2;
|
||||||
|
else
|
||||||
|
assert(pb->offset + pb->remain + 2 <= pb->len);
|
||||||
|
pb->offset += 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_4(struct p9pbuf *pb, uint32_t val)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, 4);
|
||||||
|
|
||||||
|
HTOLE32(val);
|
||||||
|
memcpy(pb->buf + pb->offset, &val, 4);
|
||||||
|
if (pb->offset + pb->remain == pb->len)
|
||||||
|
pb->remain -= 4;
|
||||||
|
else
|
||||||
|
assert(pb->offset + pb->remain + 4 <= pb->len);
|
||||||
|
pb->offset += 4;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_8(struct p9pbuf *pb, uint64_t val)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, 8);
|
||||||
|
|
||||||
|
HTOLE64(val);
|
||||||
|
memcpy(pb->buf + pb->offset, &val, 8);
|
||||||
|
if (pb->offset + pb->remain == pb->len)
|
||||||
|
pb->remain -= 8;
|
||||||
|
else
|
||||||
|
assert(pb->offset + pb->remain + 8 <= pb->len);
|
||||||
|
pb->offset += 8;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_data(struct p9pbuf *pb, const void *data, uint16_t dlen)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, dlen + 2);
|
||||||
|
|
||||||
|
p9pbuf_put_2(pb, dlen);
|
||||||
|
memcpy(pb->buf + pb->offset, data, dlen);
|
||||||
|
pb->offset += dlen;
|
||||||
|
pb->remain -= dlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_put_str(struct p9pbuf *pb, const char *str)
|
||||||
|
{
|
||||||
|
|
||||||
|
return p9pbuf_put_data(pb, str, strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_write_data(struct p9pbuf *pb, uint8_t *data, uint32_t dlen)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_PUT);
|
||||||
|
|
||||||
|
P9PB_CHECK(pb, dlen);
|
||||||
|
memcpy(pb->buf + pb->offset, data, dlen);
|
||||||
|
pb->offset += dlen;
|
||||||
|
pb->remain -= dlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_1(struct p9pbuf *pb, uint8_t *val)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (pb->remain < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(val, pb->buf + pb->offset, 1);
|
||||||
|
pb->offset += 1;
|
||||||
|
pb->remain -= 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_2(struct p9pbuf *pb, uint16_t *val)
|
||||||
|
{
|
||||||
|
uint16_t v;
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (pb->remain < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(&v, pb->buf + pb->offset, 2);
|
||||||
|
pb->offset += 2;
|
||||||
|
pb->remain -= 2;
|
||||||
|
|
||||||
|
*val = le16toh(v);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_4(struct p9pbuf *pb, uint32_t *val)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (pb->remain < 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(&v, pb->buf + pb->offset, 4);
|
||||||
|
pb->offset += 4;
|
||||||
|
pb->remain -= 4;
|
||||||
|
|
||||||
|
*val = le32toh(v);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_8(struct p9pbuf *pb, uint64_t *val)
|
||||||
|
{
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (pb->remain < 8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(&v, pb->buf + pb->offset, 8);
|
||||||
|
pb->offset += 8;
|
||||||
|
pb->remain -= 8;
|
||||||
|
|
||||||
|
*val = le64toh(v);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_data(struct p9pbuf *pb, uint8_t **dp, uint16_t *dlenp)
|
||||||
|
{
|
||||||
|
uint8_t *d;
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (!(p9pbuf_get_2(pb, &len)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pb->remain < len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dp) {
|
||||||
|
d = emalloc(len+1);
|
||||||
|
memcpy(d, pb->buf + pb->offset, len);
|
||||||
|
d[len] = '\0';
|
||||||
|
*dp = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
pb->offset += len;
|
||||||
|
pb->remain -= len;
|
||||||
|
|
||||||
|
if (dlenp)
|
||||||
|
*dlenp = len;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_read_data(struct p9pbuf *pb, uint8_t *buf, uint32_t dlen)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(pb->state == P9PBUF_GETREADY);
|
||||||
|
|
||||||
|
if (pb->remain < dlen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memcpy(buf, pb->buf + pb->offset, dlen);
|
||||||
|
pb->offset += dlen;
|
||||||
|
pb->remain -= dlen;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_get_str(struct p9pbuf *pb, char **dp, uint16_t *dlenp)
|
||||||
|
{
|
||||||
|
|
||||||
|
return p9pbuf_get_data(pb, (uint8_t **)dp, dlenp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_tell(struct p9pbuf *pb)
|
||||||
|
{
|
||||||
|
|
||||||
|
return pb->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9pbuf_remaining(struct p9pbuf *pb)
|
||||||
|
{
|
||||||
|
|
||||||
|
return pb->remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
p9pbuf_seekset(struct p9pbuf *pb, int newoff)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (newoff > pb->offset)
|
||||||
|
pb->remain -= newoff - pb->offset;
|
||||||
|
pb->offset = newoff;
|
||||||
|
}
|
|
@ -0,0 +1,365 @@
|
||||||
|
/* $NetBSD: nineproto.c,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: nineproto.c,v 1.1 2007/04/21 14:21:43 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
#include "nineproto.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_getqid(struct p9pbuf *pb, struct qid9p *qid)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pb->remain < 13)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p9pbuf_get_1(pb, &qid->qidtype);
|
||||||
|
p9pbuf_get_4(pb, &qid->qidvers);
|
||||||
|
p9pbuf_get_8(pb, &qid->qidpath);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uid_t
|
||||||
|
ustr2uid(char *uid)
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
pw = getpwnam(uid);
|
||||||
|
if (pw == NULL)
|
||||||
|
return 0; /* XXXXX */
|
||||||
|
|
||||||
|
return pw->pw_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gid_t
|
||||||
|
gstr2gid(char *gid)
|
||||||
|
{
|
||||||
|
struct group *grr;
|
||||||
|
|
||||||
|
grr = getgrnam(gid);
|
||||||
|
if (grr == NULL)
|
||||||
|
return 0; /* more XXXX */
|
||||||
|
|
||||||
|
return grr->gr_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
uid2ustr(uid_t uid)
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
pw = getpwuid(uid);
|
||||||
|
if (pw == NULL)
|
||||||
|
return "root"; /* XXXXX */
|
||||||
|
|
||||||
|
return pw->pw_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
gid2gstr(gid_t gid)
|
||||||
|
{
|
||||||
|
struct group *grr;
|
||||||
|
|
||||||
|
grr = getgrgid(gid);
|
||||||
|
if (grr == NULL)
|
||||||
|
return "wheel"; /* XXXXXX */
|
||||||
|
|
||||||
|
return grr->gr_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GETFIELD(a,b,unitsize) \
|
||||||
|
do { \
|
||||||
|
if (size < unitsize) return 0; \
|
||||||
|
if (!(a(pb, b))) return 0; \
|
||||||
|
size -= unitsize; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
#define GETSTR(val,strsize) \
|
||||||
|
do { \
|
||||||
|
if (!(p9pbuf_get_str(pb, val, strsize))) return 0; \
|
||||||
|
if (*strsize > size) return 0; \
|
||||||
|
size -= *strsize; \
|
||||||
|
} while (/*CONSTCOND*/0)
|
||||||
|
int
|
||||||
|
proto_getstat(struct p9pbuf *pb, struct vattr *vap, char **name, uint16_t *rs)
|
||||||
|
{
|
||||||
|
char *uid, *gid;
|
||||||
|
struct qid9p qid;
|
||||||
|
uint64_t flen;
|
||||||
|
uint32_t rdev, mode, atime, mtime;
|
||||||
|
uint16_t size, v16;
|
||||||
|
|
||||||
|
/* check size */
|
||||||
|
if (!p9pbuf_get_2(pb, &size))
|
||||||
|
return 0;
|
||||||
|
if (p9pbuf_remaining(pb) < size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (rs)
|
||||||
|
*rs = size+2; /* compensate for size field itself */
|
||||||
|
|
||||||
|
GETFIELD(p9pbuf_get_2, &v16, 2);
|
||||||
|
if (v16)
|
||||||
|
printf("%d\n", v16);
|
||||||
|
GETFIELD(p9pbuf_get_4, &rdev, 4);
|
||||||
|
GETFIELD(proto_getqid, &qid, 13);
|
||||||
|
GETFIELD(p9pbuf_get_4, &mode, 4);
|
||||||
|
GETFIELD(p9pbuf_get_4, &atime, 4);
|
||||||
|
GETFIELD(p9pbuf_get_4, &mtime, 4);
|
||||||
|
GETFIELD(p9pbuf_get_8, &flen, 8);
|
||||||
|
GETSTR(name, &v16);
|
||||||
|
GETSTR(&uid, &v16);
|
||||||
|
GETSTR(&gid, &v16);
|
||||||
|
|
||||||
|
if (rdev)
|
||||||
|
printf("%d\n", rdev);
|
||||||
|
vap->va_rdev = rdev;
|
||||||
|
vap->va_mode = mode & 0777; /* may contain other uninteresting bits */
|
||||||
|
vap->va_atime.tv_sec = atime;
|
||||||
|
vap->va_mtime.tv_sec = mtime;
|
||||||
|
vap->va_ctime.tv_sec = mtime;
|
||||||
|
vap->va_atime.tv_nsec=vap->va_mtime.tv_nsec=vap->va_ctime.tv_nsec = 0;
|
||||||
|
vap->va_birthtime.tv_sec = vap->va_birthtime.tv_nsec = 0;
|
||||||
|
vap->va_size = vap->va_bytes = flen;
|
||||||
|
vap->va_uid = ustr2uid(uid);
|
||||||
|
vap->va_gid = gstr2gid(gid);
|
||||||
|
qid2vattr(vap, &qid);
|
||||||
|
|
||||||
|
/* some defaults */
|
||||||
|
if (vap->va_type == VDIR)
|
||||||
|
vap->va_nlink = 1906;
|
||||||
|
else
|
||||||
|
vap->va_nlink = 1;
|
||||||
|
vap->va_blocksize = 512;
|
||||||
|
vap->va_flags = vap->va_vaflags = 0;
|
||||||
|
vap->va_filerev = PUFFS_VNOVAL;
|
||||||
|
|
||||||
|
/* muid, not used */
|
||||||
|
GETSTR(NULL, &v16);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_cc_dupfid(struct puffs_cc *pcc, p9pfid_t oldfid, p9pfid_t newfid)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc);
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
p9ptag_t tag = NEXTTAG(p9p);
|
||||||
|
uint16_t qids;
|
||||||
|
int rv, error = 0;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WALK);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, oldfid);
|
||||||
|
p9pbuf_put_4(pb, newfid);
|
||||||
|
p9pbuf_put_2(pb, 0);
|
||||||
|
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
rv = proto_expect_walk_nqids(pb, &qids);
|
||||||
|
if (rv)
|
||||||
|
error = rv;
|
||||||
|
if (qids != 0)
|
||||||
|
error = EPROTO;
|
||||||
|
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_cc_clunkfid(struct puffs_cc *pcc, p9pfid_t fid, int waitforit)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc);
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
p9ptag_t tag = NEXTTAG(p9p);
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_CLUNK);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, fid);
|
||||||
|
|
||||||
|
if (waitforit) {
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
if (pb->type != P9PROTO_R_CLUNK)
|
||||||
|
error = EPROTO;
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
} else {
|
||||||
|
outbuf_enqueue_nocc(p9p, pb, NULL, NULL, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* walk a new fid, then open it
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
proto_cc_open(struct puffs_cc *pcc, p9pfid_t fid, p9pfid_t newfid, int mode)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc);
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
p9ptag_t tag = NEXTTAG(p9p);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = proto_cc_dupfid(pcc, fid, newfid);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_OPEN);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, newfid);
|
||||||
|
p9pbuf_put_1(pb, mode);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
if (pb->type != P9PROTO_R_OPEN)
|
||||||
|
error = EPROTO;
|
||||||
|
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
proto_make_stat(struct p9pbuf *pb, const struct vattr *vap,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
struct vattr fakeva;
|
||||||
|
uint32_t mode, atime, mtime;
|
||||||
|
uint64_t flen;
|
||||||
|
const char *owner, *group;
|
||||||
|
int startoff, curoff;
|
||||||
|
|
||||||
|
if (vap == NULL) {
|
||||||
|
puffs_vattr_null(&fakeva);
|
||||||
|
vap = &fakeva;
|
||||||
|
}
|
||||||
|
|
||||||
|
startoff = p9pbuf_tell(pb);
|
||||||
|
p9pbuf_seekset(pb, startoff + 2 + 2); /* stat[n], containing stat[2] */
|
||||||
|
|
||||||
|
if (vap->va_mode != (mode_t)PUFFS_VNOVAL)
|
||||||
|
mode = vap->va_mode;
|
||||||
|
else
|
||||||
|
mode = P9PROTO_STAT_NOVAL4;
|
||||||
|
if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||||
|
atime = vap->va_atime.tv_sec;
|
||||||
|
else
|
||||||
|
atime = P9PROTO_STAT_NOVAL4;
|
||||||
|
if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||||
|
mtime = vap->va_mtime.tv_sec;
|
||||||
|
else
|
||||||
|
mtime = P9PROTO_STAT_NOVAL4;
|
||||||
|
if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
|
||||||
|
flen = vap->va_size;
|
||||||
|
else
|
||||||
|
flen = P9PROTO_STAT_NOVAL8;
|
||||||
|
if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
|
||||||
|
owner = uid2ustr(vap->va_uid);
|
||||||
|
else
|
||||||
|
owner = "";
|
||||||
|
if (vap->va_gid != (gid_t)PUFFS_VNOVAL)
|
||||||
|
group = gid2gstr(vap->va_gid);
|
||||||
|
else
|
||||||
|
group = "";
|
||||||
|
|
||||||
|
p9pbuf_put_2(pb, P9PROTO_STAT_NOVAL2); /* kernel type */
|
||||||
|
p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* dev */
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_STAT_NOVAL1); /* type */
|
||||||
|
p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* version */
|
||||||
|
p9pbuf_put_8(pb, P9PROTO_STAT_NOVAL8); /* path */
|
||||||
|
p9pbuf_put_4(pb, mode);
|
||||||
|
p9pbuf_put_4(pb, atime);
|
||||||
|
p9pbuf_put_4(pb, mtime);
|
||||||
|
p9pbuf_put_8(pb, flen);
|
||||||
|
p9pbuf_put_str(pb, filename ? filename : "");
|
||||||
|
p9pbuf_put_str(pb, owner);
|
||||||
|
p9pbuf_put_str(pb, group);
|
||||||
|
p9pbuf_put_str(pb, ""); /* muid */
|
||||||
|
|
||||||
|
curoff = p9pbuf_tell(pb);
|
||||||
|
p9pbuf_seekset(pb, startoff);
|
||||||
|
p9pbuf_put_2(pb, curoff-(startoff+2)); /* stat[n] size */
|
||||||
|
p9pbuf_put_2(pb, curoff-(startoff+4)); /* size[2] stat */
|
||||||
|
|
||||||
|
p9pbuf_seekset(pb, curoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_expect_walk_nqids(struct p9pbuf *pb, uint16_t *nqids)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_WALK)
|
||||||
|
return EPROTO;
|
||||||
|
if (!p9pbuf_get_2(pb, nqids))
|
||||||
|
return EPROTO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_expect_qid(struct p9pbuf *pb, uint8_t op, struct qid9p *qid)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pb->type != op)
|
||||||
|
return EPROTO;
|
||||||
|
if (!proto_getqid(pb, qid))
|
||||||
|
return EPROTO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
proto_expect_stat(struct p9pbuf *pb, struct vattr *va)
|
||||||
|
{
|
||||||
|
uint16_t dummy;
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_STAT)
|
||||||
|
return EPROTO;
|
||||||
|
if (!p9pbuf_get_2(pb, &dummy))
|
||||||
|
return EPROTO;
|
||||||
|
if (!proto_getstat(pb, va, NULL, NULL))
|
||||||
|
return EPROTO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* $NetBSD: nineproto.h,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PUFFS9P_9PROTO_H_
|
||||||
|
#define PUFFS9P_9PROTO_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define P9PROTO_VERSION "9P2000"
|
||||||
|
|
||||||
|
#define P9PROTO_T_VERSION 100
|
||||||
|
#define P9PROTO_R_VERSION 101
|
||||||
|
#define P9PROTO_T_AUTH 102
|
||||||
|
#define P9PROTO_R_AUTH 103
|
||||||
|
#define P9PROTO_T_ATTACH 104
|
||||||
|
#define P9PROTO_R_ATTACH 105
|
||||||
|
#define P9PROTO_T_ERROR 106
|
||||||
|
#define P9PROTO_R_ERROR 107
|
||||||
|
#define P9PROTO_T_FLUSH 108
|
||||||
|
#define P9PROTO_R_FLUSH 109
|
||||||
|
#define P9PROTO_T_WALK 110
|
||||||
|
#define P9PROTO_R_WALK 111
|
||||||
|
#define P9PROTO_T_OPEN 112
|
||||||
|
#define P9PROTO_R_OPEN 113
|
||||||
|
#define P9PROTO_T_CREATE 114
|
||||||
|
#define P9PROTO_R_CREATE 115
|
||||||
|
#define P9PROTO_T_READ 116
|
||||||
|
#define P9PROTO_R_READ 117
|
||||||
|
#define P9PROTO_T_WRITE 118
|
||||||
|
#define P9PROTO_R_WRITE 119
|
||||||
|
#define P9PROTO_T_CLUNK 120
|
||||||
|
#define P9PROTO_R_CLUNK 121
|
||||||
|
#define P9PROTO_T_REMOVE 122
|
||||||
|
#define P9PROTO_R_REMOVE 123
|
||||||
|
#define P9PROTO_T_STAT 124
|
||||||
|
#define P9PROTO_R_STAT 125
|
||||||
|
#define P9PROTO_T_WSTAT 126
|
||||||
|
#define P9PROTO_R_WSTAT 127
|
||||||
|
#define P9PROTO_MIN 9PROTO_T_VERSION
|
||||||
|
#define P9PROTO_MAX 9PROTO_R_MAX
|
||||||
|
|
||||||
|
#define P9PROTO_NOFID (uint32_t)~0
|
||||||
|
#define P9PROTO_NOTAG (uint16_t)~0
|
||||||
|
|
||||||
|
/* type field in a qid */
|
||||||
|
#define P9PROTO_QID_TYPE_DIR 0x80
|
||||||
|
#define P9PROTO_QID_TYPE_APPEND 0x40
|
||||||
|
#define P9PROTO_QID_TYPE_EXCL 0x20
|
||||||
|
#define P9PROTO_QID_TYPE_MOUNT 0x10
|
||||||
|
#define P9PROTO_QID_TYPE_AUTH 0x08
|
||||||
|
|
||||||
|
/* mode in open */
|
||||||
|
#define P9PROTO_OMODE_READ 0x00
|
||||||
|
#define P9PROTO_OMODE_WRITE 0x01
|
||||||
|
#define P9PROTO_OMODE_RDWR 0x02
|
||||||
|
#define P9PROTO_OMODE_EXEC 0x03
|
||||||
|
#define P9PROTO_OMODE_TRUNC 0x10
|
||||||
|
#define P9PROTO_OMODE_RMCLOSE 0x40
|
||||||
|
|
||||||
|
/* for creating directories */
|
||||||
|
#define P9PROTO_CPERM_DIR 0x80000000
|
||||||
|
|
||||||
|
/* stat non-values */
|
||||||
|
#define P9PROTO_STAT_NOVAL1 (uint8_t)~0
|
||||||
|
#define P9PROTO_STAT_NOVAL2 (uint16_t)~0
|
||||||
|
#define P9PROTO_STAT_NOVAL4 (uint32_t)~0
|
||||||
|
#define P9PROTO_STAT_NOVAL8 (uint64_t)~0
|
||||||
|
|
||||||
|
#endif /* PUFFS9P_PROTO_H_ */
|
|
@ -0,0 +1,394 @@
|
||||||
|
/* $NetBSD: ninepuffs.c,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 9puffs: access a 9P file server as a vfs via puffs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: ninepuffs.c,v 1.1 2007/04/21 14:21:43 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
|
||||||
|
#define DEFPORT_9P 564
|
||||||
|
|
||||||
|
static void puffs9p_eventloop(struct puffs_usermount *, struct puffs9p *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
errx(1, "usage: %s user server mountpoint", getprogname());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TCPv4 connection to 9P file server, forget IL and IPv6 for now.
|
||||||
|
* Return connected socket or exit with error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
serverconnect(const char *addr, unsigned short port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in mysin;
|
||||||
|
struct hostent *he;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
he = gethostbyname2(addr, AF_INET);
|
||||||
|
if (he == NULL) {
|
||||||
|
herror("gethostbyname");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (s == -1)
|
||||||
|
err(1, "socket");
|
||||||
|
|
||||||
|
memset(&mysin, 0, sizeof(struct sockaddr_in));
|
||||||
|
mysin.sin_family = AF_INET;
|
||||||
|
mysin.sin_port = htons(port);
|
||||||
|
memcpy(&mysin.sin_addr, he->h_addr, sizeof(struct in_addr));
|
||||||
|
|
||||||
|
if (connect(s, (struct sockaddr *)&mysin, sizeof(mysin)) == -1)
|
||||||
|
err(1, "connect");
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct puffs9p p9p;
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_ops *pops;
|
||||||
|
struct puffs_node *pn_root;
|
||||||
|
struct statvfs svfsb;
|
||||||
|
mntoptparse_t mp;
|
||||||
|
char *srvhost;
|
||||||
|
char *user;
|
||||||
|
unsigned short port;
|
||||||
|
int mntflags, pflags, ch;
|
||||||
|
int detach;
|
||||||
|
|
||||||
|
setprogname(argv[0]);
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
mntflags = pflags = 0;
|
||||||
|
detach = 1;
|
||||||
|
port = DEFPORT_9P;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "o:p:s")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'o':
|
||||||
|
mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags);
|
||||||
|
if (mp == NULL)
|
||||||
|
err(1, "getmntopts");
|
||||||
|
freemntopts(mp);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
detach = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
user = argv[0];
|
||||||
|
srvhost = argv[1];
|
||||||
|
|
||||||
|
if (pflags & PUFFS_FLAG_OPDUMP)
|
||||||
|
detach = 0;
|
||||||
|
|
||||||
|
PUFFSOP_INIT(pops);
|
||||||
|
|
||||||
|
PUFFSOP_SET(pops, puffs9p, fs, unmount);
|
||||||
|
PUFFSOP_SETFSNOP(pops, sync);
|
||||||
|
PUFFSOP_SETFSNOP(pops, statvfs);
|
||||||
|
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, lookup);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, readdir);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, getattr);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, setattr);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, create);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, open);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, close);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, mkdir);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, remove);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, rmdir);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, read);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, write);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, rename);
|
||||||
|
#if 0
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, reclaim);
|
||||||
|
PUFFSOP_SET(pops, puffs9p, node, mknod);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(&p9p, 0, sizeof(p9p));
|
||||||
|
p9p.maxreq = P9P_DEFREQLEN;
|
||||||
|
p9p.nextfid = 1;
|
||||||
|
TAILQ_INIT(&p9p.outbufq);
|
||||||
|
TAILQ_INIT(&p9p.req_queue);
|
||||||
|
|
||||||
|
p9p.servsock = serverconnect(srvhost, port);
|
||||||
|
pu = puffs_init(pops, "9P", &p9p, pflags);
|
||||||
|
if (pu == NULL)
|
||||||
|
err(1, "puffs_init");
|
||||||
|
|
||||||
|
if ((pn_root = p9p_handshake(pu, user)) == NULL) {
|
||||||
|
puffs_exit(pu, 1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK) == -1)
|
||||||
|
err(1, "setblockingmode");
|
||||||
|
|
||||||
|
if (puffs_domount(pu, argv[2], mntflags) == -1)
|
||||||
|
err(1, "puffs_domount");
|
||||||
|
|
||||||
|
puffs_zerostatvfs(&svfsb);
|
||||||
|
if (puffs_start(pu, pn_root, &svfsb) == -1)
|
||||||
|
err(1, "puffs_start");
|
||||||
|
|
||||||
|
if (detach)
|
||||||
|
daemon(1, 0);
|
||||||
|
|
||||||
|
puffs9p_eventloop(pu, &p9p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enqueue buffer to be handled with cc
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
outbuf_enqueue(struct puffs9p *p9p, struct p9pbuf *pb,
|
||||||
|
struct puffs_cc *pcc, uint16_t tagid)
|
||||||
|
{
|
||||||
|
|
||||||
|
pb->p9pr.tagid = tagid;
|
||||||
|
pb->p9pr.pcc = pcc;
|
||||||
|
pb->p9pr.func = NULL;
|
||||||
|
pb->p9pr.arg = NULL;
|
||||||
|
TAILQ_INSERT_TAIL(&p9p->outbufq, pb, p9pr.entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enqueue buffer to be handled with "f". "f" must not block.
|
||||||
|
* gives up struct p9pbuf ownership.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
outbuf_enqueue_nocc(struct puffs9p *p9p, struct p9pbuf *pb,
|
||||||
|
void (*f)(struct puffs9p *, struct p9pbuf *, void *), void *arg,
|
||||||
|
uint16_t tagid)
|
||||||
|
{
|
||||||
|
|
||||||
|
pb->p9pr.tagid = tagid;
|
||||||
|
pb->p9pr.pcc = NULL;
|
||||||
|
pb->p9pr.func = f;
|
||||||
|
pb->p9pr.arg = arg;
|
||||||
|
TAILQ_INSERT_TAIL(&p9p->outbufq, pb, p9pr.entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct p9pbuf *
|
||||||
|
req_get(struct puffs9p *p9p, uint16_t tagid)
|
||||||
|
{
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(pb, &p9p->req_queue, p9pr.entries)
|
||||||
|
if (pb->p9pr.tagid == tagid)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!pb)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&p9p->req_queue, pb, p9pr.entries);
|
||||||
|
|
||||||
|
return pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handlebuf(struct puffs9p *p9p, struct p9pbuf *datapb,
|
||||||
|
struct puffs_putreq *ppr)
|
||||||
|
{
|
||||||
|
struct p9preq p9prtmp;
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
|
||||||
|
/* is this something we are expecting? */
|
||||||
|
pb = req_get(p9p, datapb->tagid);
|
||||||
|
|
||||||
|
if (pb == NULL) {
|
||||||
|
printf("invalid server request response %d\n", datapb->tagid);
|
||||||
|
p9pbuf_destroy(datapb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep p9preq clean, xxx uknow */
|
||||||
|
p9prtmp = pb->p9pr;
|
||||||
|
*pb = *datapb;
|
||||||
|
pb->p9pr = p9prtmp;
|
||||||
|
free(datapb);
|
||||||
|
|
||||||
|
/* don't allow both cc and handler func, but allow neither */
|
||||||
|
assert((pb->p9pr.pcc && pb->p9pr.func) == 0);
|
||||||
|
if (pb->p9pr.pcc) {
|
||||||
|
puffs_docc(pb->p9pr.pcc, ppr);
|
||||||
|
} else if (pb->p9pr.func) {
|
||||||
|
pb->p9pr.func(p9p, pb, pb->p9pr.arg);
|
||||||
|
} else {
|
||||||
|
assert(pb->p9pr.arg == NULL);
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
psshinput(struct puffs9p *p9p, struct puffs_putreq *ppr)
|
||||||
|
{
|
||||||
|
struct p9pbuf *cb;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if ((cb = p9p->curpb) == NULL) {
|
||||||
|
cb = p9pbuf_make(p9p->maxreq, P9PB_IN);
|
||||||
|
if (cb == NULL)
|
||||||
|
return -1;
|
||||||
|
p9p->curpb = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = p9pbuf_read(p9p, cb);
|
||||||
|
if (rv == -1)
|
||||||
|
err(1, "p9pbuf read");
|
||||||
|
if (rv == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
handlebuf(p9p, cb, ppr);
|
||||||
|
p9p->curpb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
psshoutput(struct puffs9p *p9p)
|
||||||
|
{
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(pb, &p9p->outbufq, p9pr.entries) {
|
||||||
|
rv = p9pbuf_write(p9p, pb);
|
||||||
|
if (rv == -1)
|
||||||
|
return -1;
|
||||||
|
if (rv == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* sent everything, move to cookiequeue */
|
||||||
|
TAILQ_REMOVE(&p9p->outbufq, pb, p9pr.entries);
|
||||||
|
free(pb->buf);
|
||||||
|
TAILQ_INSERT_TAIL(&p9p->req_queue, pb, p9pr.entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PFD_SOCK 0
|
||||||
|
#define PFD_PUFFS 1
|
||||||
|
static void
|
||||||
|
puffs9p_eventloop(struct puffs_usermount *pu, struct puffs9p *p9p)
|
||||||
|
{
|
||||||
|
struct puffs_getreq *pgr;
|
||||||
|
struct puffs_putreq *ppr;
|
||||||
|
struct pollfd pfds[2];
|
||||||
|
|
||||||
|
pgr = puffs_req_makeget(pu, puffs_getmaxreqlen(pu), 0);
|
||||||
|
if (!pgr)
|
||||||
|
err(1, "makegetreq");
|
||||||
|
ppr = puffs_req_makeput(pu);
|
||||||
|
if (!ppr)
|
||||||
|
err(1, "makeputreq");
|
||||||
|
|
||||||
|
while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
|
||||||
|
memset(pfds, 0, sizeof(pfds));
|
||||||
|
pfds[PFD_SOCK].events = POLLIN;
|
||||||
|
if (!TAILQ_EMPTY(&p9p->outbufq))
|
||||||
|
pfds[PFD_SOCK].events |= POLLOUT;
|
||||||
|
pfds[PFD_SOCK].fd = p9p->servsock;
|
||||||
|
pfds[PFD_PUFFS].fd = puffs_getselectable(pu);
|
||||||
|
pfds[PFD_PUFFS].events = POLLIN;
|
||||||
|
|
||||||
|
if (poll(pfds, 2, INFTIM) == -1)
|
||||||
|
err(1, "poll");
|
||||||
|
|
||||||
|
if (pfds[PFD_SOCK].revents & POLLOUT)
|
||||||
|
if (psshoutput(p9p) == -1)
|
||||||
|
err(1, "psshoutput");
|
||||||
|
|
||||||
|
/* get & possibly dispatch events from kernel */
|
||||||
|
if (pfds[PFD_PUFFS].revents & POLLIN)
|
||||||
|
if (puffs_req_handle(pu, pgr, ppr, 0) == -1)
|
||||||
|
err(1, "puffs_handlereqs");
|
||||||
|
|
||||||
|
/* get input from sftpd, possibly build more responses */
|
||||||
|
if (pfds[PFD_SOCK].revents & POLLIN)
|
||||||
|
if (psshinput(p9p, ppr) == -1)
|
||||||
|
errx(1, "psshinput");
|
||||||
|
|
||||||
|
/* it's likely we got outputtables, poke the ice with a stick */
|
||||||
|
if (psshoutput(p9p) == -1)
|
||||||
|
err(1, "psshoutput");
|
||||||
|
|
||||||
|
/* stuff all replies from both of the above into kernel */
|
||||||
|
if (puffs_req_putput(ppr) == -1)
|
||||||
|
err(1, "putputreq");
|
||||||
|
puffs_req_resetput(ppr);
|
||||||
|
}
|
||||||
|
|
||||||
|
puffs_req_destroyget(pgr);
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
/* $NetBSD: ninepuffs.h,v 1.1 2007/04/21 14:21:43 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PUFFS9P_H_
|
||||||
|
#define PUFFS9P_H_
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <puffs.h>
|
||||||
|
|
||||||
|
PUFFSOP_PROTOS(puffs9p);
|
||||||
|
|
||||||
|
/* Qid structure. optimized for in-mem. different order on-wire */
|
||||||
|
struct qid9p {
|
||||||
|
uint64_t qidpath;
|
||||||
|
uint32_t qidvers;
|
||||||
|
uint8_t qidtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint16_t p9ptag_t;
|
||||||
|
typedef uint32_t p9pfid_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* refuse (no, not *that* refuse) to play if the server doesn't
|
||||||
|
* support requests of at least the following size. It would only
|
||||||
|
* make life difficult
|
||||||
|
*/
|
||||||
|
#define P9P_MINREQLEN 512
|
||||||
|
|
||||||
|
#define P9P_DEFREQLEN (16*1024)
|
||||||
|
#define P9P_INVALFID 0
|
||||||
|
#define P9P_ROOTFID 1
|
||||||
|
|
||||||
|
#define NEXTTAG(p9p) \
|
||||||
|
((++(p9p->nexttag)) == P9PROTO_NOTAG ? p9p->nexttag = 0 : p9p->nexttag)
|
||||||
|
|
||||||
|
#define NEXTFID(p9p) \
|
||||||
|
((++(p9p->nextfid)) == P9P_INVALFID ? p9p->nextfid = 2 : p9p->nextfid)
|
||||||
|
|
||||||
|
#define AUTOVAR(pcc) \
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc); \
|
||||||
|
uint16_t tag = NEXTTAG(p9p); \
|
||||||
|
struct p9pbuf *pb = p9pbuf_make(p9p->maxreq, P9PB_OUT); \
|
||||||
|
int rv = 0
|
||||||
|
|
||||||
|
#define RETURN(rv) \
|
||||||
|
p9pbuf_destroy(pb); \
|
||||||
|
return (rv)
|
||||||
|
|
||||||
|
struct puffs9p;
|
||||||
|
/*
|
||||||
|
* XXX: urgh
|
||||||
|
*
|
||||||
|
* This is slightly messy / abusatory structure. It is used for multiple
|
||||||
|
* things. Typical life cycle: create output buffer, append to output
|
||||||
|
* queue (pcc included) . Once the buffer has been sent, the buffer is
|
||||||
|
* freed and the structure is appended to reqqueue as psreq. It is kept
|
||||||
|
* there until matching network data is read. Once this happens, the
|
||||||
|
* data from the received buffer is copied to buffer stored on the queue.
|
||||||
|
* This should be rewritten, clearly.
|
||||||
|
*
|
||||||
|
* Also, this should not be copypasted from psshfs. But that's
|
||||||
|
* another matter ;)
|
||||||
|
*/
|
||||||
|
#define P9PB_OUT 0
|
||||||
|
#define P9PB_IN 1
|
||||||
|
struct p9pbuf {
|
||||||
|
struct p9preq {
|
||||||
|
p9ptag_t tagid;
|
||||||
|
|
||||||
|
/* either ... */
|
||||||
|
struct puffs_cc *pcc;
|
||||||
|
|
||||||
|
/* ... or */
|
||||||
|
void (*func)(struct puffs9p *, struct p9pbuf *, void *);
|
||||||
|
void *arg;
|
||||||
|
/* no union, we'd need a "which" flag */
|
||||||
|
|
||||||
|
TAILQ_ENTRY(p9pbuf) entries;
|
||||||
|
} p9pr;
|
||||||
|
|
||||||
|
/* in / out */
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t offset;
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
/* helpers for in */
|
||||||
|
uint32_t remain;
|
||||||
|
uint8_t type;
|
||||||
|
p9ptag_t tagid;
|
||||||
|
|
||||||
|
int state;
|
||||||
|
};
|
||||||
|
#define P9PBUF_PUT 0
|
||||||
|
#define P9PBUF_PUTDONE 1
|
||||||
|
#define P9PBUF_GETLEN 2
|
||||||
|
#define P9PBUF_GETDATA 3
|
||||||
|
#define P9PBUF_GETREADY 4
|
||||||
|
|
||||||
|
#define P9PB_CHECK(pb, space) if (pb->remain < (space)) return ENOMEM
|
||||||
|
|
||||||
|
struct puffs9p {
|
||||||
|
int servsock;
|
||||||
|
|
||||||
|
p9ptag_t nexttag;
|
||||||
|
p9pfid_t nextfid;
|
||||||
|
|
||||||
|
size_t maxreq; /* negotiated with server */
|
||||||
|
struct p9pbuf *curpb;
|
||||||
|
|
||||||
|
TAILQ_HEAD(, p9pbuf) outbufq;
|
||||||
|
TAILQ_HEAD(, p9pbuf) req_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dirfid {
|
||||||
|
p9pfid_t fid;
|
||||||
|
off_t seekoff;
|
||||||
|
LIST_ENTRY(dirfid) entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct p9pnode {
|
||||||
|
p9pfid_t fid_base;
|
||||||
|
p9pfid_t fid_open;
|
||||||
|
int opencount;
|
||||||
|
|
||||||
|
LIST_HEAD(,dirfid) dir_openlist;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct p9pbuf *p9pbuf_make(size_t, int);
|
||||||
|
void p9pbuf_destroy(struct p9pbuf *);
|
||||||
|
void p9pbuf_recycle(struct p9pbuf *, int);
|
||||||
|
|
||||||
|
int p9pbuf_read(struct puffs9p *, struct p9pbuf *);
|
||||||
|
int p9pbuf_write(struct puffs9p *, struct p9pbuf *);
|
||||||
|
|
||||||
|
void outbuf_enqueue(struct puffs9p *, struct p9pbuf *,
|
||||||
|
struct puffs_cc *, uint16_t);
|
||||||
|
void outbuf_enqueue_nocc(struct puffs9p *, struct p9pbuf *,
|
||||||
|
void (*f)(struct puffs9p *,
|
||||||
|
struct p9pbuf *, void *),
|
||||||
|
void *, uint16_t);
|
||||||
|
struct p9pbuf *req_get(struct puffs9p *, uint16_t);
|
||||||
|
|
||||||
|
|
||||||
|
int p9pbuf_put_1(struct p9pbuf *, uint8_t);
|
||||||
|
int p9pbuf_put_2(struct p9pbuf *, uint16_t);
|
||||||
|
int p9pbuf_put_4(struct p9pbuf *, uint32_t);
|
||||||
|
int p9pbuf_put_8(struct p9pbuf *, uint64_t);
|
||||||
|
int p9pbuf_put_str(struct p9pbuf *, const char *);
|
||||||
|
int p9pbuf_put_data(struct p9pbuf *, const void *, uint16_t);
|
||||||
|
int p9pbuf_write_data(struct p9pbuf *, uint8_t *, uint32_t);
|
||||||
|
|
||||||
|
int p9pbuf_get_1(struct p9pbuf *, uint8_t *);
|
||||||
|
int p9pbuf_get_2(struct p9pbuf *, uint16_t *);
|
||||||
|
int p9pbuf_get_4(struct p9pbuf *, uint32_t *);
|
||||||
|
int p9pbuf_get_8(struct p9pbuf *, uint64_t *);
|
||||||
|
int p9pbuf_get_str(struct p9pbuf *, char **, uint16_t *);
|
||||||
|
int p9pbuf_get_data(struct p9pbuf *, uint8_t **, uint16_t *);
|
||||||
|
int p9pbuf_read_data(struct p9pbuf *, uint8_t *, uint32_t);
|
||||||
|
|
||||||
|
int p9pbuf_remaining(struct p9pbuf *);
|
||||||
|
int p9pbuf_tell(struct p9pbuf *);
|
||||||
|
void p9pbuf_seekset(struct p9pbuf *, int);
|
||||||
|
|
||||||
|
int proto_getqid(struct p9pbuf *, struct qid9p *);
|
||||||
|
int proto_getstat(struct p9pbuf *, struct vattr *, char **, uint16_t *);
|
||||||
|
int proto_expect_walk_nqids(struct p9pbuf *, uint16_t *);
|
||||||
|
int proto_expect_stat(struct p9pbuf *, struct vattr *);
|
||||||
|
int proto_expect_qid(struct p9pbuf *, uint8_t, struct qid9p *);
|
||||||
|
|
||||||
|
int proto_cc_dupfid(struct puffs_cc *, p9pfid_t, p9pfid_t);
|
||||||
|
int proto_cc_clunkfid(struct puffs_cc *, p9pfid_t, int);
|
||||||
|
int proto_cc_open(struct puffs_cc *, p9pfid_t, p9pfid_t, int);
|
||||||
|
|
||||||
|
void proto_make_stat(struct p9pbuf *, const struct vattr *, const char *);
|
||||||
|
|
||||||
|
struct puffs_node *p9p_handshake(struct puffs_usermount *, const char *);
|
||||||
|
|
||||||
|
void qid2vattr(struct vattr *, const struct qid9p *);
|
||||||
|
struct puffs_node *newp9pnode_va(struct puffs_usermount *,
|
||||||
|
const struct vattr *, p9pfid_t);
|
||||||
|
struct puffs_node *newp9pnode_qid(struct puffs_usermount *,
|
||||||
|
const struct qid9p *, p9pfid_t);
|
||||||
|
|
||||||
|
int getdfwithoffset(struct puffs_cc *, struct p9pnode *, off_t,
|
||||||
|
struct dirfid **);
|
||||||
|
void storedf(struct p9pnode *, struct dirfid *);
|
||||||
|
void releasedf(struct puffs_cc *, struct dirfid *);
|
||||||
|
void nukealldf(struct puffs_cc *, struct p9pnode *);
|
||||||
|
|
||||||
|
#endif /* PUFFS9P_H_ */
|
|
@ -0,0 +1,558 @@
|
||||||
|
/* $NetBSD: node.c,v 1.1 2007/04/21 14:21:44 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: node.c,v 1.1 2007/04/21 14:21:44 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
#include "nineproto.h"
|
||||||
|
|
||||||
|
static void *
|
||||||
|
nodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
|
||||||
|
{
|
||||||
|
struct vattr *vap = &pn->pn_va;
|
||||||
|
struct qid9p *qid = arg;
|
||||||
|
|
||||||
|
if (vap->va_fileid == qid->qidpath)
|
||||||
|
return pn;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
|
||||||
|
enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
|
||||||
|
const struct puffs_cn *pcn)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
||||||
|
struct puffs_node *pn, *pn_dir = opc;
|
||||||
|
struct p9pnode *p9n_dir = pn_dir->pn_data;
|
||||||
|
p9ptag_t tfid = NEXTFID(p9p);
|
||||||
|
struct qid9p newqid;
|
||||||
|
uint16_t nqid;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WALK);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n_dir->fid_base);
|
||||||
|
p9pbuf_put_4(pb, tfid);
|
||||||
|
p9pbuf_put_2(pb, 1);
|
||||||
|
p9pbuf_put_str(pb, pcn->pcn_name);
|
||||||
|
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
rv = proto_expect_walk_nqids(pb, &nqid);
|
||||||
|
if (rv) {
|
||||||
|
rv = ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (nqid != 1 || !proto_getqid(pb, &newqid)) {
|
||||||
|
rv = EPROTO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn = puffs_pn_nodewalk(pu, nodecmp, &newqid);
|
||||||
|
if (pn == NULL)
|
||||||
|
pn = newp9pnode_qid(pu, &newqid, tfid);
|
||||||
|
else
|
||||||
|
proto_cc_clunkfid(pcc, tfid, 0);
|
||||||
|
|
||||||
|
*newnode = pn;
|
||||||
|
*newtype = pn->pn_va.va_type;
|
||||||
|
*newsize = pn->pn_va.va_size;
|
||||||
|
*newrdev = pn->pn_va.va_rdev;
|
||||||
|
|
||||||
|
out:
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Problem is that 9P doesn't allow seeking into a directory. So we
|
||||||
|
* maintain a list of active fids for any given directory. They
|
||||||
|
* start living at the first read and exist either until the directory
|
||||||
|
* is closed or until they reach the end.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
puffs9p_node_readdir(struct puffs_cc *pcc, void *opc, struct dirent *dent,
|
||||||
|
off_t *readoff, size_t *reslen, const struct puffs_cred *pcr,
|
||||||
|
int *eofflag, off_t *cookies, size_t *ncookies)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
struct vattr va;
|
||||||
|
struct dirfid *dfp;
|
||||||
|
char *name;
|
||||||
|
uint32_t count;
|
||||||
|
uint16_t statsize;
|
||||||
|
|
||||||
|
rv = getdfwithoffset(pcc, p9n, *readoff, &dfp);
|
||||||
|
if (rv)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
tag = NEXTTAG(p9p);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_READ);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, dfp->fid);
|
||||||
|
p9pbuf_put_8(pb, *readoff);
|
||||||
|
p9pbuf_put_4(pb, *reslen); /* XXX */
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
p9pbuf_get_4(pb, &count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if count is 0, assume we at end-of-dir. dfp is no longer
|
||||||
|
* useful, so nuke it
|
||||||
|
*/
|
||||||
|
if (count == 0) {
|
||||||
|
*eofflag = 1;
|
||||||
|
releasedf(pcc, dfp);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
if (!proto_getstat(pb, &va, &name, &statsize)) {
|
||||||
|
rv = EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
puffs_nextdent(&dent, name, va.va_fileid,
|
||||||
|
puffs_vtype2dt(va.va_type), reslen);
|
||||||
|
|
||||||
|
count -= statsize;
|
||||||
|
*readoff += statsize;
|
||||||
|
dfp->seekoff += statsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
storedf(p9n, dfp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *vap,
|
||||||
|
const struct puffs_cred *pcr, pid_t pid)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_STAT);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n->fid_base);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
rv = proto_expect_stat(pb, &pn->pn_va);
|
||||||
|
if (rv)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
memcpy(vap, &pn->pn_va, sizeof(struct vattr));
|
||||||
|
|
||||||
|
out:
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_setattr(struct puffs_cc *pcc, void *opc,
|
||||||
|
const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WSTAT);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n->fid_base);
|
||||||
|
proto_make_stat(pb, va, NULL);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_WSTAT)
|
||||||
|
rv = EPROTO;
|
||||||
|
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok, time to get clever. There are two possible cases: we are
|
||||||
|
* opening a file or we are opening a directory.
|
||||||
|
*
|
||||||
|
* If it's a directory, don't bother opening it here, but rather
|
||||||
|
* wait until readdir, since it's probable we need to be able to
|
||||||
|
* open a directory there in any case.
|
||||||
|
*
|
||||||
|
* If it's a regular file, open it with full permissions here.
|
||||||
|
* Let the upper layers of the kernel worry about permission
|
||||||
|
* control.
|
||||||
|
*
|
||||||
|
* XXX: this doesn't work too well due to us hitting the open file
|
||||||
|
* limit pretty soon
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
puffs9p_node_open(struct puffs_cc *pcc, void *opc, int mode,
|
||||||
|
const struct puffs_cred *pcr, pid_t pid)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
p9pfid_t nfid;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
p9n->opencount++;
|
||||||
|
if (pn->pn_va.va_type != VDIR && p9n->fid_open == P9P_INVALFID) {
|
||||||
|
nfid = NEXTFID(p9p);
|
||||||
|
error = proto_cc_open(pcc, p9n->fid_base, nfid,
|
||||||
|
P9PROTO_OMODE_RDWR);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
p9n->fid_open = nfid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_close(struct puffs_cc *pcc, void *opc, int flags,
|
||||||
|
const struct puffs_cred *pcr, pid_t pid)
|
||||||
|
{
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
|
||||||
|
if (--p9n->opencount == 0)
|
||||||
|
if (pn->pn_va.va_type == VDIR)
|
||||||
|
nukealldf(pcc, p9n);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
|
||||||
|
off_t offset, size_t *resid, const struct puffs_cred *pcr,
|
||||||
|
int ioflag)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
uint32_t count;
|
||||||
|
size_t nread;
|
||||||
|
|
||||||
|
nread = 0;
|
||||||
|
while (*resid > 0) {
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_READ);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n->fid_open);
|
||||||
|
p9pbuf_put_8(pb, offset+nread);
|
||||||
|
p9pbuf_put_4(pb, MIN((uint32_t)*resid,p9p->maxreq-24));
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_READ) {
|
||||||
|
rv = EPROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_get_4(pb, &count);
|
||||||
|
if (!p9pbuf_read_data(pb, buf + nread, count)) {
|
||||||
|
rv = EPROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*resid -= count;
|
||||||
|
nread += count;
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
|
||||||
|
off_t offset, size_t *resid, const struct puffs_cred *cred,
|
||||||
|
int ioflag)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn = opc;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
uint32_t chunk, count;
|
||||||
|
size_t nwrite;
|
||||||
|
|
||||||
|
if (ioflag & PUFFS_IO_APPEND)
|
||||||
|
offset = pn->pn_va.va_size;
|
||||||
|
|
||||||
|
nwrite = 0;
|
||||||
|
while (*resid > 0) {
|
||||||
|
chunk = MIN(*resid, p9p->maxreq-32);
|
||||||
|
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WRITE);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n->fid_open);
|
||||||
|
p9pbuf_put_8(pb, offset+nwrite);
|
||||||
|
p9pbuf_put_4(pb, chunk);
|
||||||
|
p9pbuf_write_data(pb, buf+nwrite, chunk);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_WRITE) {
|
||||||
|
rv = EPROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_get_4(pb, &count);
|
||||||
|
*resid -= count;
|
||||||
|
nwrite += count;
|
||||||
|
|
||||||
|
if (count != chunk) {
|
||||||
|
rv = EPROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nodecreate(struct puffs_cc *pcc, struct puffs_node *pn, void **newnode,
|
||||||
|
const char *name, const struct vattr *vap, uint32_t dirbit)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
||||||
|
struct puffs_node *pn_new;
|
||||||
|
struct p9pnode *p9n = pn->pn_data;
|
||||||
|
p9pfid_t nfid = NEXTFID(p9p);
|
||||||
|
struct qid9p nqid;
|
||||||
|
int tries = 0;
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (++tries > 5) {
|
||||||
|
rv = EPROTO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = proto_cc_dupfid(pcc, p9n->fid_base, nfid);
|
||||||
|
if (rv)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_CREATE);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, nfid);
|
||||||
|
p9pbuf_put_str(pb, name);
|
||||||
|
p9pbuf_put_4(pb, dirbit | (vap->va_mode & 0777));
|
||||||
|
p9pbuf_put_1(pb, 0);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
rv = proto_expect_qid(pb, P9PROTO_R_CREATE, &nqid);
|
||||||
|
if (rv)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now, little problem here: create returns an *open* fid.
|
||||||
|
* So, clunk it and walk the parent directory to get a fid
|
||||||
|
* which is not open for I/O yet.
|
||||||
|
*/
|
||||||
|
proto_cc_clunkfid(pcc, nfid, 0);
|
||||||
|
nfid = NEXTFID(p9p);
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WALK);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n->fid_base);
|
||||||
|
p9pbuf_put_4(pb, nfid);
|
||||||
|
p9pbuf_put_2(pb, 1);
|
||||||
|
p9pbuf_put_str(pb, name);
|
||||||
|
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* someone removed it already? try again
|
||||||
|
* note: this is kind of lose/lose
|
||||||
|
*/
|
||||||
|
if (pb->type != P9PROTO_R_WALK)
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
pn_new = newp9pnode_va(pu, vap, nfid);
|
||||||
|
qid2vattr(&pn_new->pn_va, &nqid);
|
||||||
|
*newnode = pn_new;
|
||||||
|
|
||||||
|
out:
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_create(struct puffs_cc *pcc, void *opc, void **newnode,
|
||||||
|
const struct puffs_cn *pcn, const struct vattr *va)
|
||||||
|
{
|
||||||
|
|
||||||
|
return nodecreate(pcc, opc, newnode, pcn->pcn_name, va, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
|
||||||
|
const struct puffs_cn *pcn, const struct vattr *va)
|
||||||
|
{
|
||||||
|
|
||||||
|
return nodecreate(pcc, opc, newnode, pcn->pcn_name,
|
||||||
|
va, P9PROTO_CPERM_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need to be a bit clever again: the fid is clunked no matter if
|
||||||
|
* the remove succeeds or not. Re-getting a fid would be way too
|
||||||
|
* difficult in case the remove failed for a valid reason (directory
|
||||||
|
* not empty etcetc.). So walk ourselves another fid to prod the
|
||||||
|
* ice with.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
noderemove(struct puffs_cc *pcc, struct p9pnode *p9n)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
p9pfid_t testfid = NEXTFID(p9p);
|
||||||
|
|
||||||
|
rv = proto_cc_dupfid(pcc, p9n->fid_base, testfid);
|
||||||
|
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_REMOVE);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, testfid);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_REMOVE) {
|
||||||
|
rv = EPROTO;
|
||||||
|
} else {
|
||||||
|
proto_cc_clunkfid(pcc, p9n->fid_base, 0);
|
||||||
|
p9n->fid_base = P9P_INVALFID;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
|
||||||
|
const struct puffs_cn *pcn)
|
||||||
|
{
|
||||||
|
struct puffs_node *pn = targ;
|
||||||
|
|
||||||
|
if (pn->pn_va.va_type == VDIR)
|
||||||
|
return EISDIR;
|
||||||
|
|
||||||
|
return noderemove(pcc, pn->pn_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
puffs9p_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
|
||||||
|
const struct puffs_cn *pcn)
|
||||||
|
{
|
||||||
|
struct puffs_node *pn = targ;
|
||||||
|
|
||||||
|
if (pn->pn_va.va_type != VDIR)
|
||||||
|
return ENOTDIR;
|
||||||
|
|
||||||
|
return noderemove(pcc, pn->pn_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 9P supports renames only for regular files within a directory
|
||||||
|
* from what I could tell. So just support in-directory renames
|
||||||
|
* for now.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
puffs9p_node_rename(struct puffs_cc *pcc, void *opc, void *src,
|
||||||
|
const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
|
||||||
|
const struct puffs_cn *pcn_targ)
|
||||||
|
{
|
||||||
|
AUTOVAR(pcc);
|
||||||
|
struct puffs_node *pn_src = src;
|
||||||
|
struct p9pnode *p9n_src = pn_src->pn_data;
|
||||||
|
|
||||||
|
if (opc != targ_dir) {
|
||||||
|
rv = EOPNOTSUPP;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 9P doesn't allow to overwrite in rename */
|
||||||
|
if (targ) {
|
||||||
|
struct puffs_node *pn_targ = targ;
|
||||||
|
|
||||||
|
rv = noderemove(pcc, pn_targ->pn_data);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_WSTAT);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, p9n_src->fid_base);
|
||||||
|
proto_make_stat(pb, NULL, pcn_targ->pcn_name);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_WSTAT)
|
||||||
|
rv = EPROTO;
|
||||||
|
|
||||||
|
out:
|
||||||
|
RETURN(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* - "here's one"
|
||||||
|
* - "9P"
|
||||||
|
* ~ "i'm not dead"
|
||||||
|
* - "you're not fooling anyone you know, you'll be stone dead in a minute
|
||||||
|
* - "he says he's not quite dead"
|
||||||
|
* - "isn't there anything you could do?"
|
||||||
|
* - *clunk*!
|
||||||
|
* - "thanks"
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
puffs9p_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (p9n->fid_open != P9P_INVALFID)
|
||||||
|
proto_cc_clunkfid(pcc, p9n->fid_open, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
/* $NetBSD: subr.c,v 1.1 2007/04/21 14:21:44 pooka Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#ifndef lint
|
||||||
|
__RCSID("$NetBSD: subr.c,v 1.1 2007/04/21 14:21:44 pooka Exp $");
|
||||||
|
#endif /* !lint */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
#include "ninepuffs.h"
|
||||||
|
#include "nineproto.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
qid2vattr(struct vattr *vap, const struct qid9p *qid)
|
||||||
|
{
|
||||||
|
|
||||||
|
vap->va_fileid = qid->qidpath;
|
||||||
|
vap->va_gen = qid->qidvers;
|
||||||
|
if (qid->qidtype & P9PROTO_QID_TYPE_DIR)
|
||||||
|
vap->va_type = VDIR;
|
||||||
|
else
|
||||||
|
vap->va_type = VREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct puffs_node *
|
||||||
|
makep9pnode(struct puffs_usermount *pu, p9pfid_t fid)
|
||||||
|
{
|
||||||
|
struct p9pnode *p9n;
|
||||||
|
struct puffs_node *pn;
|
||||||
|
|
||||||
|
p9n = emalloc(sizeof(struct p9pnode));
|
||||||
|
memset(p9n, 0, sizeof(struct p9pnode));
|
||||||
|
p9n->fid_base = fid;
|
||||||
|
LIST_INIT(&p9n->dir_openlist);
|
||||||
|
|
||||||
|
pn = puffs_pn_new(pu, p9n);
|
||||||
|
if (pn == NULL)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
return pn;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct puffs_node *
|
||||||
|
newp9pnode_va(struct puffs_usermount *pu, const struct vattr *va, p9pfid_t fid)
|
||||||
|
{
|
||||||
|
struct puffs_node *pn;
|
||||||
|
|
||||||
|
pn = makep9pnode(pu, fid);
|
||||||
|
pn->pn_va = *va;
|
||||||
|
|
||||||
|
return pn;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct puffs_node *
|
||||||
|
newp9pnode_qid(struct puffs_usermount *pu, const struct qid9p *qid,
|
||||||
|
p9pfid_t fid)
|
||||||
|
{
|
||||||
|
struct puffs_node *pn;
|
||||||
|
|
||||||
|
pn = makep9pnode(pu, fid);
|
||||||
|
puffs_vattr_null(&pn->pn_va);
|
||||||
|
qid2vattr(&pn->pn_va, qid);
|
||||||
|
|
||||||
|
return pn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* search list of fids, or if none is found, walk a fid for a new one
|
||||||
|
* and issue dummy readdirs until we get the result we want
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getdfwithoffset(struct puffs_cc *pcc, struct p9pnode *p9n, off_t wantoff,
|
||||||
|
struct dirfid **rfid)
|
||||||
|
{
|
||||||
|
struct puffs9p *p9p = puffs_cc_getspecific(pcc);
|
||||||
|
struct p9pbuf *pb;
|
||||||
|
struct dirfid *dfp = NULL;
|
||||||
|
p9ptag_t tag = NEXTTAG(p9p);
|
||||||
|
off_t curoff, advance;
|
||||||
|
uint32_t count;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
LIST_FOREACH(dfp, &p9n->dir_openlist, entries) {
|
||||||
|
if (dfp->seekoff == wantoff) {
|
||||||
|
LIST_REMOVE(dfp, entries);
|
||||||
|
*rfid = dfp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didn't get off easy? damn, do manual labour */
|
||||||
|
pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
|
||||||
|
dfp = ecalloc(1, sizeof(struct dirfid));
|
||||||
|
dfp->fid = NEXTFID(p9p);
|
||||||
|
error = proto_cc_open(pcc, p9n->fid_base, dfp->fid, P9PROTO_OMODE_READ);
|
||||||
|
if (error)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
for (curoff = 0;;) {
|
||||||
|
advance = wantoff - curoff;
|
||||||
|
|
||||||
|
tag = NEXTTAG(p9p);
|
||||||
|
p9pbuf_put_1(pb, P9PROTO_T_READ);
|
||||||
|
p9pbuf_put_2(pb, tag);
|
||||||
|
p9pbuf_put_4(pb, dfp->fid);
|
||||||
|
p9pbuf_put_8(pb, 0);
|
||||||
|
p9pbuf_put_4(pb, advance);
|
||||||
|
outbuf_enqueue(p9p, pb, pcc, tag);
|
||||||
|
puffs_cc_yield(pcc);
|
||||||
|
|
||||||
|
if (pb->type != P9PROTO_R_READ) {
|
||||||
|
error = EPROTO;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check how many bytes we got. If we got the amount we
|
||||||
|
* wanted, we are at the correct position. If we got
|
||||||
|
* zero bytes, either the directory doesn't "support" the
|
||||||
|
* seek offset we want (someone has probably inserted an
|
||||||
|
* entry meantime) or we at the end of directory. Either
|
||||||
|
* way, let the upper layer deal with it.
|
||||||
|
*/
|
||||||
|
p9pbuf_get_4(pb, &count);
|
||||||
|
curoff += count;
|
||||||
|
if (count == advance || count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p9pbuf_recycle(pb, P9PB_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
dfp->seekoff = curoff;
|
||||||
|
*rfid = dfp;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
p9pbuf_destroy(pb);
|
||||||
|
free(dfp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
releasedf(struct puffs_cc *pcc, struct dirfid *dfp)
|
||||||
|
{
|
||||||
|
|
||||||
|
proto_cc_clunkfid(pcc, dfp->fid, 0);
|
||||||
|
free(dfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
storedf(struct p9pnode *p9n, struct dirfid *dfp)
|
||||||
|
{
|
||||||
|
|
||||||
|
LIST_INSERT_HEAD(&p9n->dir_openlist, dfp, entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nukealldf(struct puffs_cc *pcc, struct p9pnode *p9n)
|
||||||
|
{
|
||||||
|
struct dirfid *dfp, *dfp_next;
|
||||||
|
|
||||||
|
for (dfp = LIST_FIRST(&p9n->dir_openlist); dfp; dfp = dfp_next) {
|
||||||
|
dfp_next = LIST_NEXT(dfp, entries);
|
||||||
|
LIST_REMOVE(dfp, entries);
|
||||||
|
releasedf(pcc, dfp);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue