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