1
2
3
4
5
6
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
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
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
47
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
60
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
102
103
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
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
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++;
262 args->offset = ntohl(*p++);
263 p++;
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
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);
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
410
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;
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;
426 *p++ = htonl((u32) ino);
427 p = xdr_encode_array(p, name, namlen);
428 cd->offset = p;
429 *p++ = ~(u32) 0;
430
431 cd->buflen = buflen;
432 cd->buffer = p;
433 return 0;
434}
435
436
437
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