linux-bk/fs/nfsd/nfsxdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfsd/xdr.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
  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
  18#define NFSDDBG_FACILITY                NFSDDBG_XDR
  19
  20
  21#ifdef NFSD_OPTIMIZE_SPACE
  22# define inline
  23#endif
  24
  25/*
  26 * Mapping of S_IF* types to NFS file types
  27 */
  28static u32      nfs_ftypes[] = {
  29        NFNON,  NFCHR,  NFCHR, NFBAD,
  30        NFDIR,  NFBAD,  NFBLK, NFBAD,
  31        NFREG,  NFBAD,  NFLNK, NFBAD,
  32        NFSOCK, NFBAD,  NFLNK, NFBAD,
  33};
  34
  35
  36/*
  37 * XDR functions for basic NFS types
  38 */
  39static inline u32 *
  40decode_fh(u32 *p, struct svc_fh *fhp)
  41{
  42        fh_init(fhp, NFS_FHSIZE);
  43        memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
  44        fhp->fh_handle.fh_size = NFS_FHSIZE;
  45
  46        /* FIXME: Look up export pointer here and verify
  47         * Sun Secure RPC if requested */
  48        return p + (NFS_FHSIZE >> 2);
  49}
  50
  51static inline u32 *
  52encode_fh(u32 *p, struct svc_fh *fhp)
  53{
  54        memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
  55        return p + (NFS_FHSIZE>> 2);
  56}
  57
  58/*
  59 * Decode a file name and make sure that the path contains
  60 * no slashes or null bytes.
  61 */
  62static inline u32 *
  63decode_filename(u32 *p, char **namp, int *lenp)
  64{
  65        char            *name;
  66        int             i;
  67
  68        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
  69                for (i = 0, name = *namp; i < *lenp; i++, name++) {
  70                        if (*name == '\0' || *name == '/')
  71                                return NULL;
  72                }
  73        }
  74
  75        return p;
  76}
  77
  78static inline u32 *
  79decode_pathname(u32 *p, char **namp, int *lenp)
  80{
  81        char            *name;
  82        int             i;
  83
  84        if ((p = xdr_decode_string(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
  85                for (i = 0, name = *namp; i < *lenp; i++, name++) {
  86                        if (*name == '\0')
  87                                return NULL;
  88                }
  89        }
  90
  91        return p;
  92}
  93
  94static inline u32 *
  95decode_sattr(u32 *p, struct iattr *iap)
  96{
  97        u32     tmp, tmp1;
  98
  99        iap->ia_valid = 0;
 100
 101        /* Sun client bug compatibility check: some sun clients seem to
 102         * put 0xffff in the mode field when they mean 0xffffffff.
 103         * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
 104         */
 105        if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) {
 106                iap->ia_valid |= ATTR_MODE;
 107                iap->ia_mode = tmp;
 108        }
 109        if ((tmp = ntohl(*p++)) != (u32)-1) {
 110                iap->ia_valid |= ATTR_UID;
 111                iap->ia_uid = tmp;
 112        }
 113        if ((tmp = ntohl(*p++)) != (u32)-1) {
 114                iap->ia_valid |= ATTR_GID;
 115                iap->ia_gid = tmp;
 116        }
 117        if ((tmp = ntohl(*p++)) != (u32)-1) {
 118                iap->ia_valid |= ATTR_SIZE;
 119                iap->ia_size = tmp;
 120        }
 121        tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
 122        if (tmp != (u32)-1 && tmp1 != (u32)-1) {
 123                iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 124                iap->ia_atime = tmp;
 125        }
 126        tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
 127        if (tmp != (u32)-1 && tmp1 != (u32)-1) {
 128                iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 129                iap->ia_mtime = tmp;
 130        }
 131        return p;
 132}
 133
 134static inline u32 *
 135encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 136{
 137        struct vfsmount *mnt = fhp->fh_export->ex_mnt;
 138        struct dentry   *dentry = fhp->fh_dentry;
 139        struct kstat stat;
 140        int type;
 141
 142        vfs_getattr(mnt, dentry, &stat);
 143        type = (stat.mode & S_IFMT);
 144
 145        *p++ = htonl(nfs_ftypes[type >> 12]);
 146        *p++ = htonl((u32) stat.mode);
 147        *p++ = htonl((u32) stat.nlink);
 148        *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
 149        *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
 150
 151        if (S_ISLNK(type) && stat.size > NFS_MAXPATHLEN) {
 152                *p++ = htonl(NFS_MAXPATHLEN);
 153        } else {
 154                *p++ = htonl((u32) stat.size);
 155        }
 156        *p++ = htonl((u32) stat.blksize);
 157        if (S_ISCHR(type) || S_ISBLK(type))
 158                *p++ = htonl((u32) stat.rdev);
 159        else
 160                *p++ = htonl(0xffffffff);
 161        *p++ = htonl((u32) stat.blocks);
 162        if (rqstp->rq_reffh->fh_version == 1 
 163            && rqstp->rq_reffh->fh_fsid_type == 1
 164            && (fhp->fh_export->ex_flags & NFSEXP_FSID))
 165                *p++ = htonl((u32) fhp->fh_export->ex_fsid);
 166        else
 167                *p++ = htonl((u32) stat.dev);
 168        *p++ = htonl((u32) stat.ino);
 169        *p++ = htonl((u32) stat.atime);
 170        *p++ = 0;
 171        *p++ = htonl((u32) lease_get_mtime(dentry->d_inode));
 172        *p++ = 0;
 173        *p++ = htonl((u32) stat.ctime);
 174        *p++ = 0;
 175
 176        return p;
 177}
 178
 179/*
 180 * Check buffer bounds after decoding arguments
 181 */
 182static inline int
 183xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
 184{
 185        struct svc_buf  *buf = &rqstp->rq_argbuf;
 186
 187        return p - buf->base <= buf->buflen;
 188}
 189
 190static inline int
 191xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
 192{
 193        struct svc_buf  *buf = &rqstp->rq_resbuf;
 194
 195        buf->len = p - buf->base;
 196        dprintk("nfsd: ressize_check p %p base %p len %d\n",
 197                        p, buf->base, buf->buflen);
 198        return (buf->len <= buf->buflen);
 199}
 200
 201/*
 202 * XDR decode functions
 203 */
 204int
 205nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
 206{
 207        return xdr_argsize_check(rqstp, p);
 208}
 209
 210int
 211nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 212{
 213        if (!(p = decode_fh(p, fhp)))
 214                return 0;
 215        return xdr_argsize_check(rqstp, p);
 216}
 217
 218int
 219nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
 220                                        struct nfsd_sattrargs *args)
 221{
 222        if (!(p = decode_fh(p, &args->fh))
 223         || !(p = decode_sattr(p, &args->attrs)))
 224                return 0;
 225
 226        return xdr_argsize_check(rqstp, p);
 227}
 228
 229int
 230nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
 231                                        struct nfsd_diropargs *args)
 232{
 233        if (!(p = decode_fh(p, &args->fh))
 234         || !(p = decode_filename(p, &args->name, &args->len)))
 235                return 0;
 236
 237         return xdr_argsize_check(rqstp, p);
 238}
 239
 240int
 241nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
 242                                        struct nfsd_readargs *args)
 243{
 244        if (!(p = decode_fh(p, &args->fh)))
 245                return 0;
 246
 247        args->offset    = ntohl(*p++);
 248        args->count     = ntohl(*p++);
 249        args->totalsize = ntohl(*p++);
 250
 251        return xdr_argsize_check(rqstp, p);
 252}
 253
 254int
 255nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
 256                                        struct nfsd_writeargs *args)
 257{
 258        if (!(p = decode_fh(p, &args->fh)))
 259                return 0;
 260
 261        p++;                            /* beginoffset */
 262        args->offset = ntohl(*p++);     /* offset */
 263        p++;                            /* totalcount */
 264        args->len = ntohl(*p++);
 265        args->data = (char *) p;
 266        p += XDR_QUADLEN(args->len);
 267
 268        return xdr_argsize_check(rqstp, p);
 269}
 270
 271int
 272nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
 273                                        struct nfsd_createargs *args)
 274{
 275        if (!(p = decode_fh(p, &args->fh))
 276         || !(p = decode_filename(p, &args->name, &args->len))
 277         || !(p = decode_sattr(p, &args->attrs)))
 278                return 0;
 279
 280        return xdr_argsize_check(rqstp, p);
 281}
 282
 283int
 284nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
 285                                        struct nfsd_renameargs *args)
 286{
 287        if (!(p = decode_fh(p, &args->ffh))
 288         || !(p = decode_filename(p, &args->fname, &args->flen))
 289         || !(p = decode_fh(p, &args->tfh))
 290         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 291                return 0;
 292
 293        return xdr_argsize_check(rqstp, p);
 294}
 295
 296int
 297nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
 298                                        struct nfsd_linkargs *args)
 299{
 300        if (!(p = decode_fh(p, &args->ffh))
 301         || !(p = decode_fh(p, &args->tfh))
 302         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 303                return 0;
 304
 305        return xdr_argsize_check(rqstp, p);
 306}
 307
 308int
 309nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
 310                                        struct nfsd_symlinkargs *args)
 311{
 312        if (!(p = decode_fh(p, &args->ffh))
 313         || !(p = decode_filename(p, &args->fname, &args->flen))
 314         || !(p = decode_pathname(p, &args->tname, &args->tlen))
 315         || !(p = decode_sattr(p, &args->attrs)))
 316                return 0;
 317
 318        return xdr_argsize_check(rqstp, p);
 319}
 320
 321int
 322nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
 323                                        struct nfsd_readdirargs *args)
 324{
 325        if (!(p = decode_fh(p, &args->fh)))
 326                return 0;
 327        args->cookie = ntohl(*p++);
 328        args->count  = ntohl(*p++);
 329
 330        return xdr_argsize_check(rqstp, p);
 331}
 332
 333/*
 334 * XDR encode functions
 335 */
 336int
 337nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
 338{
 339        return xdr_ressize_check(rqstp, p);
 340}
 341
 342int
 343nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
 344                                        struct nfsd_attrstat *resp)
 345{
 346        p = encode_fattr(rqstp, p, &resp->fh);
 347        return xdr_ressize_check(rqstp, p);
 348}
 349
 350int
 351nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
 352                                        struct nfsd_diropres *resp)
 353{
 354        p = encode_fh(p, &resp->fh);
 355        p = encode_fattr(rqstp, p, &resp->fh);
 356        return xdr_ressize_check(rqstp, p);
 357}
 358
 359int
 360nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
 361                                        struct nfsd_readlinkres *resp)
 362{
 363        *p++ = htonl(resp->len);
 364        p += XDR_QUADLEN(resp->len);
 365        return xdr_ressize_check(rqstp, p);
 366}
 367
 368int
 369nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 370                                        struct nfsd_readres *resp)
 371{
 372        p = encode_fattr(rqstp, p, &resp->fh);
 373        *p++ = htonl(resp->count);
 374        p += XDR_QUADLEN(resp->count);
 375
 376        return xdr_ressize_check(rqstp, p);
 377}
 378
 379int
 380nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 381                                        struct nfsd_readdirres *resp)
 382{
 383        p += XDR_QUADLEN(resp->count);
 384        return xdr_ressize_check(rqstp, p);
 385}
 386
 387int
 388nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
 389                                        struct nfsd_statfsres *resp)
 390{
 391        struct statfs   *stat = &resp->stats;
 392
 393        *p++ = htonl(NFSSVC_MAXBLKSIZE);        /* max transfer size */
 394        *p++ = htonl(stat->f_bsize);
 395        *p++ = htonl(stat->f_blocks);
 396        *p++ = htonl(stat->f_bfree);
 397        *p++ = htonl(stat->f_bavail);
 398        return xdr_ressize_check(rqstp, p);
 399}
 400
 401int
 402nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
 403                    int namlen, loff_t offset, ino_t ino, unsigned int d_type)
 404{
 405        u32     *p = cd->buffer;
 406        int     buflen, slen;
 407
 408        /*
 409        dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
 410                        namlen, name, offset, ino);
 411         */
 412
 413        if (offset > ~((u32) 0))
 414                return -EINVAL;
 415        if (cd->offset)
 416                *cd->offset = htonl(offset);
 417        if (namlen > NFS2_MAXNAMLEN)
 418                namlen = NFS2_MAXNAMLEN;/* truncate filename */
 419
 420        slen = XDR_QUADLEN(namlen);
 421        if ((buflen = cd->buflen - slen - 4) < 0) {
 422                cd->eob = 1;
 423                return -EINVAL;
 424        }
 425        *p++ = xdr_one;                         /* mark entry present */
 426        *p++ = htonl((u32) ino);                /* file id */
 427        p    = xdr_encode_array(p, name, namlen);/* name length & name */
 428        cd->offset = p;                 /* remember pointer */
 429        *p++ = ~(u32) 0;                /* offset of next entry */
 430
 431        cd->buflen = buflen;
 432        cd->buffer = p;
 433        return 0;
 434}
 435
 436/*
 437 * XDR release functions
 438 */
 439int
 440nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
 441                                        struct nfsd_fhandle *resp)
 442{
 443        fh_put(&resp->fh);
 444        return 1;
 445}
 446
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.