nfs.c revision 1.43 1 1.43 christos /* $NetBSD: nfs.c,v 1.43 2008/03/25 21:23:50 christos Exp $ */
2 1.4 cgd
3 1.1 brezak /*-
4 1.1 brezak * Copyright (c) 1993 John Brezak
5 1.1 brezak * All rights reserved.
6 1.37 perry *
7 1.1 brezak * Redistribution and use in source and binary forms, with or without
8 1.1 brezak * modification, are permitted provided that the following conditions
9 1.1 brezak * are met:
10 1.1 brezak * 1. Redistributions of source code must retain the above copyright
11 1.1 brezak * notice, this list of conditions and the following disclaimer.
12 1.1 brezak * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 brezak * notice, this list of conditions and the following disclaimer in the
14 1.1 brezak * documentation and/or other materials provided with the distribution.
15 1.1 brezak * 3. The name of the author may not be used to endorse or promote products
16 1.1 brezak * derived from this software without specific prior written permission.
17 1.37 perry *
18 1.1 brezak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 1.1 brezak * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 1.1 brezak * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 1.1 brezak * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 1.1 brezak * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 1.1 brezak * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 1.1 brezak * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.1 brezak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 1.1 brezak * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 1.1 brezak * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.1 brezak * POSSIBILITY OF SUCH DAMAGE.
29 1.1 brezak */
30 1.1 brezak
31 1.25 cgd /*
32 1.25 cgd * XXX Does not currently implement:
33 1.25 cgd * XXX
34 1.25 cgd * XXX LIBSA_NO_FS_CLOSE
35 1.25 cgd * XXX LIBSA_NO_FS_SEEK
36 1.25 cgd * XXX LIBSA_NO_FS_WRITE
37 1.25 cgd * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
38 1.25 cgd * XXX LIBSA_FS_SINGLECOMPONENT (does this even make sense?)
39 1.25 cgd */
40 1.25 cgd
41 1.1 brezak #include <sys/param.h>
42 1.1 brezak #include <sys/time.h>
43 1.1 brezak #include <sys/socket.h>
44 1.1 brezak #include <sys/stat.h>
45 1.27 thorpej #ifdef _STANDALONE
46 1.27 thorpej #include <lib/libkern/libkern.h>
47 1.27 thorpej #else
48 1.27 thorpej #include <string.h>
49 1.27 thorpej #endif
50 1.1 brezak
51 1.1 brezak #include <netinet/in.h>
52 1.1 brezak #include <netinet/in_systm.h>
53 1.1 brezak
54 1.14 gwr #include "rpcv2.h"
55 1.13 scottr #include "nfsv2.h"
56 1.1 brezak
57 1.1 brezak #include "stand.h"
58 1.1 brezak #include "net.h"
59 1.1 brezak #include "nfs.h"
60 1.1 brezak #include "rpc.h"
61 1.1 brezak
62 1.40 yamt /* Define our own NFS attributes */
63 1.7 gwr struct nfsv2_fattrs {
64 1.7 gwr n_long fa_type;
65 1.7 gwr n_long fa_mode;
66 1.7 gwr n_long fa_nlink;
67 1.7 gwr n_long fa_uid;
68 1.7 gwr n_long fa_gid;
69 1.7 gwr n_long fa_size;
70 1.7 gwr n_long fa_blocksize;
71 1.7 gwr n_long fa_rdev;
72 1.7 gwr n_long fa_blocks;
73 1.7 gwr n_long fa_fsid;
74 1.7 gwr n_long fa_fileid;
75 1.7 gwr struct nfsv2_time fa_atime;
76 1.7 gwr struct nfsv2_time fa_mtime;
77 1.7 gwr struct nfsv2_time fa_ctime;
78 1.7 gwr };
79 1.7 gwr
80 1.7 gwr
81 1.7 gwr struct nfs_read_args {
82 1.1 brezak u_char fh[NFS_FHSIZE];
83 1.7 gwr n_long off;
84 1.7 gwr n_long len;
85 1.7 gwr n_long xxx; /* XXX what's this for? */
86 1.1 brezak };
87 1.1 brezak
88 1.1 brezak /* Data part of nfs rpc reply (also the largest thing we receive) */
89 1.7 gwr #define NFSREAD_SIZE 1024
90 1.7 gwr struct nfs_read_repl {
91 1.7 gwr n_long errno;
92 1.7 gwr struct nfsv2_fattrs fa;
93 1.7 gwr n_long count;
94 1.7 gwr u_char data[NFSREAD_SIZE];
95 1.1 brezak };
96 1.1 brezak
97 1.21 drochner #ifndef NFS_NOSYMLINK
98 1.16 ws struct nfs_readlnk_repl {
99 1.16 ws n_long errno;
100 1.16 ws n_long len;
101 1.16 ws char path[NFS_MAXPATHLEN];
102 1.16 ws };
103 1.21 drochner #endif
104 1.16 ws
105 1.1 brezak struct nfs_iodesc {
106 1.7 gwr struct iodesc *iodesc;
107 1.1 brezak off_t off;
108 1.7 gwr u_char fh[NFS_FHSIZE];
109 1.7 gwr struct nfsv2_fattrs fa; /* all in network order */
110 1.7 gwr };
111 1.7 gwr
112 1.8 gwr struct nfs_iodesc nfs_root_node;
113 1.1 brezak
114 1.24 pk int nfs_getrootfh __P((struct iodesc *, char *, u_char *));
115 1.32 dsl int nfs_lookupfh __P((struct nfs_iodesc *, const char *, int,
116 1.32 dsl struct nfs_iodesc *));
117 1.24 pk int nfs_readlink __P((struct nfs_iodesc *, char *));
118 1.24 pk ssize_t nfs_readdata __P((struct nfs_iodesc *, off_t, void *, size_t));
119 1.7 gwr
120 1.12 gwr /*
121 1.12 gwr * Fetch the root file handle (call mount daemon)
122 1.12 gwr * On error, return non-zero and set errno.
123 1.12 gwr */
124 1.7 gwr int
125 1.42 isaki nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
126 1.1 brezak {
127 1.29 augustss int len;
128 1.7 gwr struct args {
129 1.7 gwr n_long len;
130 1.7 gwr char path[FNAME_SIZE];
131 1.7 gwr } *args;
132 1.7 gwr struct repl {
133 1.7 gwr n_long errno;
134 1.7 gwr u_char fh[NFS_FHSIZE];
135 1.7 gwr } *repl;
136 1.1 brezak struct {
137 1.7 gwr n_long h[RPC_HEADER_WORDS];
138 1.7 gwr struct args d;
139 1.7 gwr } sdata;
140 1.1 brezak struct {
141 1.7 gwr n_long h[RPC_HEADER_WORDS];
142 1.7 gwr struct repl d;
143 1.7 gwr } rdata;
144 1.33 fvdl ssize_t cc;
145 1.37 perry
146 1.1 brezak #ifdef NFS_DEBUG
147 1.1 brezak if (debug)
148 1.19 christos printf("nfs_getrootfh: %s\n", path);
149 1.1 brezak #endif
150 1.6 mycroft
151 1.7 gwr args = &sdata.d;
152 1.7 gwr repl = &rdata.d;
153 1.7 gwr
154 1.43 christos (void)memset(args, 0, sizeof(*args));
155 1.1 brezak len = strlen(path);
156 1.33 fvdl if ((size_t)len > sizeof(args->path))
157 1.7 gwr len = sizeof(args->path);
158 1.7 gwr args->len = htonl(len);
159 1.43 christos (void)memcpy(args->path, path, len);
160 1.7 gwr len = 4 + roundup(len, 4);
161 1.7 gwr
162 1.7 gwr cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
163 1.7 gwr args, len, repl, sizeof(*repl));
164 1.12 gwr if (cc == -1) {
165 1.12 gwr /* errno was set by rpc_call */
166 1.42 isaki return -1;
167 1.12 gwr }
168 1.12 gwr if (cc < 4) {
169 1.12 gwr errno = EBADRPC;
170 1.42 isaki return -1;
171 1.12 gwr }
172 1.7 gwr if (repl->errno) {
173 1.7 gwr errno = ntohl(repl->errno);
174 1.42 isaki return -1;
175 1.1 brezak }
176 1.43 christos (void)memcpy(fhp, repl->fh, sizeof(repl->fh));
177 1.42 isaki return 0;
178 1.1 brezak }
179 1.1 brezak
180 1.12 gwr /*
181 1.12 gwr * Lookup a file. Store handle and attributes.
182 1.12 gwr * Return zero or error number.
183 1.12 gwr */
184 1.7 gwr int
185 1.42 isaki nfs_lookupfh(struct nfs_iodesc *d, const char *name, int len,
186 1.42 isaki struct nfs_iodesc *newfd)
187 1.1 brezak {
188 1.32 dsl int rlen;
189 1.7 gwr struct args {
190 1.1 brezak u_char fh[NFS_FHSIZE];
191 1.7 gwr n_long len;
192 1.1 brezak char name[FNAME_SIZE];
193 1.7 gwr } *args;
194 1.7 gwr struct repl {
195 1.7 gwr n_long errno;
196 1.7 gwr u_char fh[NFS_FHSIZE];
197 1.7 gwr struct nfsv2_fattrs fa;
198 1.7 gwr } *repl;
199 1.7 gwr struct {
200 1.7 gwr n_long h[RPC_HEADER_WORDS];
201 1.7 gwr struct args d;
202 1.7 gwr } sdata;
203 1.1 brezak struct {
204 1.7 gwr n_long h[RPC_HEADER_WORDS];
205 1.7 gwr struct repl d;
206 1.7 gwr } rdata;
207 1.9 pk ssize_t cc;
208 1.37 perry
209 1.1 brezak #ifdef NFS_DEBUG
210 1.1 brezak if (debug)
211 1.19 christos printf("lookupfh: called\n");
212 1.1 brezak #endif
213 1.1 brezak
214 1.7 gwr args = &sdata.d;
215 1.7 gwr repl = &rdata.d;
216 1.7 gwr
217 1.43 christos (void)memset(args, 0, sizeof(*args));
218 1.43 christos (void)memcpy(args->fh, d->fh, sizeof(args->fh));
219 1.33 fvdl if ((size_t)len > sizeof(args->name))
220 1.7 gwr len = sizeof(args->name);
221 1.43 christos (void)memcpy(args->name, name, len);
222 1.7 gwr args->len = htonl(len);
223 1.7 gwr len = 4 + roundup(len, 4);
224 1.7 gwr len += NFS_FHSIZE;
225 1.7 gwr
226 1.7 gwr rlen = sizeof(*repl);
227 1.7 gwr
228 1.7 gwr cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
229 1.7 gwr args, len, repl, rlen);
230 1.12 gwr if (cc == -1)
231 1.42 isaki return errno; /* XXX - from rpc_call */
232 1.7 gwr if (cc < 4)
233 1.42 isaki return EIO;
234 1.7 gwr if (repl->errno) {
235 1.12 gwr /* saerrno.h now matches NFS error numbers. */
236 1.42 isaki return ntohl(repl->errno);
237 1.1 brezak }
238 1.43 christos (void)memcpy(&newfd->fh, repl->fh, sizeof(newfd->fh));
239 1.43 christos (void)memcpy(&newfd->fa, &repl->fa, sizeof(newfd->fa));
240 1.42 isaki return 0;
241 1.1 brezak }
242 1.1 brezak
243 1.21 drochner #ifndef NFS_NOSYMLINK
244 1.12 gwr /*
245 1.16 ws * Get the destination of a symbolic link.
246 1.16 ws */
247 1.16 ws int
248 1.42 isaki nfs_readlink(struct nfs_iodesc *d, char *buf)
249 1.16 ws {
250 1.16 ws struct {
251 1.16 ws n_long h[RPC_HEADER_WORDS];
252 1.16 ws u_char fh[NFS_FHSIZE];
253 1.16 ws } sdata;
254 1.16 ws struct {
255 1.16 ws n_long h[RPC_HEADER_WORDS];
256 1.16 ws struct nfs_readlnk_repl d;
257 1.16 ws } rdata;
258 1.16 ws ssize_t cc;
259 1.16 ws
260 1.16 ws #ifdef NFS_DEBUG
261 1.16 ws if (debug)
262 1.19 christos printf("readlink: called\n");
263 1.16 ws #endif
264 1.16 ws
265 1.43 christos (void)memcpy(sdata.fh, d->fh, NFS_FHSIZE);
266 1.16 ws cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
267 1.42 isaki sdata.fh, NFS_FHSIZE,
268 1.42 isaki &rdata.d, sizeof(rdata.d));
269 1.16 ws if (cc == -1)
270 1.42 isaki return errno;
271 1.16 ws
272 1.16 ws if (cc < 4)
273 1.42 isaki return EIO;
274 1.37 perry
275 1.16 ws if (rdata.d.errno)
276 1.42 isaki return ntohl(rdata.d.errno);
277 1.17 cgd
278 1.17 cgd rdata.d.len = ntohl(rdata.d.len);
279 1.16 ws if (rdata.d.len > NFS_MAXPATHLEN)
280 1.42 isaki return ENAMETOOLONG;
281 1.16 ws
282 1.43 christos (void)memcpy(buf, rdata.d.path, rdata.d.len);
283 1.16 ws buf[rdata.d.len] = 0;
284 1.42 isaki return 0;
285 1.16 ws }
286 1.21 drochner #endif
287 1.16 ws
288 1.16 ws /*
289 1.12 gwr * Read data from a file.
290 1.12 gwr * Return transfer count or -1 (and set errno)
291 1.12 gwr */
292 1.9 pk ssize_t
293 1.42 isaki nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
294 1.1 brezak {
295 1.7 gwr struct nfs_read_args *args;
296 1.7 gwr struct nfs_read_repl *repl;
297 1.7 gwr struct {
298 1.7 gwr n_long h[RPC_HEADER_WORDS];
299 1.7 gwr struct nfs_read_args d;
300 1.7 gwr } sdata;
301 1.7 gwr struct {
302 1.7 gwr n_long h[RPC_HEADER_WORDS];
303 1.7 gwr struct nfs_read_repl d;
304 1.7 gwr } rdata;
305 1.33 fvdl ssize_t cc;
306 1.9 pk long x;
307 1.33 fvdl size_t hlen, rlen;
308 1.7 gwr
309 1.7 gwr args = &sdata.d;
310 1.7 gwr repl = &rdata.d;
311 1.6 mycroft
312 1.43 christos (void)memcpy(args->fh, d->fh, NFS_FHSIZE);
313 1.14 gwr args->off = htonl((n_long)off);
314 1.6 mycroft if (len > NFSREAD_SIZE)
315 1.6 mycroft len = NFSREAD_SIZE;
316 1.14 gwr args->len = htonl((n_long)len);
317 1.14 gwr args->xxx = htonl((n_long)0);
318 1.7 gwr hlen = sizeof(*repl) - NFSREAD_SIZE;
319 1.7 gwr
320 1.7 gwr cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
321 1.7 gwr args, sizeof(*args),
322 1.7 gwr repl, sizeof(*repl));
323 1.12 gwr if (cc == -1) {
324 1.12 gwr /* errno was already set by rpc_call */
325 1.42 isaki return -1;
326 1.12 gwr }
327 1.33 fvdl if (cc < (ssize_t)hlen) {
328 1.12 gwr errno = EBADRPC;
329 1.42 isaki return -1;
330 1.9 pk }
331 1.7 gwr if (repl->errno) {
332 1.7 gwr errno = ntohl(repl->errno);
333 1.42 isaki return -1;
334 1.7 gwr }
335 1.7 gwr rlen = cc - hlen;
336 1.7 gwr x = ntohl(repl->count);
337 1.33 fvdl if (rlen < (size_t)x) {
338 1.36 he printf("nfsread: short packet, %lu < %ld\n", (u_long) rlen, x);
339 1.9 pk errno = EBADRPC;
340 1.42 isaki return -1;
341 1.7 gwr }
342 1.43 christos (void)memcpy(addr, repl->data, x);
343 1.42 isaki return x;
344 1.1 brezak }
345 1.1 brezak
346 1.1 brezak /*
347 1.1 brezak * nfs_mount - mount this nfs filesystem to a host
348 1.12 gwr * On error, return non-zero and set errno.
349 1.1 brezak */
350 1.1 brezak int
351 1.42 isaki nfs_mount(int sock, struct in_addr ip, char *path)
352 1.1 brezak {
353 1.1 brezak struct iodesc *desc;
354 1.8 gwr struct nfsv2_fattrs *fa;
355 1.7 gwr
356 1.1 brezak if (!(desc = socktodesc(sock))) {
357 1.1 brezak errno = EINVAL;
358 1.42 isaki return -1;
359 1.1 brezak }
360 1.7 gwr
361 1.7 gwr /* Bind to a reserved port. */
362 1.7 gwr desc->myport = htons(--rpc_port);
363 1.1 brezak desc->destip = ip;
364 1.7 gwr if (nfs_getrootfh(desc, path, nfs_root_node.fh))
365 1.42 isaki return -1;
366 1.7 gwr nfs_root_node.iodesc = desc;
367 1.8 gwr /* Fake up attributes for the root dir. */
368 1.8 gwr fa = &nfs_root_node.fa;
369 1.8 gwr fa->fa_type = htonl(NFDIR);
370 1.8 gwr fa->fa_mode = htonl(0755);
371 1.8 gwr fa->fa_nlink = htonl(2);
372 1.1 brezak
373 1.1 brezak #ifdef NFS_DEBUG
374 1.1 brezak if (debug)
375 1.19 christos printf("nfs_mount: got fh for %s\n", path);
376 1.1 brezak #endif
377 1.1 brezak
378 1.42 isaki return 0;
379 1.1 brezak }
380 1.1 brezak
381 1.1 brezak /*
382 1.1 brezak * Open a file.
383 1.12 gwr * return zero or error number
384 1.1 brezak */
385 1.1 brezak int
386 1.42 isaki nfs_open(const char *path, struct open_file *f)
387 1.1 brezak {
388 1.16 ws struct nfs_iodesc *newfd, *currfd;
389 1.32 dsl const char *cp;
390 1.21 drochner #ifndef NFS_NOSYMLINK
391 1.32 dsl const char *ncp;
392 1.29 augustss int c;
393 1.16 ws char namebuf[NFS_MAXPATHLEN + 1];
394 1.16 ws char linkbuf[NFS_MAXPATHLEN + 1];
395 1.16 ws int nlinks = 0;
396 1.21 drochner #endif
397 1.12 gwr int error = 0;
398 1.1 brezak
399 1.1 brezak #ifdef NFS_DEBUG
400 1.1 brezak if (debug)
401 1.42 isaki printf("nfs_open: %s\n", path);
402 1.1 brezak #endif
403 1.7 gwr if (nfs_root_node.iodesc == NULL) {
404 1.19 christos printf("nfs_open: must mount first.\n");
405 1.42 isaki return ENXIO;
406 1.1 brezak }
407 1.1 brezak
408 1.16 ws currfd = &nfs_root_node;
409 1.16 ws newfd = 0;
410 1.21 drochner
411 1.21 drochner #ifndef NFS_NOSYMLINK
412 1.16 ws cp = path;
413 1.16 ws while (*cp) {
414 1.16 ws /*
415 1.16 ws * Remove extra separators
416 1.16 ws */
417 1.16 ws while (*cp == '/')
418 1.16 ws cp++;
419 1.16 ws
420 1.16 ws if (*cp == '\0')
421 1.16 ws break;
422 1.16 ws /*
423 1.16 ws * Check that current node is a directory.
424 1.16 ws */
425 1.17 cgd if (currfd->fa.fa_type != htonl(NFDIR)) {
426 1.16 ws error = ENOTDIR;
427 1.16 ws goto out;
428 1.16 ws }
429 1.37 perry
430 1.16 ws /* allocate file system specific data structure */
431 1.16 ws newfd = alloc(sizeof(*newfd));
432 1.16 ws newfd->iodesc = currfd->iodesc;
433 1.16 ws newfd->off = 0;
434 1.37 perry
435 1.16 ws /*
436 1.16 ws * Get next component of path name.
437 1.16 ws */
438 1.16 ws {
439 1.29 augustss int len = 0;
440 1.37 perry
441 1.16 ws ncp = cp;
442 1.16 ws while ((c = *cp) != '\0' && c != '/') {
443 1.16 ws if (++len > NFS_MAXNAMLEN) {
444 1.16 ws error = ENOENT;
445 1.16 ws goto out;
446 1.16 ws }
447 1.16 ws cp++;
448 1.16 ws }
449 1.16 ws }
450 1.37 perry
451 1.16 ws /* lookup a file handle */
452 1.32 dsl error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd);
453 1.16 ws if (error)
454 1.16 ws goto out;
455 1.37 perry
456 1.16 ws /*
457 1.16 ws * Check for symbolic link
458 1.16 ws */
459 1.17 cgd if (newfd->fa.fa_type == htonl(NFLNK)) {
460 1.16 ws int link_len, len;
461 1.37 perry
462 1.16 ws error = nfs_readlink(newfd, linkbuf);
463 1.16 ws if (error)
464 1.16 ws goto out;
465 1.16 ws
466 1.16 ws link_len = strlen(linkbuf);
467 1.16 ws len = strlen(cp);
468 1.16 ws
469 1.16 ws if (link_len + len > MAXPATHLEN
470 1.16 ws || ++nlinks > MAXSYMLINKS) {
471 1.16 ws error = ENOENT;
472 1.16 ws goto out;
473 1.16 ws }
474 1.16 ws
475 1.43 christos (void)memcpy(&namebuf[link_len], cp, len + 1);
476 1.43 christos (void)memcpy(namebuf, linkbuf, link_len);
477 1.37 perry
478 1.16 ws /*
479 1.16 ws * If absolute pathname, restart at root.
480 1.16 ws * If relative pathname, restart at parent directory.
481 1.16 ws */
482 1.16 ws cp = namebuf;
483 1.16 ws if (*cp == '/') {
484 1.16 ws if (currfd != &nfs_root_node)
485 1.39 christos dealloc(currfd, sizeof(*currfd));
486 1.16 ws currfd = &nfs_root_node;
487 1.16 ws }
488 1.16 ws
489 1.39 christos dealloc(newfd, sizeof(*newfd));
490 1.16 ws newfd = 0;
491 1.37 perry
492 1.16 ws continue;
493 1.16 ws }
494 1.37 perry
495 1.16 ws if (currfd != &nfs_root_node)
496 1.39 christos dealloc(currfd, sizeof(*currfd));
497 1.16 ws currfd = newfd;
498 1.16 ws newfd = 0;
499 1.16 ws }
500 1.16 ws
501 1.16 ws error = 0;
502 1.1 brezak
503 1.16 ws out:
504 1.21 drochner #else
505 1.28 simonb /* allocate file system specific data structure */
506 1.28 simonb currfd = alloc(sizeof(*currfd));
507 1.28 simonb currfd->iodesc = nfs_root_node.iodesc;
508 1.28 simonb currfd->off = 0;
509 1.21 drochner
510 1.28 simonb cp = path;
511 1.28 simonb /*
512 1.28 simonb * Remove extra separators
513 1.28 simonb */
514 1.28 simonb while (*cp == '/')
515 1.28 simonb cp++;
516 1.28 simonb
517 1.28 simonb /* XXX: Check for empty path here? */
518 1.28 simonb
519 1.32 dsl error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd);
520 1.21 drochner #endif
521 1.12 gwr if (!error) {
522 1.16 ws f->f_fsdata = (void *)currfd;
523 1.42 isaki return 0;
524 1.1 brezak }
525 1.37 perry
526 1.1 brezak #ifdef NFS_DEBUG
527 1.1 brezak if (debug)
528 1.19 christos printf("nfs_open: %s lookupfh failed: %s\n",
529 1.18 christos path, strerror(error));
530 1.1 brezak #endif
531 1.16 ws if (currfd != &nfs_root_node)
532 1.39 christos dealloc(currfd, sizeof(*currfd));
533 1.16 ws if (newfd)
534 1.39 christos dealloc(newfd, sizeof(*newfd));
535 1.16 ws
536 1.42 isaki return error;
537 1.1 brezak }
538 1.1 brezak
539 1.1 brezak int
540 1.42 isaki nfs_close(struct open_file *f)
541 1.1 brezak {
542 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
543 1.1 brezak
544 1.1 brezak #ifdef NFS_DEBUG
545 1.1 brezak if (debug)
546 1.23 thorpej printf("nfs_close: fp=0x%lx\n", (u_long)fp);
547 1.1 brezak #endif
548 1.7 gwr
549 1.7 gwr if (fp)
550 1.39 christos dealloc(fp, sizeof(struct nfs_iodesc));
551 1.1 brezak f->f_fsdata = (void *)0;
552 1.37 perry
553 1.42 isaki return 0;
554 1.1 brezak }
555 1.1 brezak
556 1.1 brezak /*
557 1.1 brezak * read a portion of a file
558 1.1 brezak */
559 1.10 pk int
560 1.42 isaki nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
561 1.1 brezak {
562 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
563 1.29 augustss ssize_t cc;
564 1.29 augustss char *addr = buf;
565 1.37 perry
566 1.1 brezak #ifdef NFS_DEBUG
567 1.1 brezak if (debug)
568 1.23 thorpej printf("nfs_read: size=%lu off=%d\n", (u_long)size,
569 1.23 thorpej (int)fp->off);
570 1.1 brezak #endif
571 1.9 pk while ((int)size > 0) {
572 1.25 cgd #if !defined(LIBSA_NO_TWIDDLE)
573 1.7 gwr twiddle();
574 1.25 cgd #endif
575 1.7 gwr cc = nfs_readdata(fp, fp->off, (void *)addr, size);
576 1.6 mycroft /* XXX maybe should retry on certain errors */
577 1.6 mycroft if (cc == -1) {
578 1.6 mycroft #ifdef NFS_DEBUG
579 1.6 mycroft if (debug)
580 1.41 uwe printf("nfs_read: read: %s\n",
581 1.41 uwe strerror(errno));
582 1.1 brezak #endif
583 1.42 isaki return errno; /* XXX - from nfs_readdata */
584 1.6 mycroft }
585 1.6 mycroft if (cc == 0) {
586 1.20 pk #ifdef NFS_DEBUG
587 1.1 brezak if (debug)
588 1.41 uwe printf("nfs_read: hit EOF unexpectantly\n");
589 1.20 pk #endif
590 1.1 brezak goto ret;
591 1.1 brezak }
592 1.1 brezak fp->off += cc;
593 1.1 brezak addr += cc;
594 1.1 brezak size -= cc;
595 1.1 brezak }
596 1.1 brezak ret:
597 1.1 brezak if (resid)
598 1.1 brezak *resid = size;
599 1.1 brezak
600 1.42 isaki return 0;
601 1.1 brezak }
602 1.1 brezak
603 1.1 brezak /*
604 1.1 brezak * Not implemented.
605 1.1 brezak */
606 1.10 pk int
607 1.42 isaki nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
608 1.1 brezak {
609 1.42 isaki return EROFS;
610 1.1 brezak }
611 1.1 brezak
612 1.1 brezak off_t
613 1.42 isaki nfs_seek(struct open_file *f, off_t offset, int where)
614 1.1 brezak {
615 1.29 augustss struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
616 1.7 gwr n_long size = ntohl(d->fa.fa_size);
617 1.1 brezak
618 1.1 brezak switch (where) {
619 1.1 brezak case SEEK_SET:
620 1.7 gwr d->off = offset;
621 1.1 brezak break;
622 1.1 brezak case SEEK_CUR:
623 1.7 gwr d->off += offset;
624 1.1 brezak break;
625 1.1 brezak case SEEK_END:
626 1.7 gwr d->off = size - offset;
627 1.1 brezak break;
628 1.1 brezak default:
629 1.42 isaki return -1;
630 1.1 brezak }
631 1.7 gwr
632 1.42 isaki return d->off;
633 1.1 brezak }
634 1.1 brezak
635 1.7 gwr /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
636 1.31 mycroft const int nfs_stat_types[8] = {
637 1.7 gwr 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
638 1.7 gwr
639 1.1 brezak int
640 1.42 isaki nfs_stat(struct open_file *f, struct stat *sb)
641 1.1 brezak {
642 1.7 gwr struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
643 1.29 augustss n_long ftype, mode;
644 1.1 brezak
645 1.7 gwr ftype = ntohl(fp->fa.fa_type);
646 1.7 gwr mode = ntohl(fp->fa.fa_mode);
647 1.7 gwr mode |= nfs_stat_types[ftype & 7];
648 1.7 gwr
649 1.7 gwr sb->st_mode = mode;
650 1.7 gwr sb->st_nlink = ntohl(fp->fa.fa_nlink);
651 1.7 gwr sb->st_uid = ntohl(fp->fa.fa_uid);
652 1.7 gwr sb->st_gid = ntohl(fp->fa.fa_gid);
653 1.7 gwr sb->st_size = ntohl(fp->fa.fa_size);
654 1.1 brezak
655 1.42 isaki return 0;
656 1.1 brezak }
657