nfs.c revision 1.52 1 1.52 rin /* $NetBSD: nfs.c,v 1.52 2023/12/14 05:39:00 rin 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.51 mlelstv #include "nfsv3.h"
57 1.1 brezak
58 1.1 brezak #include "stand.h"
59 1.1 brezak #include "net.h"
60 1.1 brezak #include "nfs.h"
61 1.1 brezak #include "rpc.h"
62 1.1 brezak
63 1.51 mlelstv /* Storage for any filehandle (including length for V3) */
64 1.51 mlelstv #define NFS_FHSTORE (NFS_FHSIZE < NFS_V3FHSIZE ? NFS_V3FHSIZE + 4: NFS_FHSIZE)
65 1.1 brezak
66 1.1 brezak /* Data part of nfs rpc reply (also the largest thing we receive) */
67 1.7 gwr #define NFSREAD_SIZE 1024
68 1.1 brezak
69 1.21 drochner #ifndef NFS_NOSYMLINK
70 1.16 ws struct nfs_readlnk_repl {
71 1.16 ws n_long errno;
72 1.16 ws n_long len;
73 1.16 ws char path[NFS_MAXPATHLEN];
74 1.16 ws };
75 1.21 drochner #endif
76 1.16 ws
77 1.51 mlelstv static inline uint64_t
78 1.51 mlelstv getnquad(n_long x[2]) {
79 1.51 mlelstv return (uint64_t)ntohl(x[0]) << 32 | ntohl(x[1]);
80 1.51 mlelstv }
81 1.51 mlelstv
82 1.51 mlelstv static inline void
83 1.51 mlelstv setnquad(n_long x[2], uint64_t v)
84 1.51 mlelstv {
85 1.51 mlelstv x[0] = htonl((n_long)(v >> 32));
86 1.51 mlelstv x[1] = htonl((n_long)(v & 0xffffffff));
87 1.51 mlelstv }
88 1.51 mlelstv
89 1.1 brezak struct nfs_iodesc {
90 1.7 gwr struct iodesc *iodesc;
91 1.1 brezak off_t off;
92 1.51 mlelstv int version;
93 1.51 mlelstv u_char fh[NFS_FHSTORE];
94 1.51 mlelstv union {
95 1.51 mlelstv /* all in network order */
96 1.51 mlelstv struct nfsv2_fattr v2;
97 1.51 mlelstv struct nfsv3_fattr v3;
98 1.51 mlelstv } u_fa;
99 1.7 gwr };
100 1.7 gwr
101 1.51 mlelstv static inline size_t
102 1.51 mlelstv fhstore(int version, u_char *fh)
103 1.51 mlelstv {
104 1.51 mlelstv size_t len;
105 1.51 mlelstv
106 1.51 mlelstv switch (version) {
107 1.51 mlelstv case NFS_VER2:
108 1.51 mlelstv len = NFS_FHSIZE;
109 1.51 mlelstv break;
110 1.51 mlelstv case NFS_VER3:
111 1.51 mlelstv len = fh[0] << 24 | fh[1] << 16 | fh[2] << 8 | fh[3];
112 1.51 mlelstv if (len > NFS_V3FHSIZE)
113 1.51 mlelstv len = NFS_V3FHSIZE;
114 1.51 mlelstv len = 4 + roundup(len, 4);
115 1.51 mlelstv break;
116 1.51 mlelstv default:
117 1.51 mlelstv len = 0;
118 1.51 mlelstv break;
119 1.51 mlelstv }
120 1.51 mlelstv
121 1.51 mlelstv return len;
122 1.51 mlelstv }
123 1.51 mlelstv
124 1.51 mlelstv static inline size_t
125 1.51 mlelstv fhcopy(int version, u_char *src, u_char *dst)
126 1.51 mlelstv {
127 1.51 mlelstv size_t len = fhstore(version, src);
128 1.51 mlelstv memcpy(dst, src, len);
129 1.51 mlelstv return len;
130 1.51 mlelstv }
131 1.51 mlelstv
132 1.51 mlelstv #define setfh(d, s) fhcopy((d)->version, (s), (d)->fh)
133 1.51 mlelstv #define getfh(d, s) fhcopy((d)->version, (d)->fh, (s))
134 1.51 mlelstv
135 1.51 mlelstv
136 1.8 gwr struct nfs_iodesc nfs_root_node;
137 1.1 brezak
138 1.51 mlelstv int nfs_getrootfh(struct iodesc *, char *, u_char *, int *);
139 1.45 tsutsui int nfs_lookupfh(struct nfs_iodesc *, const char *, int,
140 1.45 tsutsui struct nfs_iodesc *);
141 1.45 tsutsui int nfs_readlink(struct nfs_iodesc *, char *);
142 1.45 tsutsui ssize_t nfs_readdata(struct nfs_iodesc *, off_t, void *, size_t);
143 1.7 gwr
144 1.12 gwr /*
145 1.12 gwr * Fetch the root file handle (call mount daemon)
146 1.12 gwr * On error, return non-zero and set errno.
147 1.12 gwr */
148 1.7 gwr int
149 1.51 mlelstv nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp, int *versionp)
150 1.1 brezak {
151 1.29 augustss int len;
152 1.7 gwr struct args {
153 1.7 gwr n_long len;
154 1.7 gwr char path[FNAME_SIZE];
155 1.7 gwr } *args;
156 1.7 gwr struct repl {
157 1.7 gwr n_long errno;
158 1.51 mlelstv u_char fh[NFS_FHSTORE];
159 1.7 gwr } *repl;
160 1.1 brezak struct {
161 1.7 gwr n_long h[RPC_HEADER_WORDS];
162 1.7 gwr struct args d;
163 1.7 gwr } sdata;
164 1.1 brezak struct {
165 1.7 gwr n_long h[RPC_HEADER_WORDS];
166 1.7 gwr struct repl d;
167 1.7 gwr } rdata;
168 1.33 fvdl ssize_t cc;
169 1.37 perry
170 1.1 brezak #ifdef NFS_DEBUG
171 1.1 brezak if (debug)
172 1.49 christos printf("%s: %s\n", __func__, path);
173 1.1 brezak #endif
174 1.6 mycroft
175 1.7 gwr args = &sdata.d;
176 1.7 gwr repl = &rdata.d;
177 1.7 gwr
178 1.43 christos (void)memset(args, 0, sizeof(*args));
179 1.1 brezak len = strlen(path);
180 1.33 fvdl if ((size_t)len > sizeof(args->path))
181 1.7 gwr len = sizeof(args->path);
182 1.7 gwr args->len = htonl(len);
183 1.43 christos (void)memcpy(args->path, path, len);
184 1.7 gwr len = 4 + roundup(len, 4);
185 1.7 gwr
186 1.51 mlelstv *versionp = NFS_VER3;
187 1.51 mlelstv cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
188 1.7 gwr args, len, repl, sizeof(*repl));
189 1.51 mlelstv if (cc == -1 || cc < 4 || repl->errno) {
190 1.51 mlelstv *versionp = NFS_VER2;
191 1.51 mlelstv cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
192 1.51 mlelstv args, len, repl, sizeof(*repl));
193 1.51 mlelstv }
194 1.12 gwr if (cc == -1) {
195 1.12 gwr /* errno was set by rpc_call */
196 1.42 isaki return -1;
197 1.12 gwr }
198 1.12 gwr if (cc < 4) {
199 1.12 gwr errno = EBADRPC;
200 1.42 isaki return -1;
201 1.12 gwr }
202 1.7 gwr if (repl->errno) {
203 1.7 gwr errno = ntohl(repl->errno);
204 1.42 isaki return -1;
205 1.1 brezak }
206 1.51 mlelstv fhcopy(*versionp, repl->fh, fhp);
207 1.42 isaki return 0;
208 1.1 brezak }
209 1.1 brezak
210 1.12 gwr /*
211 1.12 gwr * Lookup a file. Store handle and attributes.
212 1.12 gwr * Return zero or error number.
213 1.12 gwr */
214 1.7 gwr int
215 1.42 isaki nfs_lookupfh(struct nfs_iodesc *d, const char *name, int len,
216 1.42 isaki struct nfs_iodesc *newfd)
217 1.1 brezak {
218 1.51 mlelstv struct argsv2 {
219 1.1 brezak u_char fh[NFS_FHSIZE];
220 1.7 gwr n_long len;
221 1.1 brezak char name[FNAME_SIZE];
222 1.51 mlelstv } *argsv2;
223 1.51 mlelstv struct argsv3 {
224 1.51 mlelstv u_char fh[NFS_FHSTORE];
225 1.51 mlelstv n_long len;
226 1.51 mlelstv char name[FNAME_SIZE];
227 1.51 mlelstv } *argsv3;
228 1.51 mlelstv struct replv2 {
229 1.7 gwr n_long errno;
230 1.7 gwr u_char fh[NFS_FHSIZE];
231 1.51 mlelstv struct nfsv2_fattr fa;
232 1.51 mlelstv } *replv2;
233 1.51 mlelstv struct replv3 {
234 1.51 mlelstv n_long errno;
235 1.51 mlelstv u_char fh[NFS_FHSTORE];
236 1.51 mlelstv n_long fattrflag;
237 1.51 mlelstv struct nfsv3_fattr fa;
238 1.51 mlelstv n_long dattrflag;
239 1.51 mlelstv struct nfsv3_fattr da;
240 1.51 mlelstv } *replv3;
241 1.7 gwr struct {
242 1.7 gwr n_long h[RPC_HEADER_WORDS];
243 1.51 mlelstv union {
244 1.51 mlelstv struct argsv2 v2;
245 1.51 mlelstv struct argsv3 v3;
246 1.51 mlelstv } u_d;
247 1.7 gwr } sdata;
248 1.1 brezak struct {
249 1.7 gwr n_long h[RPC_HEADER_WORDS];
250 1.51 mlelstv union {
251 1.51 mlelstv struct replv2 v2;
252 1.51 mlelstv struct replv3 v3;
253 1.51 mlelstv } u_d;
254 1.7 gwr } rdata;
255 1.9 pk ssize_t cc;
256 1.51 mlelstv size_t alen;
257 1.37 perry
258 1.1 brezak #ifdef NFS_DEBUG
259 1.1 brezak if (debug)
260 1.49 christos printf("%s: called\n", __func__);
261 1.1 brezak #endif
262 1.1 brezak
263 1.51 mlelstv argsv2 = &sdata.u_d.v2;
264 1.51 mlelstv argsv3 = &sdata.u_d.v3;
265 1.51 mlelstv replv2 = &rdata.u_d.v2;
266 1.51 mlelstv replv3 = &rdata.u_d.v3;
267 1.51 mlelstv
268 1.51 mlelstv switch (d->version) {
269 1.51 mlelstv case NFS_VER2:
270 1.51 mlelstv (void)memset(argsv2, 0, sizeof(*argsv2));
271 1.51 mlelstv getfh(d, argsv2->fh);
272 1.51 mlelstv if ((size_t)len > sizeof(argsv2->name))
273 1.51 mlelstv len = sizeof(argsv2->name);
274 1.51 mlelstv (void)memcpy(argsv2->name, name, len);
275 1.51 mlelstv argsv2->len = htonl(len);
276 1.51 mlelstv
277 1.51 mlelstv /* padded name, name length */
278 1.51 mlelstv len = roundup(len, 4) + 4;
279 1.51 mlelstv /* filehandle size */
280 1.51 mlelstv alen = fhstore(d->version, argsv2->fh);
281 1.51 mlelstv
282 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
283 1.51 mlelstv argsv2, alen+len, replv2, sizeof(*replv2));
284 1.51 mlelstv break;
285 1.51 mlelstv case NFS_VER3:
286 1.51 mlelstv (void)memset(argsv3, 0, sizeof(*argsv3));
287 1.51 mlelstv getfh(d, argsv3->fh);
288 1.51 mlelstv if ((size_t)len > sizeof(argsv3->name))
289 1.51 mlelstv len = sizeof(argsv3->name);
290 1.51 mlelstv (void)memcpy(argsv3->name, name, len);
291 1.51 mlelstv argsv3->len = htonl(len);
292 1.51 mlelstv
293 1.51 mlelstv /* padded name, name length */
294 1.51 mlelstv len = roundup(len, 4) + 4;
295 1.51 mlelstv /* filehandle size */
296 1.51 mlelstv alen = fhstore(d->version, argsv3->fh);
297 1.7 gwr
298 1.51 mlelstv /* adjust for variable sized file handle */
299 1.51 mlelstv memmove(argsv3->fh + alen, &argsv3->len, len);
300 1.7 gwr
301 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSV3PROC_LOOKUP,
302 1.51 mlelstv argsv3, alen+len, replv3, sizeof(*replv3));
303 1.51 mlelstv break;
304 1.51 mlelstv default:
305 1.51 mlelstv return ENOSYS;
306 1.51 mlelstv }
307 1.7 gwr
308 1.12 gwr if (cc == -1)
309 1.42 isaki return errno; /* XXX - from rpc_call */
310 1.7 gwr if (cc < 4)
311 1.42 isaki return EIO;
312 1.51 mlelstv
313 1.51 mlelstv switch (d->version) {
314 1.51 mlelstv case NFS_VER2:
315 1.51 mlelstv if (replv2->errno) {
316 1.51 mlelstv /* saerrno.h now matches NFS error numbers. */
317 1.51 mlelstv return ntohl(replv2->errno);
318 1.51 mlelstv }
319 1.51 mlelstv
320 1.51 mlelstv setfh(newfd, replv2->fh);
321 1.51 mlelstv (void)memcpy(&newfd->u_fa.v2, &replv2->fa,
322 1.51 mlelstv sizeof(newfd->u_fa.v2));
323 1.51 mlelstv break;
324 1.51 mlelstv case NFS_VER3:
325 1.51 mlelstv if (replv3->errno) {
326 1.51 mlelstv /* saerrno.h now matches NFS error numbers. */
327 1.51 mlelstv return ntohl(replv3->errno);
328 1.51 mlelstv }
329 1.51 mlelstv
330 1.51 mlelstv setfh(newfd, replv3->fh);
331 1.51 mlelstv
332 1.51 mlelstv if (replv3->fattrflag) {
333 1.51 mlelstv (void)memcpy(&newfd->u_fa.v3, &replv3->fa,
334 1.51 mlelstv sizeof(newfd->u_fa.v3));
335 1.51 mlelstv }
336 1.51 mlelstv break;
337 1.1 brezak }
338 1.42 isaki return 0;
339 1.1 brezak }
340 1.1 brezak
341 1.21 drochner #ifndef NFS_NOSYMLINK
342 1.12 gwr /*
343 1.16 ws * Get the destination of a symbolic link.
344 1.16 ws */
345 1.16 ws int
346 1.42 isaki nfs_readlink(struct nfs_iodesc *d, char *buf)
347 1.16 ws {
348 1.16 ws struct {
349 1.16 ws n_long h[RPC_HEADER_WORDS];
350 1.51 mlelstv u_char fh[NFS_FHSTORE];
351 1.16 ws } sdata;
352 1.16 ws struct {
353 1.16 ws n_long h[RPC_HEADER_WORDS];
354 1.16 ws struct nfs_readlnk_repl d;
355 1.16 ws } rdata;
356 1.16 ws ssize_t cc;
357 1.16 ws
358 1.16 ws #ifdef NFS_DEBUG
359 1.16 ws if (debug)
360 1.49 christos printf("%s: called\n", __func__);
361 1.16 ws #endif
362 1.16 ws
363 1.51 mlelstv getfh(d, sdata.fh);
364 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READLINK,
365 1.51 mlelstv sdata.fh, fhstore(d->version, sdata.fh),
366 1.51 mlelstv &rdata.d, sizeof(rdata.d));
367 1.16 ws if (cc == -1)
368 1.42 isaki return errno;
369 1.16 ws
370 1.16 ws if (cc < 4)
371 1.42 isaki return EIO;
372 1.37 perry
373 1.16 ws if (rdata.d.errno)
374 1.42 isaki return ntohl(rdata.d.errno);
375 1.17 cgd
376 1.17 cgd rdata.d.len = ntohl(rdata.d.len);
377 1.16 ws if (rdata.d.len > NFS_MAXPATHLEN)
378 1.42 isaki return ENAMETOOLONG;
379 1.16 ws
380 1.43 christos (void)memcpy(buf, rdata.d.path, rdata.d.len);
381 1.16 ws buf[rdata.d.len] = 0;
382 1.42 isaki return 0;
383 1.16 ws }
384 1.21 drochner #endif
385 1.16 ws
386 1.16 ws /*
387 1.12 gwr * Read data from a file.
388 1.12 gwr * Return transfer count or -1 (and set errno)
389 1.12 gwr */
390 1.9 pk ssize_t
391 1.42 isaki nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
392 1.1 brezak {
393 1.51 mlelstv struct argsv2 {
394 1.51 mlelstv u_char fh[NFS_FHSIZE];
395 1.51 mlelstv n_long off;
396 1.51 mlelstv n_long len;
397 1.51 mlelstv n_long xxx; /* XXX what's this for? */
398 1.51 mlelstv } *argsv2;
399 1.51 mlelstv struct argsv3 {
400 1.51 mlelstv u_char fh[NFS_FHSTORE];
401 1.51 mlelstv n_long off[2];
402 1.51 mlelstv n_long len;
403 1.51 mlelstv } *argsv3;
404 1.51 mlelstv struct replv2 {
405 1.51 mlelstv n_long errno;
406 1.51 mlelstv struct nfsv2_fattr fa;
407 1.51 mlelstv n_long count;
408 1.51 mlelstv u_char data[NFSREAD_SIZE];
409 1.51 mlelstv } *replv2;
410 1.51 mlelstv struct replv3 {
411 1.51 mlelstv n_long errno;
412 1.51 mlelstv n_long attrflag;
413 1.51 mlelstv struct nfsv3_fattr fa;
414 1.51 mlelstv n_long count;
415 1.51 mlelstv n_long eof;
416 1.51 mlelstv n_long length;
417 1.51 mlelstv u_char data[NFSREAD_SIZE];
418 1.51 mlelstv } *replv3;
419 1.51 mlelstv struct replv3_noattr {
420 1.51 mlelstv n_long errno;
421 1.51 mlelstv n_long attrflag;
422 1.51 mlelstv n_long count;
423 1.51 mlelstv n_long eof;
424 1.51 mlelstv n_long length;
425 1.51 mlelstv u_char data[NFSREAD_SIZE];
426 1.51 mlelstv } *replv3no;
427 1.7 gwr struct {
428 1.7 gwr n_long h[RPC_HEADER_WORDS];
429 1.51 mlelstv union {
430 1.51 mlelstv struct argsv2 v2;
431 1.51 mlelstv struct argsv3 v3;
432 1.51 mlelstv } u_d;
433 1.7 gwr } sdata;
434 1.7 gwr struct {
435 1.7 gwr n_long h[RPC_HEADER_WORDS];
436 1.51 mlelstv union {
437 1.51 mlelstv struct replv2 v2;
438 1.51 mlelstv struct replv3 v3;
439 1.51 mlelstv } u_d;
440 1.7 gwr } rdata;
441 1.33 fvdl ssize_t cc;
442 1.9 pk long x;
443 1.51 mlelstv size_t hlen, rlen, alen;
444 1.51 mlelstv u_char *data;
445 1.7 gwr
446 1.51 mlelstv argsv2 = &sdata.u_d.v2;
447 1.51 mlelstv argsv3 = &sdata.u_d.v3;
448 1.51 mlelstv replv2 = &rdata.u_d.v2;
449 1.51 mlelstv replv3 = &rdata.u_d.v3;
450 1.6 mycroft
451 1.6 mycroft if (len > NFSREAD_SIZE)
452 1.6 mycroft len = NFSREAD_SIZE;
453 1.51 mlelstv
454 1.51 mlelstv switch (d->version) {
455 1.51 mlelstv case NFS_VER2:
456 1.51 mlelstv getfh(d, argsv2->fh);
457 1.51 mlelstv argsv2->off = htonl((n_long)off);
458 1.51 mlelstv argsv2->len = htonl((n_long)len);
459 1.51 mlelstv argsv2->xxx = htonl((n_long)0);
460 1.51 mlelstv hlen = sizeof(*replv2) - NFSREAD_SIZE;
461 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READ,
462 1.51 mlelstv argsv2, sizeof(*argsv2),
463 1.51 mlelstv replv2, sizeof(*replv2));
464 1.51 mlelstv break;
465 1.51 mlelstv case NFS_VER3:
466 1.51 mlelstv getfh(d, argsv3->fh);
467 1.51 mlelstv setnquad(argsv3->off, (uint64_t)off);
468 1.51 mlelstv argsv3->len = htonl((n_long)len);
469 1.51 mlelstv hlen = sizeof(*replv3) - NFSREAD_SIZE;
470 1.51 mlelstv
471 1.51 mlelstv /* adjust for variable sized file handle */
472 1.51 mlelstv alen = sizeof(*argsv3) - offsetof(struct argsv3, off);
473 1.51 mlelstv memmove(argsv3->fh + fhstore(d->version, argsv3->fh),
474 1.51 mlelstv &argsv3->off, alen);
475 1.51 mlelstv alen += fhstore(d->version, argsv3->fh);
476 1.51 mlelstv
477 1.51 mlelstv cc = rpc_call(d->iodesc, NFS_PROG, d->version, NFSPROC_READ,
478 1.51 mlelstv argsv3, alen,
479 1.51 mlelstv replv3, sizeof(*replv3));
480 1.51 mlelstv break;
481 1.51 mlelstv default:
482 1.51 mlelstv errno = ENOSYS;
483 1.51 mlelstv return -1;
484 1.51 mlelstv }
485 1.51 mlelstv
486 1.12 gwr if (cc == -1) {
487 1.12 gwr /* errno was already set by rpc_call */
488 1.42 isaki return -1;
489 1.12 gwr }
490 1.33 fvdl if (cc < (ssize_t)hlen) {
491 1.12 gwr errno = EBADRPC;
492 1.42 isaki return -1;
493 1.9 pk }
494 1.51 mlelstv
495 1.51 mlelstv switch (d->version) {
496 1.51 mlelstv case NFS_VER2:
497 1.51 mlelstv if (replv2->errno) {
498 1.51 mlelstv errno = ntohl(replv2->errno);
499 1.51 mlelstv return -1;
500 1.51 mlelstv }
501 1.51 mlelstv x = ntohl(replv2->count);
502 1.51 mlelstv data = replv2->data;
503 1.51 mlelstv break;
504 1.51 mlelstv case NFS_VER3:
505 1.51 mlelstv if (replv3->errno) {
506 1.51 mlelstv errno = ntohl(replv3->errno);
507 1.51 mlelstv return -1;
508 1.51 mlelstv }
509 1.51 mlelstv
510 1.51 mlelstv /* adjust for optional attributes */
511 1.51 mlelstv if (replv3->attrflag) {
512 1.51 mlelstv x = ntohl(replv3->length);
513 1.51 mlelstv data = replv3->data;
514 1.51 mlelstv } else {
515 1.51 mlelstv replv3no = (struct replv3_noattr *)replv3;
516 1.51 mlelstv x = ntohl(replv3no->length);
517 1.51 mlelstv data = replv3no->data;
518 1.51 mlelstv }
519 1.51 mlelstv break;
520 1.51 mlelstv default:
521 1.51 mlelstv errno = ENOSYS;
522 1.42 isaki return -1;
523 1.7 gwr }
524 1.51 mlelstv
525 1.7 gwr rlen = cc - hlen;
526 1.33 fvdl if (rlen < (size_t)x) {
527 1.49 christos printf("%s: short packet, %zu < %ld\n", __func__, rlen, x);
528 1.9 pk errno = EBADRPC;
529 1.42 isaki return -1;
530 1.7 gwr }
531 1.51 mlelstv (void)memcpy(addr, data, x);
532 1.42 isaki return x;
533 1.1 brezak }
534 1.1 brezak
535 1.1 brezak /*
536 1.1 brezak * nfs_mount - mount this nfs filesystem to a host
537 1.12 gwr * On error, return non-zero and set errno.
538 1.1 brezak */
539 1.1 brezak int
540 1.42 isaki nfs_mount(int sock, struct in_addr ip, char *path)
541 1.1 brezak {
542 1.1 brezak struct iodesc *desc;
543 1.51 mlelstv struct nfsv2_fattr *fa2;
544 1.51 mlelstv struct nfsv3_fattr *fa3;
545 1.7 gwr
546 1.1 brezak if (!(desc = socktodesc(sock))) {
547 1.1 brezak errno = EINVAL;
548 1.42 isaki return -1;
549 1.1 brezak }
550 1.7 gwr
551 1.7 gwr /* Bind to a reserved port. */
552 1.7 gwr desc->myport = htons(--rpc_port);
553 1.1 brezak desc->destip = ip;
554 1.51 mlelstv if (nfs_getrootfh(desc, path, nfs_root_node.fh, &nfs_root_node.version))
555 1.42 isaki return -1;
556 1.7 gwr nfs_root_node.iodesc = desc;
557 1.8 gwr /* Fake up attributes for the root dir. */
558 1.51 mlelstv switch (nfs_root_node.version) {
559 1.51 mlelstv case NFS_VER2:
560 1.51 mlelstv fa2 = &nfs_root_node.u_fa.v2;
561 1.51 mlelstv fa2->fa_type = htonl(NFDIR);
562 1.51 mlelstv fa2->fa_mode = htonl(0755);
563 1.51 mlelstv fa2->fa_nlink = htonl(2);
564 1.51 mlelstv break;
565 1.51 mlelstv case NFS_VER3:
566 1.51 mlelstv fa3 = &nfs_root_node.u_fa.v3;
567 1.51 mlelstv fa3->fa_type = htonl(NFDIR);
568 1.51 mlelstv fa3->fa_mode = htonl(0755);
569 1.51 mlelstv fa3->fa_nlink = htonl(2);
570 1.51 mlelstv break;
571 1.51 mlelstv default:
572 1.51 mlelstv errno = ENOSYS;
573 1.51 mlelstv return -1;
574 1.51 mlelstv }
575 1.1 brezak
576 1.1 brezak #ifdef NFS_DEBUG
577 1.1 brezak if (debug)
578 1.49 christos printf("%s: got fh for %s\n", __func__, path);
579 1.1 brezak #endif
580 1.1 brezak
581 1.42 isaki return 0;
582 1.1 brezak }
583 1.1 brezak
584 1.1 brezak /*
585 1.1 brezak * Open a file.
586 1.12 gwr * return zero or error number
587 1.1 brezak */
588 1.46 joerg __compactcall int
589 1.42 isaki nfs_open(const char *path, struct open_file *f)
590 1.1 brezak {
591 1.16 ws struct nfs_iodesc *newfd, *currfd;
592 1.32 dsl const char *cp;
593 1.21 drochner #ifndef NFS_NOSYMLINK
594 1.32 dsl const char *ncp;
595 1.29 augustss int c;
596 1.16 ws char namebuf[NFS_MAXPATHLEN + 1];
597 1.16 ws char linkbuf[NFS_MAXPATHLEN + 1];
598 1.16 ws int nlinks = 0;
599 1.52 rin n_long fa_type;
600 1.21 drochner #endif
601 1.12 gwr int error = 0;
602 1.1 brezak
603 1.1 brezak #ifdef NFS_DEBUG
604 1.1 brezak if (debug)
605 1.49 christos printf("%s: %s\n", __func__, path);
606 1.1 brezak #endif
607 1.51 mlelstv
608 1.7 gwr if (nfs_root_node.iodesc == NULL) {
609 1.49 christos printf("%s: must mount first.\n", __func__);
610 1.42 isaki return ENXIO;
611 1.1 brezak }
612 1.1 brezak
613 1.16 ws currfd = &nfs_root_node;
614 1.16 ws newfd = 0;
615 1.21 drochner
616 1.21 drochner #ifndef NFS_NOSYMLINK
617 1.16 ws cp = path;
618 1.16 ws while (*cp) {
619 1.16 ws /*
620 1.16 ws * Remove extra separators
621 1.16 ws */
622 1.16 ws while (*cp == '/')
623 1.16 ws cp++;
624 1.16 ws
625 1.16 ws if (*cp == '\0')
626 1.16 ws break;
627 1.16 ws /*
628 1.16 ws * Check that current node is a directory.
629 1.16 ws */
630 1.51 mlelstv switch (currfd->version) {
631 1.51 mlelstv case NFS_VER2:
632 1.51 mlelstv fa_type = currfd->u_fa.v2.fa_type;
633 1.51 mlelstv break;
634 1.51 mlelstv case NFS_VER3:
635 1.51 mlelstv fa_type = currfd->u_fa.v3.fa_type;
636 1.51 mlelstv break;
637 1.51 mlelstv default:
638 1.51 mlelstv fa_type = htonl(NFNON);
639 1.51 mlelstv break;
640 1.51 mlelstv }
641 1.51 mlelstv if (fa_type != htonl(NFDIR)) {
642 1.16 ws error = ENOTDIR;
643 1.16 ws goto out;
644 1.16 ws }
645 1.37 perry
646 1.16 ws /* allocate file system specific data structure */
647 1.16 ws newfd = alloc(sizeof(*newfd));
648 1.16 ws newfd->iodesc = currfd->iodesc;
649 1.16 ws newfd->off = 0;
650 1.51 mlelstv newfd->version = currfd->version;
651 1.37 perry
652 1.16 ws /*
653 1.16 ws * Get next component of path name.
654 1.16 ws */
655 1.16 ws {
656 1.29 augustss int len = 0;
657 1.37 perry
658 1.16 ws ncp = cp;
659 1.16 ws while ((c = *cp) != '\0' && c != '/') {
660 1.16 ws if (++len > NFS_MAXNAMLEN) {
661 1.16 ws error = ENOENT;
662 1.16 ws goto out;
663 1.16 ws }
664 1.16 ws cp++;
665 1.16 ws }
666 1.16 ws }
667 1.37 perry
668 1.16 ws /* lookup a file handle */
669 1.32 dsl error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd);
670 1.16 ws if (error)
671 1.16 ws goto out;
672 1.37 perry
673 1.16 ws /*
674 1.16 ws * Check for symbolic link
675 1.16 ws */
676 1.51 mlelstv switch (newfd->version) {
677 1.51 mlelstv case NFS_VER2:
678 1.51 mlelstv fa_type = newfd->u_fa.v2.fa_type;
679 1.51 mlelstv break;
680 1.51 mlelstv case NFS_VER3:
681 1.51 mlelstv fa_type = newfd->u_fa.v3.fa_type;
682 1.51 mlelstv break;
683 1.51 mlelstv default:
684 1.51 mlelstv fa_type = htonl(NFNON);
685 1.51 mlelstv break;
686 1.51 mlelstv }
687 1.51 mlelstv if (fa_type == htonl(NFLNK)) {
688 1.16 ws int link_len, len;
689 1.37 perry
690 1.16 ws error = nfs_readlink(newfd, linkbuf);
691 1.16 ws if (error)
692 1.16 ws goto out;
693 1.16 ws
694 1.16 ws link_len = strlen(linkbuf);
695 1.16 ws len = strlen(cp);
696 1.16 ws
697 1.16 ws if (link_len + len > MAXPATHLEN
698 1.16 ws || ++nlinks > MAXSYMLINKS) {
699 1.16 ws error = ENOENT;
700 1.16 ws goto out;
701 1.16 ws }
702 1.16 ws
703 1.43 christos (void)memcpy(&namebuf[link_len], cp, len + 1);
704 1.43 christos (void)memcpy(namebuf, linkbuf, link_len);
705 1.37 perry
706 1.16 ws /*
707 1.16 ws * If absolute pathname, restart at root.
708 1.16 ws * If relative pathname, restart at parent directory.
709 1.16 ws */
710 1.16 ws cp = namebuf;
711 1.16 ws if (*cp == '/') {
712 1.16 ws if (currfd != &nfs_root_node)
713 1.39 christos dealloc(currfd, sizeof(*currfd));
714 1.16 ws currfd = &nfs_root_node;
715 1.16 ws }
716 1.16 ws
717 1.39 christos dealloc(newfd, sizeof(*newfd));
718 1.16 ws newfd = 0;
719 1.37 perry
720 1.16 ws continue;
721 1.16 ws }
722 1.37 perry
723 1.16 ws if (currfd != &nfs_root_node)
724 1.39 christos dealloc(currfd, sizeof(*currfd));
725 1.16 ws currfd = newfd;
726 1.16 ws newfd = 0;
727 1.16 ws }
728 1.16 ws
729 1.16 ws error = 0;
730 1.1 brezak
731 1.16 ws out:
732 1.21 drochner #else
733 1.28 simonb /* allocate file system specific data structure */
734 1.28 simonb currfd = alloc(sizeof(*currfd));
735 1.28 simonb currfd->iodesc = nfs_root_node.iodesc;
736 1.28 simonb currfd->off = 0;
737 1.51 mlelstv currfd->version = nfs_root_node.version;
738 1.21 drochner
739 1.28 simonb cp = path;
740 1.28 simonb /*
741 1.28 simonb * Remove extra separators
742 1.28 simonb */
743 1.28 simonb while (*cp == '/')
744 1.28 simonb cp++;
745 1.28 simonb
746 1.28 simonb /* XXX: Check for empty path here? */
747 1.28 simonb
748 1.32 dsl error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd);
749 1.21 drochner #endif
750 1.12 gwr if (!error) {
751 1.16 ws f->f_fsdata = (void *)currfd;
752 1.44 ad fsmod = "nfs";
753 1.42 isaki return 0;
754 1.1 brezak }
755 1.37 perry
756 1.1 brezak #ifdef NFS_DEBUG
757 1.1 brezak if (debug)
758 1.49 christos printf("%s: %s lookupfh failed: %s\n", __func__,
759 1.18 christos path, strerror(error));
760 1.1 brezak #endif
761 1.16 ws if (currfd != &nfs_root_node)
762 1.39 christos dealloc(currfd, sizeof(*currfd));
763 1.16 ws if (newfd)
764 1.39 christos dealloc(newfd, sizeof(*newfd));
765 1.16 ws
766 1.42 isaki return error;
767 1.1 brezak }
768 1.1 brezak
769 1.46 joerg __compactcall int
770 1.42 isaki nfs_close(struct open_file *f)
771 1.1 brezak {
772 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
773 1.1 brezak
774 1.1 brezak #ifdef NFS_DEBUG
775 1.1 brezak if (debug)
776 1.49 christos printf("%s: fp=%p\n", __func__, fp);
777 1.1 brezak #endif
778 1.7 gwr
779 1.7 gwr if (fp)
780 1.39 christos dealloc(fp, sizeof(struct nfs_iodesc));
781 1.1 brezak f->f_fsdata = (void *)0;
782 1.37 perry
783 1.42 isaki return 0;
784 1.1 brezak }
785 1.1 brezak
786 1.1 brezak /*
787 1.1 brezak * read a portion of a file
788 1.1 brezak */
789 1.46 joerg __compactcall int
790 1.42 isaki nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
791 1.1 brezak {
792 1.29 augustss struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
793 1.29 augustss ssize_t cc;
794 1.29 augustss char *addr = buf;
795 1.37 perry
796 1.1 brezak #ifdef NFS_DEBUG
797 1.1 brezak if (debug)
798 1.50 skrll printf("%s: size=%zu off=%" PRIx64 "\n", __func__, size, fp->off);
799 1.1 brezak #endif
800 1.9 pk while ((int)size > 0) {
801 1.25 cgd #if !defined(LIBSA_NO_TWIDDLE)
802 1.7 gwr twiddle();
803 1.25 cgd #endif
804 1.7 gwr cc = nfs_readdata(fp, fp->off, (void *)addr, size);
805 1.6 mycroft /* XXX maybe should retry on certain errors */
806 1.6 mycroft if (cc == -1) {
807 1.6 mycroft #ifdef NFS_DEBUG
808 1.6 mycroft if (debug)
809 1.49 christos printf("%s: read: %s\n", __func__,
810 1.49 christos strerror(errno));
811 1.1 brezak #endif
812 1.42 isaki return errno; /* XXX - from nfs_readdata */
813 1.6 mycroft }
814 1.6 mycroft if (cc == 0) {
815 1.20 pk #ifdef NFS_DEBUG
816 1.1 brezak if (debug)
817 1.49 christos printf("%s: hit EOF unexpectedly\n", __func__);
818 1.20 pk #endif
819 1.1 brezak goto ret;
820 1.1 brezak }
821 1.1 brezak fp->off += cc;
822 1.1 brezak addr += cc;
823 1.1 brezak size -= cc;
824 1.1 brezak }
825 1.1 brezak ret:
826 1.1 brezak if (resid)
827 1.1 brezak *resid = size;
828 1.1 brezak
829 1.42 isaki return 0;
830 1.1 brezak }
831 1.1 brezak
832 1.1 brezak /*
833 1.1 brezak * Not implemented.
834 1.1 brezak */
835 1.46 joerg __compactcall int
836 1.42 isaki nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
837 1.1 brezak {
838 1.42 isaki return EROFS;
839 1.1 brezak }
840 1.1 brezak
841 1.46 joerg __compactcall off_t
842 1.42 isaki nfs_seek(struct open_file *f, off_t offset, int where)
843 1.1 brezak {
844 1.29 augustss struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
845 1.51 mlelstv off_t size;
846 1.51 mlelstv
847 1.51 mlelstv switch (d->version) {
848 1.51 mlelstv case NFS_VER2:
849 1.51 mlelstv size = ntohl(d->u_fa.v2.fa_size);
850 1.51 mlelstv break;
851 1.51 mlelstv case NFS_VER3:
852 1.51 mlelstv size = getnquad(d->u_fa.v3.fa_size);
853 1.51 mlelstv break;
854 1.51 mlelstv default:
855 1.51 mlelstv return -1;
856 1.51 mlelstv }
857 1.1 brezak
858 1.1 brezak switch (where) {
859 1.1 brezak case SEEK_SET:
860 1.7 gwr d->off = offset;
861 1.1 brezak break;
862 1.1 brezak case SEEK_CUR:
863 1.7 gwr d->off += offset;
864 1.1 brezak break;
865 1.1 brezak case SEEK_END:
866 1.7 gwr d->off = size - offset;
867 1.1 brezak break;
868 1.1 brezak default:
869 1.42 isaki return -1;
870 1.1 brezak }
871 1.7 gwr
872 1.42 isaki return d->off;
873 1.1 brezak }
874 1.1 brezak
875 1.7 gwr /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
876 1.31 mycroft const int nfs_stat_types[8] = {
877 1.7 gwr 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
878 1.7 gwr
879 1.46 joerg __compactcall int
880 1.42 isaki nfs_stat(struct open_file *f, struct stat *sb)
881 1.1 brezak {
882 1.7 gwr struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
883 1.29 augustss n_long ftype, mode;
884 1.1 brezak
885 1.51 mlelstv switch (fp->version) {
886 1.51 mlelstv case NFS_VER2:
887 1.51 mlelstv ftype = ntohl(fp->u_fa.v2.fa_type);
888 1.51 mlelstv mode = ntohl(fp->u_fa.v2.fa_mode);
889 1.51 mlelstv sb->st_nlink = ntohl(fp->u_fa.v2.fa_nlink);
890 1.51 mlelstv sb->st_uid = ntohl(fp->u_fa.v2.fa_uid);
891 1.51 mlelstv sb->st_gid = ntohl(fp->u_fa.v2.fa_gid);
892 1.51 mlelstv sb->st_size = ntohl(fp->u_fa.v2.fa_size);
893 1.51 mlelstv break;
894 1.51 mlelstv case NFS_VER3:
895 1.51 mlelstv ftype = ntohl(fp->u_fa.v3.fa_type);
896 1.51 mlelstv mode = ntohl(fp->u_fa.v3.fa_mode);
897 1.51 mlelstv sb->st_nlink = ntohl(fp->u_fa.v3.fa_nlink);
898 1.51 mlelstv sb->st_uid = ntohl(fp->u_fa.v3.fa_uid);
899 1.51 mlelstv sb->st_gid = ntohl(fp->u_fa.v3.fa_gid);
900 1.51 mlelstv sb->st_size = getnquad(fp->u_fa.v3.fa_size);
901 1.51 mlelstv break;
902 1.51 mlelstv default:
903 1.51 mlelstv return -1;
904 1.51 mlelstv }
905 1.51 mlelstv
906 1.7 gwr mode |= nfs_stat_types[ftype & 7];
907 1.7 gwr sb->st_mode = mode;
908 1.1 brezak
909 1.42 isaki return 0;
910 1.1 brezak }
911 1.47 tsutsui
912 1.47 tsutsui #if defined(LIBSA_ENABLE_LS_OP)
913 1.48 christos #include "ls.h"
914 1.47 tsutsui __compactcall void
915 1.47 tsutsui nfs_ls(struct open_file *f, const char *pattern)
916 1.47 tsutsui {
917 1.48 christos lsunsup("nfs");
918 1.47 tsutsui }
919 1.47 tsutsui #endif
920