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