1 /* $NetBSD: nfs.c,v 1.16 2009/03/14 15:36:08 dsl Exp $ */
4 * Copyright (c) 1993 John Brezak
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/param.h>
33 #include <sys/socket.h>
36 #include <lib/libkern/libkern.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
47 #include <lib/libsa/stand.h>
53 /* Define our own NFS attributes. */
66 struct nfsv2_time fa_atime
;
67 struct nfsv2_time fa_mtime
;
68 struct nfsv2_time fa_ctime
;
72 struct nfs_read_args
{
73 u_char fh
[NFS_FHSIZE
];
76 n_long xxx
; /* XXX what's this for? */
79 /* Data part of nfs rpc reply (also the largest thing we receive) */
80 #define NFSREAD_SIZE 1024
81 struct nfs_read_repl
{
83 struct nfsv2_fattrs fa
;
85 u_char data
[NFSREAD_SIZE
];
89 struct nfs_readlnk_repl
{
92 char path
[NFS_MAXPATHLEN
];
97 struct iodesc
*iodesc
;
99 u_char fh
[NFS_FHSIZE
];
100 struct nfsv2_fattrs fa
; /* all in network order */
103 int nfs_getrootfh(struct iodesc
*, char *, u_char
*);
104 int nfs_lookupfh(struct nfs_iodesc
*, const char *, int,
105 struct nfs_iodesc
*);
106 #ifndef NFS_NOSYMLINK
107 int nfs_readlink(struct nfs_iodesc
*, char *);
109 ssize_t
nfs_readdata(struct nfs_iodesc
*, off_t
, void *, size_t);
112 * Fetch the root file handle (call mount daemon)
113 * Return zero or error number.
116 nfs_getrootfh(struct iodesc
*d
, char *path
, u_char
*fhp
)
121 char path
[FNAME_SIZE
];
125 u_char fh
[NFS_FHSIZE
];
128 n_long h
[RPC_HEADER_WORDS
];
132 n_long h
[RPC_HEADER_WORDS
];
139 printf("nfs_getrootfh: %s\n", path
);
145 memset(args
, 0, sizeof(*args
));
147 if (len
> sizeof(args
->path
))
148 len
= sizeof(args
->path
);
149 args
->len
= htonl(len
);
150 memcpy(args
->path
, path
, len
);
151 len
= 4 + roundup(len
, 4);
153 cc
= rpc_call(d
, RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_MOUNT
,
154 args
, len
, repl
, sizeof(*repl
));
156 /* errno was set by rpc_call */
162 return (ntohl(repl
->errno
));
163 memcpy(fhp
, repl
->fh
, sizeof(repl
->fh
));
168 * Lookup a file. Store handle and attributes.
169 * Return zero or error number.
172 nfs_lookupfh(struct nfs_iodesc
*d
, const char *name
, int len
, struct nfs_iodesc
*newfd
)
176 u_char fh
[NFS_FHSIZE
];
178 char name
[FNAME_SIZE
];
182 u_char fh
[NFS_FHSIZE
];
183 struct nfsv2_fattrs fa
;
186 n_long h
[RPC_HEADER_WORDS
];
190 n_long h
[RPC_HEADER_WORDS
];
197 printf("lookupfh: called\n");
203 memset(args
, 0, sizeof(*args
));
204 memcpy(args
->fh
, d
->fh
, sizeof(args
->fh
));
205 if ((size_t)len
> sizeof(args
->name
))
206 len
= sizeof(args
->name
);
207 memcpy(args
->name
, name
, len
);
208 args
->len
= htonl(len
);
209 len
= 4 + roundup(len
, 4);
212 rlen
= sizeof(*repl
);
214 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_LOOKUP
,
215 args
, len
, repl
, rlen
);
217 return (errno
); /* XXX - from rpc_call */
221 /* saerrno.h now matches NFS error numbers. */
222 return (ntohl(repl
->errno
));
224 memcpy(&newfd
->fh
, repl
->fh
, sizeof(newfd
->fh
));
225 memcpy(&newfd
->fa
, &repl
->fa
, sizeof(newfd
->fa
));
229 #ifndef NFS_NOSYMLINK
231 * Get the destination of a symbolic link.
234 nfs_readlink(struct nfs_iodesc
*d
, char *buf
)
237 n_long h
[RPC_HEADER_WORDS
];
238 u_char fh
[NFS_FHSIZE
];
241 n_long h
[RPC_HEADER_WORDS
];
242 struct nfs_readlnk_repl d
;
248 printf("readlink: called\n");
251 memcpy(sdata
.fh
, d
->fh
, NFS_FHSIZE
);
252 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_READLINK
,
253 sdata
.fh
, NFS_FHSIZE
,
254 &rdata
.d
, sizeof(rdata
.d
));
262 return (ntohl(rdata
.d
.errno
));
264 rdata
.d
.len
= ntohl(rdata
.d
.len
);
265 if (rdata
.d
.len
> NFS_MAXPATHLEN
)
266 return (ENAMETOOLONG
);
268 memcpy(buf
, rdata
.d
.path
, rdata
.d
.len
);
269 buf
[rdata
.d
.len
] = 0;
275 * Read data from a file.
276 * Return transfer count or -1 (and set errno)
279 nfs_readdata(struct nfs_iodesc
*d
, off_t off
, void *addr
, size_t len
)
281 struct nfs_read_args
*args
;
282 struct nfs_read_repl
*repl
;
284 n_long h
[RPC_HEADER_WORDS
];
285 struct nfs_read_args d
;
288 n_long h
[RPC_HEADER_WORDS
];
289 struct nfs_read_repl d
;
298 memcpy(args
->fh
, d
->fh
, NFS_FHSIZE
);
299 args
->off
= htonl((n_long
)off
);
300 if (len
> NFSREAD_SIZE
)
302 args
->len
= htonl((n_long
)len
);
303 args
->xxx
= htonl((n_long
)0);
304 hlen
= sizeof(*repl
) - NFSREAD_SIZE
;
306 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_READ
,
308 repl
, sizeof(*repl
));
310 /* errno was already set by rpc_call */
318 errno
= ntohl(repl
->errno
);
322 x
= ntohl(repl
->count
);
324 printf("nfsread: short packet, %d < %ld\n", rlen
, x
);
328 memcpy(addr
, repl
->data
, x
);
334 * return zero or error number
337 nfs_open(const char *path
, struct open_file
*f
)
339 static struct nfs_iodesc nfs_root_node
;
341 struct nfs_iodesc
*currfd
;
343 #ifndef NFS_NOSYMLINK
344 struct nfs_iodesc
*newfd
;
345 struct nfsv2_fattrs
*fa
;
348 char namebuf
[NFS_MAXPATHLEN
+ 1];
349 char linkbuf
[NFS_MAXPATHLEN
+ 1];
356 printf("nfs_open: %s\n", path
);
359 printf("no rootpath, no nfs\n");
363 if (!(desc
= socktodesc(*(int *)(f
->f_devdata
))))
366 /* Bind to a reserved port. */
367 desc
->myport
= htons(--rpc_port
);
368 desc
->destip
= rootip
;
369 if ((error
= nfs_getrootfh(desc
, rootpath
, nfs_root_node
.fh
)))
371 nfs_root_node
.iodesc
= desc
;
373 #ifndef NFS_NOSYMLINK
374 /* Fake up attributes for the root dir. */
375 fa
= &nfs_root_node
.fa
;
376 fa
->fa_type
= htonl(NFDIR
);
377 fa
->fa_mode
= htonl(0755);
378 fa
->fa_nlink
= htonl(2);
380 currfd
= &nfs_root_node
;
386 * Remove extra separators
394 * Check that current node is a directory.
396 if (currfd
->fa
.fa_type
!= htonl(NFDIR
)) {
401 /* allocate file system specific data structure */
402 newfd
= alloc(sizeof(*newfd
));
403 newfd
->iodesc
= currfd
->iodesc
;
407 * Get next component of path name.
413 while ((c
= *cp
) != '\0' && c
!= '/') {
414 if (++len
> NFS_MAXNAMLEN
) {
422 /* lookup a file handle */
423 error
= nfs_lookupfh(currfd
, ncp
, cp
- ncp
, newfd
);
428 * Check for symbolic link
430 if (newfd
->fa
.fa_type
== htonl(NFLNK
)) {
433 error
= nfs_readlink(newfd
, linkbuf
);
437 link_len
= strlen(linkbuf
);
440 if (link_len
+ len
> MAXPATHLEN
441 || ++nlinks
> MAXSYMLINKS
) {
446 memcpy(&namebuf
[link_len
], cp
, len
+ 1);
447 memcpy(namebuf
, linkbuf
, link_len
);
450 * If absolute pathname, restart at root.
451 * If relative pathname, restart at parent directory.
455 if (currfd
!= &nfs_root_node
)
456 dealloc(currfd
, sizeof(*currfd
));
457 currfd
= &nfs_root_node
;
460 dealloc(newfd
, sizeof(*newfd
));
466 if (currfd
!= &nfs_root_node
)
467 dealloc(currfd
, sizeof(*currfd
));
476 dealloc(newfd
, sizeof(*newfd
));
478 /* allocate file system specific data structure */
479 currfd
= alloc(sizeof(*currfd
));
480 currfd
->iodesc
= desc
;
485 * Remove extra separators
490 /* XXX: Check for empty path here? */
492 error
= nfs_lookupfh(&nfs_root_node
, cp
, strlen(cp
), currfd
);
495 f
->f_fsdata
= (void *)currfd
;
502 printf("nfs_open: %s lookupfh failed: %s\n",
503 path
, strerror(error
));
505 #ifndef NFS_NOSYMLINK
506 if (currfd
!= &nfs_root_node
)
508 dealloc(currfd
, sizeof(*currfd
));
514 nfs_close(struct open_file
*f
)
516 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
520 printf("nfs_close: fp=0x%lx\n", (u_long
)fp
);
524 dealloc(fp
, sizeof(struct nfs_iodesc
));
525 f
->f_fsdata
= (void *)0;
531 * read a portion of a file
534 nfs_read(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
537 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
543 printf("nfs_read: size=%lu off=%d\n", (u_long
)size
,
546 while ((int)size
> 0) {
547 #if !defined(LIBSA_NO_TWIDDLE)
550 cc
= nfs_readdata(fp
, fp
->off
, (void *)addr
, size
);
551 /* XXX maybe should retry on certain errors */
555 printf("nfs_read: read: %s", strerror(errno
));
557 return (errno
); /* XXX - from nfs_readdata */
562 printf("nfs_read: hit EOF unexpectantly");
581 nfs_write(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
589 nfs_seek(struct open_file
*f
, off_t offset
, int where
)
591 struct nfs_iodesc
*d
= (struct nfs_iodesc
*)f
->f_fsdata
;
592 n_long size
= ntohl(d
->fa
.fa_size
);
602 d
->off
= size
- offset
;
611 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
612 const int nfs_stat_types
[8] = {
613 0, S_IFREG
, S_IFDIR
, S_IFBLK
, S_IFCHR
, S_IFLNK
, 0 };
616 nfs_stat(struct open_file
*f
, struct stat
*sb
)
618 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
621 ftype
= ntohl(fp
->fa
.fa_type
);
622 mode
= ntohl(fp
->fa
.fa_mode
);
623 mode
|= nfs_stat_types
[ftype
& 7];
626 sb
->st_nlink
= ntohl(fp
->fa
.fa_nlink
);
627 sb
->st_uid
= ntohl(fp
->fa
.fa_uid
);
628 sb
->st_gid
= ntohl(fp
->fa
.fa_gid
);
629 sb
->st_size
= ntohl(fp
->fa
.fa_size
);