make oldconfig will rebuild these...
[linux-2.4.21-pre4.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/sched.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  */
28 static 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  */
39 static inline u32 *
40 decode_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
51 static inline u32 *
52 encode_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  */
62 static inline u32 *
63 decode_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
78 static inline u32 *
79 decode_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
94 static inline u32 *
95 decode_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
134 static inline u32 *
135 encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
136 {
137         struct inode *inode = fhp->fh_dentry->d_inode;
138         int type = (inode->i_mode & S_IFMT);
139
140         *p++ = htonl(nfs_ftypes[type >> 12]);
141         *p++ = htonl((u32) inode->i_mode);
142         *p++ = htonl((u32) inode->i_nlink);
143         *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
144         *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
145
146         if (S_ISLNK(type) && inode->i_size > NFS_MAXPATHLEN) {
147                 *p++ = htonl(NFS_MAXPATHLEN);
148         } else {
149                 *p++ = htonl((u32) inode->i_size);
150         }
151         *p++ = htonl((u32) inode->i_blksize);
152         if (S_ISCHR(type) || S_ISBLK(type))
153                 *p++ = htonl((u32) inode->i_rdev);
154         else
155                 *p++ = htonl(0xffffffff);
156         *p++ = htonl((u32) inode->i_blocks);
157         if (rqstp->rq_reffh->fh_version == 1 
158             && rqstp->rq_reffh->fh_fsid_type == 1
159             && (fhp->fh_export->ex_flags & NFSEXP_FSID))
160                 *p++ = htonl((u32) fhp->fh_export->ex_fsid);
161         else
162                 *p++ = htonl((u32) inode->i_dev);
163         *p++ = htonl((u32) inode->i_ino);
164         *p++ = htonl((u32) inode->i_atime);
165         *p++ = 0;
166         *p++ = htonl((u32) lease_get_mtime(inode));
167         *p++ = 0;
168         *p++ = htonl((u32) inode->i_ctime);
169         *p++ = 0;
170
171         return p;
172 }
173
174 /*
175  * Check buffer bounds after decoding arguments
176  */
177 static inline int
178 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
179 {
180         struct svc_buf  *buf = &rqstp->rq_argbuf;
181
182         return p - buf->base <= buf->buflen;
183 }
184
185 static inline int
186 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
187 {
188         struct svc_buf  *buf = &rqstp->rq_resbuf;
189
190         buf->len = p - buf->base;
191         dprintk("nfsd: ressize_check p %p base %p len %d\n",
192                         p, buf->base, buf->buflen);
193         return (buf->len <= buf->buflen);
194 }
195
196 /*
197  * XDR decode functions
198  */
199 int
200 nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
201 {
202         return xdr_argsize_check(rqstp, p);
203 }
204
205 int
206 nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
207 {
208         if (!(p = decode_fh(p, fhp)))
209                 return 0;
210         return xdr_argsize_check(rqstp, p);
211 }
212
213 int
214 nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
215                                         struct nfsd_sattrargs *args)
216 {
217         if (!(p = decode_fh(p, &args->fh))
218          || !(p = decode_sattr(p, &args->attrs)))
219                 return 0;
220
221         return xdr_argsize_check(rqstp, p);
222 }
223
224 int
225 nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
226                                         struct nfsd_diropargs *args)
227 {
228         if (!(p = decode_fh(p, &args->fh))
229          || !(p = decode_filename(p, &args->name, &args->len)))
230                 return 0;
231
232          return xdr_argsize_check(rqstp, p);
233 }
234
235 int
236 nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
237                                         struct nfsd_readargs *args)
238 {
239         if (!(p = decode_fh(p, &args->fh)))
240                 return 0;
241
242         args->offset    = ntohl(*p++);
243         args->count     = ntohl(*p++);
244         args->totalsize = ntohl(*p++);
245
246         return xdr_argsize_check(rqstp, p);
247 }
248
249 int
250 nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
251                                         struct nfsd_writeargs *args)
252 {
253         if (!(p = decode_fh(p, &args->fh)))
254                 return 0;
255
256         p++;                            /* beginoffset */
257         args->offset = ntohl(*p++);     /* offset */
258         p++;                            /* totalcount */
259         args->len = ntohl(*p++);
260         args->data = (char *) p;
261         p += XDR_QUADLEN(args->len);
262
263         return xdr_argsize_check(rqstp, p);
264 }
265
266 int
267 nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
268                                         struct nfsd_createargs *args)
269 {
270         if (!(p = decode_fh(p, &args->fh))
271          || !(p = decode_filename(p, &args->name, &args->len))
272          || !(p = decode_sattr(p, &args->attrs)))
273                 return 0;
274
275         return xdr_argsize_check(rqstp, p);
276 }
277
278 int
279 nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
280                                         struct nfsd_renameargs *args)
281 {
282         if (!(p = decode_fh(p, &args->ffh))
283          || !(p = decode_filename(p, &args->fname, &args->flen))
284          || !(p = decode_fh(p, &args->tfh))
285          || !(p = decode_filename(p, &args->tname, &args->tlen)))
286                 return 0;
287
288         return xdr_argsize_check(rqstp, p);
289 }
290
291 int
292 nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
293                                         struct nfsd_linkargs *args)
294 {
295         if (!(p = decode_fh(p, &args->ffh))
296          || !(p = decode_fh(p, &args->tfh))
297          || !(p = decode_filename(p, &args->tname, &args->tlen)))
298                 return 0;
299
300         return xdr_argsize_check(rqstp, p);
301 }
302
303 int
304 nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
305                                         struct nfsd_symlinkargs *args)
306 {
307         if (!(p = decode_fh(p, &args->ffh))
308          || !(p = decode_filename(p, &args->fname, &args->flen))
309          || !(p = decode_pathname(p, &args->tname, &args->tlen))
310          || !(p = decode_sattr(p, &args->attrs)))
311                 return 0;
312
313         return xdr_argsize_check(rqstp, p);
314 }
315
316 int
317 nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
318                                         struct nfsd_readdirargs *args)
319 {
320         if (!(p = decode_fh(p, &args->fh)))
321                 return 0;
322         args->cookie = ntohl(*p++);
323         args->count  = ntohl(*p++);
324
325         return xdr_argsize_check(rqstp, p);
326 }
327
328 /*
329  * XDR encode functions
330  */
331 int
332 nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
333 {
334         return xdr_ressize_check(rqstp, p);
335 }
336
337 int
338 nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
339                                         struct nfsd_attrstat *resp)
340 {
341         p = encode_fattr(rqstp, p, &resp->fh);
342         return xdr_ressize_check(rqstp, p);
343 }
344
345 int
346 nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
347                                         struct nfsd_diropres *resp)
348 {
349         p = encode_fh(p, &resp->fh);
350         p = encode_fattr(rqstp, p, &resp->fh);
351         return xdr_ressize_check(rqstp, p);
352 }
353
354 int
355 nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
356                                         struct nfsd_readlinkres *resp)
357 {
358         *p++ = htonl(resp->len);
359         p += XDR_QUADLEN(resp->len);
360         return xdr_ressize_check(rqstp, p);
361 }
362
363 int
364 nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
365                                         struct nfsd_readres *resp)
366 {
367         p = encode_fattr(rqstp, p, &resp->fh);
368         *p++ = htonl(resp->count);
369         p += XDR_QUADLEN(resp->count);
370
371         return xdr_ressize_check(rqstp, p);
372 }
373
374 int
375 nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
376                                         struct nfsd_readdirres *resp)
377 {
378         p += XDR_QUADLEN(resp->count);
379         return xdr_ressize_check(rqstp, p);
380 }
381
382 int
383 nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
384                                         struct nfsd_statfsres *resp)
385 {
386         struct statfs   *stat = &resp->stats;
387
388         *p++ = htonl(NFSSVC_MAXBLKSIZE);        /* max transfer size */
389         *p++ = htonl(stat->f_bsize);
390         *p++ = htonl(stat->f_blocks);
391         *p++ = htonl(stat->f_bfree);
392         *p++ = htonl(stat->f_bavail);
393         return xdr_ressize_check(rqstp, p);
394 }
395
396 int
397 nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
398                     int namlen, loff_t offset, ino_t ino, unsigned int d_type)
399 {
400         u32     *p = cd->buffer;
401         int     buflen, slen;
402
403         /*
404         dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
405                         namlen, name, offset, ino);
406          */
407
408         if (offset > ~((u32) 0))
409                 return -EINVAL;
410         if (cd->offset)
411                 *cd->offset = htonl(offset);
412         if (namlen > NFS2_MAXNAMLEN)
413                 namlen = NFS2_MAXNAMLEN;/* truncate filename */
414
415         slen = XDR_QUADLEN(namlen);
416         if ((buflen = cd->buflen - slen - 4) < 0) {
417                 cd->eob = 1;
418                 return -EINVAL;
419         }
420         *p++ = xdr_one;                         /* mark entry present */
421         *p++ = htonl((u32) ino);                /* file id */
422         p    = xdr_encode_array(p, name, namlen);/* name length & name */
423         cd->offset = p;                 /* remember pointer */
424         *p++ = ~(u32) 0;                /* offset of next entry */
425
426         cd->buflen = buflen;
427         cd->buffer = p;
428         return 0;
429 }
430
431 /*
432  * XDR release functions
433  */
434 int
435 nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
436                                         struct nfsd_fhandle *resp)
437 {
438         fh_put(&resp->fh);
439         return 1;
440 }