/*
* Process version 3 NFS requests.
*
* Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/magic.h>
#include "cache.h"
#include "xdr3.h"
#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PROC
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
static int nfs3_ftypes[] = {
0, /* NF3NON */
S_IFREG, /* NF3REG */
S_IFDIR, /* NF3DIR */
S_IFBLK, /* NF3BLK */
S_IFCHR, /* NF3CHR */
S_IFLNK, /* NF3LNK */
S_IFSOCK, /* NF3SOCK */
S_IFIFO, /* NF3FIFO */
};
/*
* NULL call.
*/
static __be32
nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
}
/*
* Get a file's attributes
*/
static __be32
nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd3_attrstat *resp)
{
__be32 nfserr;
dprintk("nfsd: GETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0,
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
if (nfserr)
RETURN_STATUS(nfserr);
nfserr = fh_getattr(&resp->fh, &resp->stat);
RETURN_STATUS(nfserr);
}
/*
* Set a file's attributes
*/
static __be32
nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
struct nfsd3_attrstat *resp)
{
__be32 nfserr;
dprintk("nfsd: SETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
argp->check_guard, argp->guardtime);
RETURN_STATUS(nfserr);
}
/*
* Look up a path name component
*/
static __be32
nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
struct nfsd3_diropres *resp)
{
__be32 nfserr;
dprintk("nfsd: LOOKUP(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
argp->len,
argp->name);
fh_copy(&resp->dirfh, &argp->fh);
fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_lookup(rqstp, &resp->dirfh,
argp->name,
argp->len,
&resp->fh);
RETURN_STATUS(nfserr);
}
/*
* Check file access
*/
static __be32
nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
struct nfsd3_accessres *resp)
{
__be32 nfserr;
dprintk("nfsd: ACCESS(3) %s 0x%x\n",
SVCFH_fmt(&argp->fh),
argp->access);
fh_copy(&resp->fh, &argp->fh);
resp->access = argp->access;
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
RETURN_STATUS(nfserr);
}
/*
* Read a symlink.
*/
static __be32
nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
struct nfsd3_readlinkres *resp)
{
__be32 nfserr;
dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
/* Read the symlink. */
fh_copy(&resp->fh, &argp->fh);
resp->len = NFS3_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
RETURN_STATUS(nfserr);
}
/*
* Read a portion of a file.
*/
static __be32
nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
struct nfsd3_readres *resp)
{
__be32 nfserr;
u32 max_blocksize = svc_max_payload(rqstp);
unsigned long cnt = min(argp->count, max_blocksize);
dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
SVCFH_fmt(&argp->fh),
(unsigned long) argp->count,
(unsigned long long) argp->offset);
/* Obtain buffer pointer for payload.
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
* + 1 (xdr opaque byte count) = 26
*/
resp->count = cnt;
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_read(rqstp, &resp->fh,
argp->offset,
rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr == 0) {
struct inode *inode = d_inode(resp->fh.fh_dentry);
resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
inode->i_size);
}
RETURN_STATUS(nfserr);
}
/*
* Write data to a file
*/
static __be32
nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp