/*
* XDR support for nfsd/protocol version 3.
*
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*
* 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
*/
#include <linux/namei.h>
#include <linux/sunrpc/svc_xprt.h>
#include "xdr3.h"
#include "auth.h"
#include "netns.h"
#include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_XDR
/*
* Mapping of S_IF* types to NFS file types
*/
static u32 nfs3_ftypes[] = {
NF3NON, NF3FIFO, NF3CHR, NF3BAD,
NF3DIR, NF3BAD, NF3BLK, NF3BAD,
NF3REG, NF3BAD, NF3LNK, NF3BAD,
NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
};
/*
* XDR functions for basic NFS types
*/
static __be32 *
encode_time3(__be32 *p, struct timespec *time)
{
*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
return p;
}
static __be32 *
decode_time3(__be32 *p, struct timespec *time)
{
time->tv_sec = ntohl(*p++);
time->tv_nsec = ntohl(*p++);
return p;
}
static __be32 *
decode_fh(__be32 *p, struct svc_fh *fhp)
{
unsigned int size;
fh_init(fhp, NFS3_FHSIZE);
size = ntohl(*p++);
if (size > NFS3_FHSIZE)
return NULL;
memcpy(&fhp->fh_handle.fh_base, p, size);
fhp->fh_handle.fh_size = size;
return p + XDR_QUADLEN(size);
}
/* Helper function for NFSv3 ACL code */
__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
{
return decode_fh(p, fhp);
}
static __be32 *
encode_fh(__be32 *p, struct svc_fh *fhp)
{
unsigned int size = fhp->fh_handle.fh_size;
*p++ = htonl(size);
if (size) p[XDR_QUADLEN(size)-1]=0;
memcpy(p, &fhp->fh_handle.fh_base, size);
return p + XDR_QUADLEN(size);
}
/*
* Decode a file name and make sure that the path contains
* no slashes or null bytes.
*/
static __be32 *
decode_filename(__be32 *p, char **namp, unsigned int *lenp)
{
char *name;
unsigned int i;
if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
for (i = 0, name = *namp; i < *lenp; i++, name++) {
if (*name == '\0' || *name == '/')
return NULL;
}
}
return p;
}
static __be32 *
decode_sattr3(__be32 *p, struct iattr *iap)
{
u32 tmp;
iap->ia_valid = 0;
if (*p++) {
iap->ia_valid |= ATTR_MODE;
iap->ia_mode = ntohl(*p++);
}
if (*p++) {
iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++));
if