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