1 /* $NetBSD: nfs.c,v 1.48 2014/03/20 03:13:18 christos 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.
32 * XXX Does not currently implement:
34 * XXX LIBSA_NO_FS_CLOSE
35 * XXX LIBSA_NO_FS_SEEK
36 * XXX LIBSA_NO_FS_WRITE
37 * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
38 * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?)
41 #include <sys/param.h>
43 #include <sys/socket.h>
46 #include <lib/libkern/libkern.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
62 /* Define our own NFS attributes */
75 struct nfsv2_time fa_atime
;
76 struct nfsv2_time fa_mtime
;
77 struct nfsv2_time fa_ctime
;
81 struct nfs_read_args
{
82 u_char fh
[NFS_FHSIZE
];
85 n_long xxx
; /* XXX what's this for? */
88 /* Data part of nfs rpc reply (also the largest thing we receive) */
89 #define NFSREAD_SIZE 1024
90 struct nfs_read_repl
{
92 struct nfsv2_fattrs fa
;
94 u_char data
[NFSREAD_SIZE
];
98 struct nfs_readlnk_repl
{
101 char path
[NFS_MAXPATHLEN
];
106 struct iodesc
*iodesc
;
108 u_char fh
[NFS_FHSIZE
];
109 struct nfsv2_fattrs fa
; /* all in network order */
112 struct nfs_iodesc nfs_root_node
;
114 int nfs_getrootfh(struct iodesc
*, char *, u_char
*);
115 int nfs_lookupfh(struct nfs_iodesc
*, const char *, int,
116 struct nfs_iodesc
*);
117 int nfs_readlink(struct nfs_iodesc
*, char *);
118 ssize_t
nfs_readdata(struct nfs_iodesc
*, off_t
, void *, size_t);
121 * Fetch the root file handle (call mount daemon)
122 * On error, return non-zero and set errno.
125 nfs_getrootfh(struct iodesc
*d
, char *path
, u_char
*fhp
)
130 char path
[FNAME_SIZE
];
134 u_char fh
[NFS_FHSIZE
];
137 n_long h
[RPC_HEADER_WORDS
];
141 n_long h
[RPC_HEADER_WORDS
];
148 printf("nfs_getrootfh: %s\n", path
);
154 (void)memset(args
, 0, sizeof(*args
));
156 if ((size_t)len
> sizeof(args
->path
))
157 len
= sizeof(args
->path
);
158 args
->len
= htonl(len
);
159 (void)memcpy(args
->path
, path
, len
);
160 len
= 4 + roundup(len
, 4);
162 cc
= rpc_call(d
, RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_MOUNT
,
163 args
, len
, repl
, sizeof(*repl
));
165 /* errno was set by rpc_call */
173 errno
= ntohl(repl
->errno
);
176 (void)memcpy(fhp
, repl
->fh
, sizeof(repl
->fh
));
181 * Lookup a file. Store handle and attributes.
182 * Return zero or error number.
185 nfs_lookupfh(struct nfs_iodesc
*d
, const char *name
, int len
,
186 struct nfs_iodesc
*newfd
)
190 u_char fh
[NFS_FHSIZE
];
192 char name
[FNAME_SIZE
];
196 u_char fh
[NFS_FHSIZE
];
197 struct nfsv2_fattrs fa
;
200 n_long h
[RPC_HEADER_WORDS
];
204 n_long h
[RPC_HEADER_WORDS
];
211 printf("lookupfh: called\n");
217 (void)memset(args
, 0, sizeof(*args
));
218 (void)memcpy(args
->fh
, d
->fh
, sizeof(args
->fh
));
219 if ((size_t)len
> sizeof(args
->name
))
220 len
= sizeof(args
->name
);
221 (void)memcpy(args
->name
, name
, len
);
222 args
->len
= htonl(len
);
223 len
= 4 + roundup(len
, 4);
226 rlen
= sizeof(*repl
);
228 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_LOOKUP
,
229 args
, len
, repl
, rlen
);
231 return errno
; /* XXX - from rpc_call */
235 /* saerrno.h now matches NFS error numbers. */
236 return ntohl(repl
->errno
);
238 (void)memcpy(&newfd
->fh
, repl
->fh
, sizeof(newfd
->fh
));
239 (void)memcpy(&newfd
->fa
, &repl
->fa
, sizeof(newfd
->fa
));
243 #ifndef NFS_NOSYMLINK
245 * Get the destination of a symbolic link.
248 nfs_readlink(struct nfs_iodesc
*d
, char *buf
)
251 n_long h
[RPC_HEADER_WORDS
];
252 u_char fh
[NFS_FHSIZE
];
255 n_long h
[RPC_HEADER_WORDS
];
256 struct nfs_readlnk_repl d
;
262 printf("readlink: called\n");
265 (void)memcpy(sdata
.fh
, d
->fh
, NFS_FHSIZE
);
266 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_READLINK
,
267 sdata
.fh
, NFS_FHSIZE
,
268 &rdata
.d
, sizeof(rdata
.d
));
276 return ntohl(rdata
.d
.errno
);
278 rdata
.d
.len
= ntohl(rdata
.d
.len
);
279 if (rdata
.d
.len
> NFS_MAXPATHLEN
)
282 (void)memcpy(buf
, rdata
.d
.path
, rdata
.d
.len
);
283 buf
[rdata
.d
.len
] = 0;
289 * Read data from a file.
290 * Return transfer count or -1 (and set errno)
293 nfs_readdata(struct nfs_iodesc
*d
, off_t off
, void *addr
, size_t len
)
295 struct nfs_read_args
*args
;
296 struct nfs_read_repl
*repl
;
298 n_long h
[RPC_HEADER_WORDS
];
299 struct nfs_read_args d
;
302 n_long h
[RPC_HEADER_WORDS
];
303 struct nfs_read_repl d
;
312 (void)memcpy(args
->fh
, d
->fh
, NFS_FHSIZE
);
313 args
->off
= htonl((n_long
)off
);
314 if (len
> NFSREAD_SIZE
)
316 args
->len
= htonl((n_long
)len
);
317 args
->xxx
= htonl((n_long
)0);
318 hlen
= sizeof(*repl
) - NFSREAD_SIZE
;
320 cc
= rpc_call(d
->iodesc
, NFS_PROG
, NFS_VER2
, NFSPROC_READ
,
322 repl
, sizeof(*repl
));
324 /* errno was already set by rpc_call */
327 if (cc
< (ssize_t
)hlen
) {
332 errno
= ntohl(repl
->errno
);
336 x
= ntohl(repl
->count
);
337 if (rlen
< (size_t)x
) {
338 printf("nfsread: short packet, %lu < %ld\n", (u_long
) rlen
, x
);
342 (void)memcpy(addr
, repl
->data
, x
);
347 * nfs_mount - mount this nfs filesystem to a host
348 * On error, return non-zero and set errno.
351 nfs_mount(int sock
, struct in_addr ip
, char *path
)
354 struct nfsv2_fattrs
*fa
;
356 if (!(desc
= socktodesc(sock
))) {
361 /* Bind to a reserved port. */
362 desc
->myport
= htons(--rpc_port
);
364 if (nfs_getrootfh(desc
, path
, nfs_root_node
.fh
))
366 nfs_root_node
.iodesc
= desc
;
367 /* Fake up attributes for the root dir. */
368 fa
= &nfs_root_node
.fa
;
369 fa
->fa_type
= htonl(NFDIR
);
370 fa
->fa_mode
= htonl(0755);
371 fa
->fa_nlink
= htonl(2);
375 printf("nfs_mount: got fh for %s\n", path
);
383 * return zero or error number
386 nfs_open(const char *path
, struct open_file
*f
)
388 struct nfs_iodesc
*newfd
, *currfd
;
390 #ifndef NFS_NOSYMLINK
393 char namebuf
[NFS_MAXPATHLEN
+ 1];
394 char linkbuf
[NFS_MAXPATHLEN
+ 1];
401 printf("nfs_open: %s\n", path
);
403 if (nfs_root_node
.iodesc
== NULL
) {
404 printf("nfs_open: must mount first.\n");
408 currfd
= &nfs_root_node
;
411 #ifndef NFS_NOSYMLINK
415 * Remove extra separators
423 * Check that current node is a directory.
425 if (currfd
->fa
.fa_type
!= htonl(NFDIR
)) {
430 /* allocate file system specific data structure */
431 newfd
= alloc(sizeof(*newfd
));
432 newfd
->iodesc
= currfd
->iodesc
;
436 * Get next component of path name.
442 while ((c
= *cp
) != '\0' && c
!= '/') {
443 if (++len
> NFS_MAXNAMLEN
) {
451 /* lookup a file handle */
452 error
= nfs_lookupfh(currfd
, ncp
, cp
- ncp
, newfd
);
457 * Check for symbolic link
459 if (newfd
->fa
.fa_type
== htonl(NFLNK
)) {
462 error
= nfs_readlink(newfd
, linkbuf
);
466 link_len
= strlen(linkbuf
);
469 if (link_len
+ len
> MAXPATHLEN
470 || ++nlinks
> MAXSYMLINKS
) {
475 (void)memcpy(&namebuf
[link_len
], cp
, len
+ 1);
476 (void)memcpy(namebuf
, linkbuf
, link_len
);
479 * If absolute pathname, restart at root.
480 * If relative pathname, restart at parent directory.
484 if (currfd
!= &nfs_root_node
)
485 dealloc(currfd
, sizeof(*currfd
));
486 currfd
= &nfs_root_node
;
489 dealloc(newfd
, sizeof(*newfd
));
495 if (currfd
!= &nfs_root_node
)
496 dealloc(currfd
, sizeof(*currfd
));
505 /* allocate file system specific data structure */
506 currfd
= alloc(sizeof(*currfd
));
507 currfd
->iodesc
= nfs_root_node
.iodesc
;
512 * Remove extra separators
517 /* XXX: Check for empty path here? */
519 error
= nfs_lookupfh(&nfs_root_node
, cp
, strlen(cp
), currfd
);
522 f
->f_fsdata
= (void *)currfd
;
529 printf("nfs_open: %s lookupfh failed: %s\n",
530 path
, strerror(error
));
532 if (currfd
!= &nfs_root_node
)
533 dealloc(currfd
, sizeof(*currfd
));
535 dealloc(newfd
, sizeof(*newfd
));
541 nfs_close(struct open_file
*f
)
543 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
547 printf("nfs_close: fp=0x%lx\n", (u_long
)fp
);
551 dealloc(fp
, sizeof(struct nfs_iodesc
));
552 f
->f_fsdata
= (void *)0;
558 * read a portion of a file
561 nfs_read(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
563 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
569 printf("nfs_read: size=%lu off=%d\n", (u_long
)size
,
572 while ((int)size
> 0) {
573 #if !defined(LIBSA_NO_TWIDDLE)
576 cc
= nfs_readdata(fp
, fp
->off
, (void *)addr
, size
);
577 /* XXX maybe should retry on certain errors */
581 printf("nfs_read: read: %s\n",
584 return errno
; /* XXX - from nfs_readdata */
589 printf("nfs_read: hit EOF unexpectantly\n");
608 nfs_write(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
614 nfs_seek(struct open_file
*f
, off_t offset
, int where
)
616 struct nfs_iodesc
*d
= (struct nfs_iodesc
*)f
->f_fsdata
;
617 n_long size
= ntohl(d
->fa
.fa_size
);
627 d
->off
= size
- offset
;
636 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
637 const int nfs_stat_types
[8] = {
638 0, S_IFREG
, S_IFDIR
, S_IFBLK
, S_IFCHR
, S_IFLNK
, 0 };
641 nfs_stat(struct open_file
*f
, struct stat
*sb
)
643 struct nfs_iodesc
*fp
= (struct nfs_iodesc
*)f
->f_fsdata
;
646 ftype
= ntohl(fp
->fa
.fa_type
);
647 mode
= ntohl(fp
->fa
.fa_mode
);
648 mode
|= nfs_stat_types
[ftype
& 7];
651 sb
->st_nlink
= ntohl(fp
->fa
.fa_nlink
);
652 sb
->st_uid
= ntohl(fp
->fa
.fa_uid
);
653 sb
->st_gid
= ntohl(fp
->fa
.fa_gid
);
654 sb
->st_size
= ntohl(fp
->fa
.fa_size
);
659 #if defined(LIBSA_ENABLE_LS_OP)
662 nfs_ls(struct open_file
*f
, const char *pattern
)