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