linux/fs/nfsd/nfsxdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfsd/nfsxdr.c
   3 *
   4 * XDR support for nfsd
   5 *
   6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/time.h>
  11#include <linux/nfs.h>
  12#include <linux/vfs.h>
  13#include <linux/sunrpc/xdr.h>
  14#include <linux/sunrpc/svc.h>
  15#include <linux/nfsd/nfsd.h>
  16#include <linux/nfsd/xdr.h>
  17#include <linux/mm.h>
  18#include "auth.h"
  19
  20#define NFSDDBG_FACILITY                NFSDDBG_XDR
  21
  22/*
  23 * Mapping of S_IF* types to NFS file types
  24 */
  25static u32      nfs_ftypes[] = {
  26        NFNON,  NFCHR,  NFCHR, NFBAD,
  27        NFDIR,  NFBAD,  NFBLK, NFBAD,
  28        NFREG,  NFBAD,  NFLNK, NFBAD,
  29        NFSOCK, NFBAD,  NFLNK, NFBAD,
  30};
  31
  32
  33/*
  34 * XDR functions for basic NFS types
  35 */
  36static __be32 *
  37decode_fh(__be32 *p, struct svc_fh *fhp)
  38{
  39        fh_init(fhp, NFS_FHSIZE);
  40        memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
  41        fhp->fh_handle.fh_size = NFS_FHSIZE;
  42
  43        /* FIXME: Look up export pointer here and verify
  44         * Sun Secure RPC if requested */
  45        return p + (NFS_FHSIZE >> 2);
  46}
  47
  48/* Helper function for NFSv2 ACL code */
  49__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
  50{
  51        return decode_fh(p, fhp);
  52}
  53
  54static __be32 *
  55encode_fh(__be32 *p, struct svc_fh *fhp)
  56{
  57        memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
  58        return p + (NFS_FHSIZE>> 2);
  59}
  60
  61/*
  62 * Decode a file name and make sure that the path contains
  63 * no slashes or null bytes.
  64 */
  65static __be32 *
  66decode_filename(__be32 *p, char **namp, unsigned int *lenp)
  67{
  68        char            *name;
  69        unsigned int    i;
  70
  71        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
  72                for (i = 0, name = *namp; i < *lenp; i++, name++) {
  73                        if (*name == '\0' || *name == '/')
  74                                return NULL;
  75                }
  76        }
  77
  78        return p;
  79}
  80
  81static __be32 *
  82decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
  83{
  84        char            *name;
  85        unsigned int    i;
  86
  87        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
  88                for (i = 0, name = *namp; i < *lenp; i++, name++) {
  89                        if (*name == '\0')
  90                                return NULL;
  91                }
  92        }
  93
  94        return p;
  95}
  96
  97static __be32 *
  98decode_sattr(__be32 *p, struct iattr *iap)
  99{
 100        u32     tmp, tmp1;
 101
 102        iap->ia_valid = 0;
 103
 104        /* Sun client bug compatibility check: some sun clients seem to
 105         * put 0xffff in the mode field when they mean 0xffffffff.
 106         * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
 107         */
 108        if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) {
 109                iap->ia_valid |= ATTR_MODE;
 110                iap->ia_mode = tmp;
 111        }
 112        if ((tmp = ntohl(*p++)) != (u32)-1) {
 113                iap->ia_valid |= ATTR_UID;
 114                iap->ia_uid = tmp;
 115        }
 116        if ((tmp = ntohl(*p++)) != (u32)-1) {
 117                iap->ia_valid |= ATTR_GID;
 118                iap->ia_gid = tmp;
 119        }
 120        if ((tmp = ntohl(*p++)) != (u32)-1) {
 121                iap->ia_valid |= ATTR_SIZE;
 122                iap->ia_size = tmp;
 123        }
 124        tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
 125        if (tmp != (u32)-1 && tmp1 != (u32)-1) {
 126                iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 127                iap->ia_atime.tv_sec = tmp;
 128                iap->ia_atime.tv_nsec = tmp1 * 1000; 
 129        }
 130        tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
 131        if (tmp != (u32)-1 && tmp1 != (u32)-1) {
 132                iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 133                iap->ia_mtime.tv_sec = tmp;
 134                iap->ia_mtime.tv_nsec = tmp1 * 1000; 
 135                /*
 136                 * Passing the invalid value useconds=1000000 for mtime
 137                 * is a Sun convention for "set both mtime and atime to
 138                 * current server time".  It's needed to make permissions
 139                 * checks for the "touch" program across v2 mounts to
 140                 * Solaris and Irix boxes work correctly. See description of
 141                 * sattr in section 6.1 of "NFS Illustrated" by
 142                 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
 143                 */
 144                if (tmp1 == 1000000)
 145                        iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
 146        }
 147        return p;
 148}
 149
 150static __be32 *
 151encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 152             struct kstat *stat)
 153{
 154        struct dentry   *dentry = fhp->fh_dentry;
 155        int type;
 156        struct timespec time;
 157        u32 f;
 158
 159        type = (stat->mode & S_IFMT);
 160
 161        *p++ = htonl(nfs_ftypes[type >> 12]);
 162        *p++ = htonl((u32) stat->mode);
 163        *p++ = htonl((u32) stat->nlink);
 164        *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
 165        *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
 166
 167        if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
 168                *p++ = htonl(NFS_MAXPATHLEN);
 169        } else {
 170                *p++ = htonl((u32) stat->size);
 171        }
 172        *p++ = htonl((u32) stat->blksize);
 173        if (S_ISCHR(type) || S_ISBLK(type))
 174                *p++ = htonl(new_encode_dev(stat->rdev));
 175        else
 176                *p++ = htonl(0xffffffff);
 177        *p++ = htonl((u32) stat->blocks);
 178        switch (fsid_source(fhp)) {
 179        default:
 180        case FSIDSOURCE_DEV:
 181                *p++ = htonl(new_encode_dev(stat->dev));
 182                break;
 183        case FSIDSOURCE_FSID:
 184                *p++ = htonl((u32) fhp->fh_export->ex_fsid);
 185                break;
 186        case FSIDSOURCE_UUID:
 187                f = ((u32*)fhp->fh_export->ex_uuid)[0];
 188                f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
 189                f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
 190                f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
 191                *p++ = htonl(f);
 192                break;
 193        }
 194        *p++ = htonl((u32) stat->ino);
 195        *p++ = htonl((u32) stat->atime.tv_sec);
 196        *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
 197        lease_get_mtime(dentry->d_inode, &time); 
 198        *p++ = htonl((u32) time.tv_sec);
 199        *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); 
 200        *p++ = htonl((u32) stat->ctime.tv_sec);
 201        *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
 202
 203        return p;
 204}
 205
 206/* Helper function for NFSv2 ACL code */
 207__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 208{
 209        struct kstat stat;
 210        vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &stat);
 211        return encode_fattr(rqstp, p, fhp, &stat);
 212}
 213
 214/*
 215 * XDR decode functions
 216 */
 217int
 218nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 219{
 220        return xdr_argsize_check(rqstp, p);
 221}
 222
 223int
 224nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
 225{
 226        if (!(p = decode_fh(p, &args->fh)))
 227                return 0;
 228        return xdr_argsize_check(rqstp, p);
 229}
 230
 231int
 232nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 233                                        struct nfsd_sattrargs *args)
 234{
 235        p = decode_fh(p, &args->fh);
 236        if (!p)
 237                return 0;
 238        p = decode_sattr(p, &args->attrs);
 239
 240        return xdr_argsize_check(rqstp, p);
 241}
 242
 243int
 244nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
 245                                        struct nfsd_diropargs *args)
 246{
 247        if (!(p = decode_fh(p, &args->fh))
 248         || !(p = decode_filename(p, &args->name, &args->len)))
 249                return 0;
 250
 251         return xdr_argsize_check(rqstp, p);
 252}
 253
 254int
 255nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
 256                                        struct nfsd_readargs *args)
 257{
 258        unsigned int len;
 259        int v,pn;
 260        if (!(p = decode_fh(p, &args->fh)))
 261                return 0;
 262
 263        args->offset    = ntohl(*p++);
 264        len = args->count     = ntohl(*p++);
 265        p++; /* totalcount - unused */
 266
 267        if (len > NFSSVC_MAXBLKSIZE_V2)
 268                len = NFSSVC_MAXBLKSIZE_V2;
 269
 270        /* set up somewhere to store response.
 271         * We take pages, put them on reslist and include in iovec
 272         */
 273        v=0;
 274        while (len > 0) {
 275                pn = rqstp->rq_resused++;
 276                rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
 277                rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
 278                len -= rqstp->rq_vec[v].iov_len;
 279                v++;
 280        }
 281        args->vlen = v;
 282        return xdr_argsize_check(rqstp, p);
 283}
 284
 285int
 286nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 287                                        struct nfsd_writeargs *args)
 288{
 289        unsigned int len, hdr, dlen;
 290        int v;
 291
 292        if (!(p = decode_fh(p, &args->fh)))
 293                return 0;
 294
 295        p++;                            /* beginoffset */
 296        args->offset = ntohl(*p++);     /* offset */
 297        p++;                            /* totalcount */
 298        len = args->len = ntohl(*p++);
 299        /*
 300         * The protocol specifies a maximum of 8192 bytes.
 301         */
 302        if (len > NFSSVC_MAXBLKSIZE_V2)
 303                return 0;
 304
 305        /*
 306         * Check to make sure that we got the right number of
 307         * bytes.
 308         */
 309        hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
 310        dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
 311                - hdr;
 312
 313        /*
 314         * Round the length of the data which was specified up to
 315         * the next multiple of XDR units and then compare that
 316         * against the length which was actually received.
 317         * Note that when RPCSEC/GSS (for example) is used, the
 318         * data buffer can be padded so dlen might be larger
 319         * than required.  It must never be smaller.
 320         */
 321        if (dlen < XDR_QUADLEN(len)*4)
 322                return 0;
 323
 324        rqstp->rq_vec[0].iov_base = (void*)p;
 325        rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
 326        v = 0;
 327        while (len > rqstp->rq_vec[v].iov_len) {
 328                len -= rqstp->rq_vec[v].iov_len;
 329                v++;
 330                rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
 331                rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 332        }
 333        rqstp->rq_vec[v].iov_len = len;
 334        args->vlen = v + 1;
 335        return 1;
 336}
 337
 338int
 339nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 340                                        struct nfsd_createargs *args)
 341{
 342        if (   !(p = decode_fh(p, &args->fh))
 343            || !(p = decode_filename(p, &args->name, &args->len)))
 344                return 0;
 345        p = decode_sattr(p, &args->attrs);
 346
 347        return xdr_argsize_check(rqstp, p);
 348}
 349
 350int
 351nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
 352                                        struct nfsd_renameargs *args)
 353{
 354        if (!(p = decode_fh(p, &args->ffh))
 355         || !(p = decode_filename(p, &args->fname, &args->flen))
 356         || !(p = decode_fh(p, &args->tfh))
 357         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 358                return 0;
 359
 360        return xdr_argsize_check(rqstp, p);
 361}
 362
 363int
 364nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
 365{
 366        if (!(p = decode_fh(p, &args->fh)))
 367                return 0;
 368        args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 369
 370        return xdr_argsize_check(rqstp, p);
 371}
 372
 373int
 374nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
 375                                        struct nfsd_linkargs *args)
 376{
 377        if (!(p = decode_fh(p, &args->ffh))
 378         || !(p = decode_fh(p, &args->tfh))
 379         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 380                return 0;
 381
 382        return xdr_argsize_check(rqstp, p);
 383}
 384
 385int
 386nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 387                                        struct nfsd_symlinkargs *args)
 388{
 389        if (   !(p = decode_fh(p, &args->ffh))
 390            || !(p = decode_filename(p, &args->fname, &args->flen))
 391            || !(p = decode_pathname(p, &args->tname, &args->tlen)))
 392                return 0;
 393        p = decode_sattr(p, &args->attrs);
 394
 395        return xdr_argsize_check(rqstp, p);
 396}
 397
 398int
 399nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
 400                                        struct nfsd_readdirargs *args)
 401{
 402        if (!(p = decode_fh(p, &args->fh)))
 403                return 0;
 404        args->cookie = ntohl(*p++);
 405        args->count  = ntohl(*p++);
 406        if (args->count > PAGE_SIZE)
 407                args->count = PAGE_SIZE;
 408
 409        args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 410
 411        return xdr_argsize_check(rqstp, p);
 412}
 413
 414/*
 415 * XDR encode functions
 416 */
 417int
 418nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
 419{
 420        return xdr_ressize_check(rqstp, p);
 421}
 422
 423int
 424nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
 425                                        struct nfsd_attrstat *resp)
 426{
 427        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 428        return xdr_ressize_check(rqstp, p);
 429}
 430
 431int
 432nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
 433                                        struct nfsd_diropres *resp)
 434{
 435        p = encode_fh(p, &resp->fh);
 436        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 437        return xdr_ressize_check(rqstp, p);
 438}
 439
 440int
 441nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
 442                                        struct nfsd_readlinkres *resp)
 443{
 444        *p++ = htonl(resp->len);
 445        xdr_ressize_check(rqstp, p);
 446        rqstp->rq_res.page_len = resp->len;
 447        if (resp->len & 3) {
 448                /* need to pad the tail */
 449                rqstp->rq_res.tail[0].iov_base = p;
 450                *p = 0;
 451                rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
 452        }
 453        return 1;
 454}
 455
 456int
 457nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
 458                                        struct nfsd_readres *resp)
 459{
 460        p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
 461        *p++ = htonl(resp->count);
 462        xdr_ressize_check(rqstp, p);
 463
 464        /* now update rqstp->rq_res to reflect data aswell */
 465        rqstp->rq_res.page_len = resp->count;
 466        if (resp->count & 3) {
 467                /* need to pad the tail */
 468                rqstp->rq_res.tail[0].iov_base = p;
 469                *p = 0;
 470                rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
 471        }
 472        return 1;
 473}
 474
 475int
 476nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
 477                                        struct nfsd_readdirres *resp)
 478{
 479        xdr_ressize_check(rqstp, p);
 480        p = resp->buffer;
 481        *p++ = 0;                       /* no more entries */
 482        *p++ = htonl((resp->common.err == nfserr_eof));
 483        rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;
 484
 485        return 1;
 486}
 487
 488int
 489nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
 490                                        struct nfsd_statfsres *resp)
 491{
 492        struct kstatfs  *stat = &resp->stats;
 493
 494        *p++ = htonl(NFSSVC_MAXBLKSIZE_V2);     /* max transfer size */
 495        *p++ = htonl(stat->f_bsize);
 496        *p++ = htonl(stat->f_blocks);
 497        *p++ = htonl(stat->f_bfree);
 498        *p++ = htonl(stat->f_bavail);
 499        return xdr_ressize_check(rqstp, p);
 500}
 501
 502int
 503nfssvc_encode_entry(void *ccdv, const char *name,
 504                    int namlen, loff_t offset, u64 ino, unsigned int d_type)
 505{
 506        struct readdir_cd *ccd = ccdv;
 507        struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
 508        __be32  *p = cd->buffer;
 509        int     buflen, slen;
 510
 511        /*
 512        dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
 513                        namlen, name, offset, ino);
 514         */
 515
 516        if (offset > ~((u32) 0)) {
 517                cd->common.err = nfserr_fbig;
 518                return -EINVAL;
 519        }
 520        if (cd->offset)
 521                *cd->offset = htonl(offset);
 522        if (namlen > NFS2_MAXNAMLEN)
 523                namlen = NFS2_MAXNAMLEN;/* truncate filename */
 524
 525        slen = XDR_QUADLEN(namlen);
 526        if ((buflen = cd->buflen - slen - 4) < 0) {
 527                cd->common.err = nfserr_toosmall;
 528                return -EINVAL;
 529        }
 530        if (ino > ~((u32) 0)) {
 531                cd->common.err = nfserr_fbig;
 532                return -EINVAL;
 533        }
 534        *p++ = xdr_one;                         /* mark entry present */
 535        *p++ = htonl((u32) ino);                /* file id */
 536        p    = xdr_encode_array(p, name, namlen);/* name length & name */
 537        cd->offset = p;                 /* remember pointer */
 538        *p++ = htonl(~0U);              /* offset of next entry */
 539
 540        cd->buflen = buflen;
 541        cd->buffer = p;
 542        cd->common.err = nfs_ok;
 543        return 0;
 544}
 545
 546/*
 547 * XDR release functions
 548 */
 549int
 550nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
 551                                        struct nfsd_fhandle *resp)
 552{
 553        fh_put(&resp->fh);
 554        return 1;
 555}
 556