2 * linux/fs/nfsd/nfsxdr.c
6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
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>
19 #define NFSDDBG_FACILITY NFSDDBG_XDR
22 * Mapping of S_IF* types to NFS file types
24 static u32 nfs_ftypes
[] = {
25 NFNON
, NFCHR
, NFCHR
, NFBAD
,
26 NFDIR
, NFBAD
, NFBLK
, NFBAD
,
27 NFREG
, NFBAD
, NFLNK
, NFBAD
,
28 NFSOCK
, NFBAD
, NFLNK
, NFBAD
,
33 * XDR functions for basic NFS types
36 decode_fh(__be32
*p
, struct svc_fh
*fhp
)
38 fh_init(fhp
, NFS_FHSIZE
);
39 memcpy(&fhp
->fh_handle
.fh_base
, p
, NFS_FHSIZE
);
40 fhp
->fh_handle
.fh_size
= NFS_FHSIZE
;
42 /* FIXME: Look up export pointer here and verify
43 * Sun Secure RPC if requested */
44 return p
+ (NFS_FHSIZE
>> 2);
47 /* Helper function for NFSv2 ACL code */
48 __be32
*nfs2svc_decode_fh(__be32
*p
, struct svc_fh
*fhp
)
50 return decode_fh(p
, fhp
);
54 encode_fh(__be32
*p
, struct svc_fh
*fhp
)
56 memcpy(p
, &fhp
->fh_handle
.fh_base
, NFS_FHSIZE
);
57 return p
+ (NFS_FHSIZE
>> 2);
61 * Decode a file name and make sure that the path contains
62 * no slashes or null bytes.
65 decode_filename(__be32
*p
, char **namp
, int *lenp
)
70 if ((p
= xdr_decode_string_inplace(p
, namp
, lenp
, NFS_MAXNAMLEN
)) != NULL
) {
71 for (i
= 0, name
= *namp
; i
< *lenp
; i
++, name
++) {
72 if (*name
== '\0' || *name
== '/')
81 decode_pathname(__be32
*p
, char **namp
, int *lenp
)
86 if ((p
= xdr_decode_string_inplace(p
, namp
, lenp
, NFS_MAXPATHLEN
)) != NULL
) {
87 for (i
= 0, name
= *namp
; i
< *lenp
; i
++, name
++) {
97 decode_sattr(__be32
*p
, struct iattr
*iap
)
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.
107 if ((tmp
= ntohl(*p
++)) != (u32
)-1 && tmp
!= 0xffff) {
108 iap
->ia_valid
|= ATTR_MODE
;
111 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
112 iap
->ia_valid
|= ATTR_UID
;
115 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
116 iap
->ia_valid
|= ATTR_GID
;
119 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
120 iap
->ia_valid
|= ATTR_SIZE
;
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
.tv_sec
= tmp
;
127 iap
->ia_atime
.tv_nsec
= tmp1
* 1000;
129 tmp
= ntohl(*p
++); tmp1
= ntohl(*p
++);
130 if (tmp
!= (u32
)-1 && tmp1
!= (u32
)-1) {
131 iap
->ia_valid
|= ATTR_MTIME
| ATTR_MTIME_SET
;
132 iap
->ia_mtime
.tv_sec
= tmp
;
133 iap
->ia_mtime
.tv_nsec
= tmp1
* 1000;
135 * Passing the invalid value useconds=1000000 for mtime
136 * is a Sun convention for "set both mtime and atime to
137 * current server time". It's needed to make permissions
138 * checks for the "touch" program across v2 mounts to
139 * Solaris and Irix boxes work correctly. See description of
140 * sattr in section 6.1 of "NFS Illustrated" by
141 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
144 iap
->ia_valid
&= ~(ATTR_ATIME_SET
|ATTR_MTIME_SET
);
150 encode_fattr(struct svc_rqst
*rqstp
, __be32
*p
, struct svc_fh
*fhp
,
153 struct dentry
*dentry
= fhp
->fh_dentry
;
155 struct timespec time
;
157 type
= (stat
->mode
& S_IFMT
);
159 *p
++ = htonl(nfs_ftypes
[type
>> 12]);
160 *p
++ = htonl((u32
) stat
->mode
);
161 *p
++ = htonl((u32
) stat
->nlink
);
162 *p
++ = htonl((u32
) nfsd_ruid(rqstp
, stat
->uid
));
163 *p
++ = htonl((u32
) nfsd_rgid(rqstp
, stat
->gid
));
165 if (S_ISLNK(type
) && stat
->size
> NFS_MAXPATHLEN
) {
166 *p
++ = htonl(NFS_MAXPATHLEN
);
168 *p
++ = htonl((u32
) stat
->size
);
170 *p
++ = htonl((u32
) stat
->blksize
);
171 if (S_ISCHR(type
) || S_ISBLK(type
))
172 *p
++ = htonl(new_encode_dev(stat
->rdev
));
174 *p
++ = htonl(0xffffffff);
175 *p
++ = htonl((u32
) stat
->blocks
);
176 if (is_fsid(fhp
, rqstp
->rq_reffh
))
177 *p
++ = htonl((u32
) fhp
->fh_export
->ex_fsid
);
179 *p
++ = htonl(new_encode_dev(stat
->dev
));
180 *p
++ = htonl((u32
) stat
->ino
);
181 *p
++ = htonl((u32
) stat
->atime
.tv_sec
);
182 *p
++ = htonl(stat
->atime
.tv_nsec
? stat
->atime
.tv_nsec
/ 1000 : 0);
183 lease_get_mtime(dentry
->d_inode
, &time
);
184 *p
++ = htonl((u32
) time
.tv_sec
);
185 *p
++ = htonl(time
.tv_nsec
? time
.tv_nsec
/ 1000 : 0);
186 *p
++ = htonl((u32
) stat
->ctime
.tv_sec
);
187 *p
++ = htonl(stat
->ctime
.tv_nsec
? stat
->ctime
.tv_nsec
/ 1000 : 0);
192 /* Helper function for NFSv2 ACL code */
193 __be32
*nfs2svc_encode_fattr(struct svc_rqst
*rqstp
, __be32
*p
, struct svc_fh
*fhp
)
196 vfs_getattr(fhp
->fh_export
->ex_mnt
, fhp
->fh_dentry
, &stat
);
197 return encode_fattr(rqstp
, p
, fhp
, &stat
);
201 * XDR decode functions
204 nfssvc_decode_void(struct svc_rqst
*rqstp
, __be32
*p
, void *dummy
)
206 return xdr_argsize_check(rqstp
, p
);
210 nfssvc_decode_fhandle(struct svc_rqst
*rqstp
, __be32
*p
, struct nfsd_fhandle
*args
)
212 if (!(p
= decode_fh(p
, &args
->fh
)))
214 return xdr_argsize_check(rqstp
, p
);
218 nfssvc_decode_sattrargs(struct svc_rqst
*rqstp
, __be32
*p
,
219 struct nfsd_sattrargs
*args
)
221 if (!(p
= decode_fh(p
, &args
->fh
))
222 || !(p
= decode_sattr(p
, &args
->attrs
)))
225 return xdr_argsize_check(rqstp
, p
);
229 nfssvc_decode_diropargs(struct svc_rqst
*rqstp
, __be32
*p
,
230 struct nfsd_diropargs
*args
)
232 if (!(p
= decode_fh(p
, &args
->fh
))
233 || !(p
= decode_filename(p
, &args
->name
, &args
->len
)))
236 return xdr_argsize_check(rqstp
, p
);
240 nfssvc_decode_readargs(struct svc_rqst
*rqstp
, __be32
*p
,
241 struct nfsd_readargs
*args
)
245 if (!(p
= decode_fh(p
, &args
->fh
)))
248 args
->offset
= ntohl(*p
++);
249 len
= args
->count
= ntohl(*p
++);
250 p
++; /* totalcount - unused */
252 if (len
> NFSSVC_MAXBLKSIZE_V2
)
253 len
= NFSSVC_MAXBLKSIZE_V2
;
255 /* set up somewhere to store response.
256 * We take pages, put them on reslist and include in iovec
260 pn
= rqstp
->rq_resused
++;
261 rqstp
->rq_vec
[v
].iov_base
= page_address(rqstp
->rq_respages
[pn
]);
262 rqstp
->rq_vec
[v
].iov_len
= len
< PAGE_SIZE
?len
:PAGE_SIZE
;
263 len
-= rqstp
->rq_vec
[v
].iov_len
;
267 return xdr_argsize_check(rqstp
, p
);
271 nfssvc_decode_writeargs(struct svc_rqst
*rqstp
, __be32
*p
,
272 struct nfsd_writeargs
*args
)
276 if (!(p
= decode_fh(p
, &args
->fh
)))
279 p
++; /* beginoffset */
280 args
->offset
= ntohl(*p
++); /* offset */
281 p
++; /* totalcount */
282 len
= args
->len
= ntohl(*p
++);
283 rqstp
->rq_vec
[0].iov_base
= (void*)p
;
284 rqstp
->rq_vec
[0].iov_len
= rqstp
->rq_arg
.head
[0].iov_len
-
285 (((void*)p
) - rqstp
->rq_arg
.head
[0].iov_base
);
286 if (len
> NFSSVC_MAXBLKSIZE_V2
)
287 len
= NFSSVC_MAXBLKSIZE_V2
;
289 while (len
> rqstp
->rq_vec
[v
].iov_len
) {
290 len
-= rqstp
->rq_vec
[v
].iov_len
;
292 rqstp
->rq_vec
[v
].iov_base
= page_address(rqstp
->rq_pages
[v
]);
293 rqstp
->rq_vec
[v
].iov_len
= PAGE_SIZE
;
295 rqstp
->rq_vec
[v
].iov_len
= len
;
297 return rqstp
->rq_vec
[0].iov_len
> 0;
301 nfssvc_decode_createargs(struct svc_rqst
*rqstp
, __be32
*p
,
302 struct nfsd_createargs
*args
)
304 if (!(p
= decode_fh(p
, &args
->fh
))
305 || !(p
= decode_filename(p
, &args
->name
, &args
->len
))
306 || !(p
= decode_sattr(p
, &args
->attrs
)))
309 return xdr_argsize_check(rqstp
, p
);
313 nfssvc_decode_renameargs(struct svc_rqst
*rqstp
, __be32
*p
,
314 struct nfsd_renameargs
*args
)
316 if (!(p
= decode_fh(p
, &args
->ffh
))
317 || !(p
= decode_filename(p
, &args
->fname
, &args
->flen
))
318 || !(p
= decode_fh(p
, &args
->tfh
))
319 || !(p
= decode_filename(p
, &args
->tname
, &args
->tlen
)))
322 return xdr_argsize_check(rqstp
, p
);
326 nfssvc_decode_readlinkargs(struct svc_rqst
*rqstp
, __be32
*p
, struct nfsd_readlinkargs
*args
)
328 if (!(p
= decode_fh(p
, &args
->fh
)))
330 args
->buffer
= page_address(rqstp
->rq_respages
[rqstp
->rq_resused
++]);
332 return xdr_argsize_check(rqstp
, p
);
336 nfssvc_decode_linkargs(struct svc_rqst
*rqstp
, __be32
*p
,
337 struct nfsd_linkargs
*args
)
339 if (!(p
= decode_fh(p
, &args
->ffh
))
340 || !(p
= decode_fh(p
, &args
->tfh
))
341 || !(p
= decode_filename(p
, &args
->tname
, &args
->tlen
)))
344 return xdr_argsize_check(rqstp
, p
);
348 nfssvc_decode_symlinkargs(struct svc_rqst
*rqstp
, __be32
*p
,
349 struct nfsd_symlinkargs
*args
)
351 if (!(p
= decode_fh(p
, &args
->ffh
))
352 || !(p
= decode_filename(p
, &args
->fname
, &args
->flen
))
353 || !(p
= decode_pathname(p
, &args
->tname
, &args
->tlen
))
354 || !(p
= decode_sattr(p
, &args
->attrs
)))
357 return xdr_argsize_check(rqstp
, p
);
361 nfssvc_decode_readdirargs(struct svc_rqst
*rqstp
, __be32
*p
,
362 struct nfsd_readdirargs
*args
)
364 if (!(p
= decode_fh(p
, &args
->fh
)))
366 args
->cookie
= ntohl(*p
++);
367 args
->count
= ntohl(*p
++);
368 if (args
->count
> PAGE_SIZE
)
369 args
->count
= PAGE_SIZE
;
371 args
->buffer
= page_address(rqstp
->rq_respages
[rqstp
->rq_resused
++]);
373 return xdr_argsize_check(rqstp
, p
);
377 * XDR encode functions
380 nfssvc_encode_void(struct svc_rqst
*rqstp
, __be32
*p
, void *dummy
)
382 return xdr_ressize_check(rqstp
, p
);
386 nfssvc_encode_attrstat(struct svc_rqst
*rqstp
, __be32
*p
,
387 struct nfsd_attrstat
*resp
)
389 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
390 return xdr_ressize_check(rqstp
, p
);
394 nfssvc_encode_diropres(struct svc_rqst
*rqstp
, __be32
*p
,
395 struct nfsd_diropres
*resp
)
397 p
= encode_fh(p
, &resp
->fh
);
398 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
399 return xdr_ressize_check(rqstp
, p
);
403 nfssvc_encode_readlinkres(struct svc_rqst
*rqstp
, __be32
*p
,
404 struct nfsd_readlinkres
*resp
)
406 *p
++ = htonl(resp
->len
);
407 xdr_ressize_check(rqstp
, p
);
408 rqstp
->rq_res
.page_len
= resp
->len
;
410 /* need to pad the tail */
411 rqstp
->rq_res
.tail
[0].iov_base
= p
;
413 rqstp
->rq_res
.tail
[0].iov_len
= 4 - (resp
->len
&3);
419 nfssvc_encode_readres(struct svc_rqst
*rqstp
, __be32
*p
,
420 struct nfsd_readres
*resp
)
422 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
423 *p
++ = htonl(resp
->count
);
424 xdr_ressize_check(rqstp
, p
);
426 /* now update rqstp->rq_res to reflect data aswell */
427 rqstp
->rq_res
.page_len
= resp
->count
;
428 if (resp
->count
& 3) {
429 /* need to pad the tail */
430 rqstp
->rq_res
.tail
[0].iov_base
= p
;
432 rqstp
->rq_res
.tail
[0].iov_len
= 4 - (resp
->count
&3);
438 nfssvc_encode_readdirres(struct svc_rqst
*rqstp
, __be32
*p
,
439 struct nfsd_readdirres
*resp
)
441 xdr_ressize_check(rqstp
, p
);
443 *p
++ = 0; /* no more entries */
444 *p
++ = htonl((resp
->common
.err
== nfserr_eof
));
445 rqstp
->rq_res
.page_len
= (((unsigned long)p
-1) & ~PAGE_MASK
)+1;
451 nfssvc_encode_statfsres(struct svc_rqst
*rqstp
, __be32
*p
,
452 struct nfsd_statfsres
*resp
)
454 struct kstatfs
*stat
= &resp
->stats
;
456 *p
++ = htonl(NFSSVC_MAXBLKSIZE_V2
); /* max transfer size */
457 *p
++ = htonl(stat
->f_bsize
);
458 *p
++ = htonl(stat
->f_blocks
);
459 *p
++ = htonl(stat
->f_bfree
);
460 *p
++ = htonl(stat
->f_bavail
);
461 return xdr_ressize_check(rqstp
, p
);
465 nfssvc_encode_entry(struct readdir_cd
*ccd
, const char *name
,
466 int namlen
, loff_t offset
, ino_t ino
, unsigned int d_type
)
468 struct nfsd_readdirres
*cd
= container_of(ccd
, struct nfsd_readdirres
, common
);
469 __be32
*p
= cd
->buffer
;
473 dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
474 namlen, name, offset, ino);
477 if (offset
> ~((u32
) 0)) {
478 cd
->common
.err
= nfserr_fbig
;
482 *cd
->offset
= htonl(offset
);
483 if (namlen
> NFS2_MAXNAMLEN
)
484 namlen
= NFS2_MAXNAMLEN
;/* truncate filename */
486 slen
= XDR_QUADLEN(namlen
);
487 if ((buflen
= cd
->buflen
- slen
- 4) < 0) {
488 cd
->common
.err
= nfserr_toosmall
;
491 *p
++ = xdr_one
; /* mark entry present */
492 *p
++ = htonl((u32
) ino
); /* file id */
493 p
= xdr_encode_array(p
, name
, namlen
);/* name length & name */
494 cd
->offset
= p
; /* remember pointer */
495 *p
++ = htonl(~0U); /* offset of next entry */
499 cd
->common
.err
= nfs_ok
;
504 * XDR release functions
507 nfssvc_release_fhandle(struct svc_rqst
*rqstp
, __be32
*p
,
508 struct nfsd_fhandle
*resp
)