Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/nfs.c
34677 views
1
/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
2
3
/*-
4
* Copyright (c) 1993 John Brezak
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
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.
17
*
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.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/time.h>
33
#include <sys/socket.h>
34
#include <sys/stat.h>
35
#include <string.h>
36
#include <stddef.h>
37
38
#include <netinet/in.h>
39
#include <netinet/in_systm.h>
40
41
#include "rpcv2.h"
42
#include "nfsv2.h"
43
44
#include "stand.h"
45
#include "net.h"
46
#include "netif.h"
47
#include "rpc.h"
48
49
#define NFS_DEBUGxx
50
51
#define NFSREAD_MIN_SIZE 1024
52
#define NFSREAD_MAX_SIZE 16384
53
54
/* NFSv3 definitions */
55
#define NFS_V3MAXFHSIZE 64
56
#define NFS_VER3 3
57
#define RPCMNT_VER3 3
58
#define NFSPROCV3_LOOKUP 3
59
#define NFSPROCV3_READLINK 5
60
#define NFSPROCV3_READ 6
61
#define NFSPROCV3_READDIR 16
62
63
typedef struct {
64
uint32_t val[2];
65
} n_quad;
66
67
struct nfsv3_time {
68
uint32_t nfs_sec;
69
uint32_t nfs_nsec;
70
};
71
72
struct nfsv3_fattrs {
73
uint32_t fa_type;
74
uint32_t fa_mode;
75
uint32_t fa_nlink;
76
uint32_t fa_uid;
77
uint32_t fa_gid;
78
n_quad fa_size;
79
n_quad fa_used;
80
n_quad fa_rdev;
81
n_quad fa_fsid;
82
n_quad fa_fileid;
83
struct nfsv3_time fa_atime;
84
struct nfsv3_time fa_mtime;
85
struct nfsv3_time fa_ctime;
86
};
87
88
/*
89
* For NFSv3, the file handle is variable in size, so most fixed sized
90
* structures for arguments won't work. For most cases, a structure
91
* that starts with any fixed size section is followed by an array
92
* that covers the maximum size required.
93
*/
94
struct nfsv3_readdir_repl {
95
uint32_t errno;
96
uint32_t ok;
97
struct nfsv3_fattrs fa;
98
uint32_t cookiev0;
99
uint32_t cookiev1;
100
};
101
102
struct nfsv3_readdir_entry {
103
uint32_t follows;
104
uint32_t fid0;
105
uint32_t fid1;
106
uint32_t len;
107
uint32_t nameplus[0];
108
};
109
110
struct nfs_iodesc {
111
struct iodesc *iodesc;
112
off_t off;
113
uint32_t fhsize;
114
u_char fh[NFS_V3MAXFHSIZE];
115
struct nfsv3_fattrs fa; /* all in network order */
116
uint64_t cookie;
117
};
118
119
/*
120
* XXX interactions with tftp? See nfswrapper.c for a confusing
121
* issue.
122
*/
123
int nfs_open(const char *path, struct open_file *f);
124
static int nfs_close(struct open_file *f);
125
static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
126
static off_t nfs_seek(struct open_file *f, off_t offset, int where);
127
static int nfs_stat(struct open_file *f, struct stat *sb);
128
static int nfs_readdir(struct open_file *f, struct dirent *d);
129
130
struct nfs_iodesc nfs_root_node;
131
132
struct fs_ops nfs_fsops = {
133
.fs_name = "nfs",
134
.fs_flags = 0,
135
.fo_open = nfs_open,
136
.fo_close = nfs_close,
137
.fo_read = nfs_read,
138
.fo_write = null_write,
139
.fo_seek = nfs_seek,
140
.fo_stat = nfs_stat,
141
.fo_readdir = nfs_readdir,
142
};
143
144
static int nfs_read_size = NFSREAD_MIN_SIZE;
145
146
/*
147
* Improve boot performance over NFS
148
*/
149
static void
150
set_nfs_read_size(void)
151
{
152
char *env, *end;
153
char buf[10];
154
155
if ((env = getenv("nfs.read_size")) != NULL) {
156
errno = 0;
157
nfs_read_size = (int)strtol(env, &end, 0);
158
if (errno != 0 || *env == '\0' || *end != '\0') {
159
printf("%s: bad value: \"%s\", defaulting to %d\n",
160
"nfs.read_size", env, NFSREAD_MIN_SIZE);
161
nfs_read_size = NFSREAD_MIN_SIZE;
162
}
163
}
164
if (nfs_read_size < NFSREAD_MIN_SIZE) {
165
printf("%s: bad value: \"%d\", defaulting to %d\n",
166
"nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
167
nfs_read_size = NFSREAD_MIN_SIZE;
168
}
169
if (nfs_read_size > NFSREAD_MAX_SIZE) {
170
printf("%s: bad value: \"%d\", defaulting to %d\n",
171
"nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
172
nfs_read_size = NFSREAD_MAX_SIZE;
173
}
174
snprintf(buf, sizeof (buf), "%d", nfs_read_size);
175
setenv("nfs.read_size", buf, 1);
176
}
177
178
/*
179
* Fetch the root file handle (call mount daemon)
180
* Return zero or error number.
181
*/
182
int
183
nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
184
{
185
void *pkt = NULL;
186
int len;
187
struct args {
188
uint32_t len;
189
char path[FNAME_SIZE];
190
} *args;
191
struct repl {
192
uint32_t errno;
193
uint32_t fhsize;
194
u_char fh[NFS_V3MAXFHSIZE];
195
uint32_t authcnt;
196
uint32_t auth[7];
197
} *repl;
198
struct {
199
uint32_t h[RPC_HEADER_WORDS];
200
struct args d;
201
} sdata;
202
size_t cc;
203
204
#ifdef NFS_DEBUG
205
if (debug)
206
printf("nfs_getrootfh: %s\n", path);
207
#endif
208
209
args = &sdata.d;
210
211
bzero(args, sizeof(*args));
212
len = strlen(path);
213
if (len > sizeof(args->path))
214
len = sizeof(args->path);
215
args->len = htonl(len);
216
bcopy(path, args->path, len);
217
len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
218
219
cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
220
args, len, (void **)&repl, &pkt);
221
if (cc == -1) {
222
free(pkt);
223
/* errno was set by rpc_call */
224
return (errno);
225
}
226
if (cc < 2 * sizeof (uint32_t)) {
227
free(pkt);
228
return (EBADRPC);
229
}
230
if (repl->errno != 0) {
231
free(pkt);
232
return (ntohl(repl->errno));
233
}
234
*fhlenp = ntohl(repl->fhsize);
235
bcopy(repl->fh, fhp, *fhlenp);
236
237
set_nfs_read_size();
238
free(pkt);
239
return (0);
240
}
241
242
/*
243
* Lookup a file. Store handle and attributes.
244
* Return zero or error number.
245
*/
246
int
247
nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
248
{
249
void *pkt = NULL;
250
int len, pos;
251
struct args {
252
uint32_t fhsize;
253
uint32_t fhplusname[1 +
254
(NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
255
} *args;
256
struct repl {
257
uint32_t errno;
258
uint32_t fhsize;
259
uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
260
2 * (sizeof(uint32_t) +
261
sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
262
} *repl;
263
struct {
264
uint32_t h[RPC_HEADER_WORDS];
265
struct args d;
266
} sdata;
267
ssize_t cc;
268
269
#ifdef NFS_DEBUG
270
if (debug)
271
printf("lookupfh: called\n");
272
#endif
273
274
args = &sdata.d;
275
276
bzero(args, sizeof(*args));
277
args->fhsize = htonl(d->fhsize);
278
bcopy(d->fh, args->fhplusname, d->fhsize);
279
len = strlen(name);
280
if (len > FNAME_SIZE)
281
len = FNAME_SIZE;
282
pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
283
args->fhplusname[pos++] = htonl(len);
284
bcopy(name, &args->fhplusname[pos], len);
285
len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
286
roundup(len, sizeof(uint32_t));
287
288
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
289
args, len, (void **)&repl, &pkt);
290
if (cc == -1) {
291
free(pkt);
292
return (errno); /* XXX - from rpc_call */
293
}
294
if (cc < 2 * sizeof(uint32_t)) {
295
free(pkt);
296
return (EIO);
297
}
298
if (repl->errno != 0) {
299
free(pkt);
300
/* saerrno.h now matches NFS error numbers. */
301
return (ntohl(repl->errno));
302
}
303
newfd->fhsize = ntohl(repl->fhsize);
304
bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
305
pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
306
if (repl->fhplusattr[pos++] == 0) {
307
free(pkt);
308
return (EIO);
309
}
310
bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
311
free(pkt);
312
return (0);
313
}
314
315
#ifndef NFS_NOSYMLINK
316
/*
317
* Get the destination of a symbolic link.
318
*/
319
int
320
nfs_readlink(struct nfs_iodesc *d, char *buf)
321
{
322
void *pkt = NULL;
323
struct args {
324
uint32_t fhsize;
325
u_char fh[NFS_V3MAXFHSIZE];
326
} *args;
327
struct repl {
328
uint32_t errno;
329
uint32_t ok;
330
struct nfsv3_fattrs fa;
331
uint32_t len;
332
u_char path[NFS_MAXPATHLEN];
333
} *repl;
334
struct {
335
uint32_t h[RPC_HEADER_WORDS];
336
struct args d;
337
} sdata;
338
ssize_t cc;
339
int rc = 0;
340
341
#ifdef NFS_DEBUG
342
if (debug)
343
printf("readlink: called\n");
344
#endif
345
346
args = &sdata.d;
347
348
bzero(args, sizeof(*args));
349
args->fhsize = htonl(d->fhsize);
350
bcopy(d->fh, args->fh, d->fhsize);
351
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
352
args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
353
(void **)&repl, &pkt);
354
if (cc == -1)
355
return (errno);
356
357
if (cc < 2 * sizeof(uint32_t)) {
358
rc = EIO;
359
goto done;
360
}
361
362
if (repl->errno != 0) {
363
rc = ntohl(repl->errno);
364
goto done;
365
}
366
367
if (repl->ok == 0) {
368
rc = EIO;
369
goto done;
370
}
371
372
repl->len = ntohl(repl->len);
373
if (repl->len > NFS_MAXPATHLEN) {
374
rc = ENAMETOOLONG;
375
goto done;
376
}
377
378
bcopy(repl->path, buf, repl->len);
379
buf[repl->len] = 0;
380
done:
381
free(pkt);
382
return (rc);
383
}
384
#endif
385
386
/*
387
* Read data from a file.
388
* Return transfer count or -1 (and set errno)
389
*/
390
ssize_t
391
nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
392
{
393
void *pkt = NULL;
394
struct args {
395
uint32_t fhsize;
396
uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
397
} *args;
398
struct repl {
399
uint32_t errno;
400
uint32_t ok;
401
struct nfsv3_fattrs fa;
402
uint32_t count;
403
uint32_t eof;
404
uint32_t len;
405
u_char data[NFSREAD_MAX_SIZE];
406
} *repl;
407
struct {
408
uint32_t h[RPC_HEADER_WORDS];
409
struct args d;
410
} sdata;
411
size_t cc;
412
long x;
413
int hlen, rlen, pos;
414
415
args = &sdata.d;
416
417
bzero(args, sizeof(*args));
418
args->fhsize = htonl(d->fhsize);
419
bcopy(d->fh, args->fhoffcnt, d->fhsize);
420
pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
421
args->fhoffcnt[pos++] = 0;
422
args->fhoffcnt[pos++] = htonl((uint32_t)off);
423
if (len > nfs_read_size)
424
len = nfs_read_size;
425
args->fhoffcnt[pos] = htonl((uint32_t)len);
426
hlen = offsetof(struct repl, data[0]);
427
428
cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
429
args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
430
(void **)&repl, &pkt);
431
if (cc == -1) {
432
/* errno was already set by rpc_call */
433
return (-1);
434
}
435
if (cc < hlen) {
436
errno = EBADRPC;
437
free(pkt);
438
return (-1);
439
}
440
if (repl->errno != 0) {
441
errno = ntohl(repl->errno);
442
free(pkt);
443
return (-1);
444
}
445
rlen = cc - hlen;
446
x = ntohl(repl->count);
447
if (rlen < x) {
448
printf("nfsread: short packet, %d < %ld\n", rlen, x);
449
errno = EBADRPC;
450
free(pkt);
451
return (-1);
452
}
453
bcopy(repl->data, addr, x);
454
free(pkt);
455
return (x);
456
}
457
458
/*
459
* Open a file.
460
* return zero or error number
461
*/
462
int
463
nfs_open(const char *upath, struct open_file *f)
464
{
465
struct devdesc *dev;
466
struct iodesc *desc;
467
struct nfs_iodesc *currfd = NULL;
468
char buf[2 * NFS_V3MAXFHSIZE + 3];
469
u_char *fh;
470
char *cp;
471
int i;
472
#ifndef NFS_NOSYMLINK
473
struct nfs_iodesc *newfd = NULL;
474
char *ncp;
475
int c;
476
char namebuf[NFS_MAXPATHLEN + 1];
477
char linkbuf[NFS_MAXPATHLEN + 1];
478
int nlinks = 0;
479
#endif
480
int error;
481
char *path = NULL;
482
483
if (netproto != NET_NFS)
484
return (EINVAL);
485
486
dev = f->f_devdata;
487
#ifdef NFS_DEBUG
488
if (debug)
489
printf("nfs_open: %s (rootip=%s rootpath=%s)\n", upath,
490
inet_ntoa(rootip), rootpath);
491
#endif
492
if (!rootpath[0]) {
493
printf("no rootpath, no nfs\n");
494
return (ENXIO);
495
}
496
497
if (f->f_dev->dv_type != DEVT_NET)
498
return (EINVAL);
499
500
if (!(desc = socktodesc(*(int *)(dev->d_opendata))))
501
return (EINVAL);
502
503
/* Bind to a reserved port. */
504
desc->myport = htons(--rpc_port);
505
desc->destip = rootip;
506
if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
507
nfs_root_node.fh)))
508
return (error);
509
nfs_root_node.fa.fa_type = htonl(NFDIR);
510
nfs_root_node.fa.fa_mode = htonl(0755);
511
nfs_root_node.fa.fa_nlink = htonl(2);
512
nfs_root_node.iodesc = desc;
513
514
fh = &nfs_root_node.fh[0];
515
buf[0] = 'X';
516
cp = &buf[1];
517
for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
518
sprintf(cp, "%02x", fh[i]);
519
sprintf(cp, "X");
520
setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
521
setenv("boot.nfsroot.path", rootpath, 1);
522
setenv("boot.nfsroot.nfshandle", buf, 1);
523
sprintf(buf, "%d", nfs_root_node.fhsize);
524
setenv("boot.nfsroot.nfshandlelen", buf, 1);
525
526
/* Allocate file system specific data structure */
527
currfd = malloc(sizeof(*newfd));
528
if (currfd == NULL) {
529
error = ENOMEM;
530
goto out;
531
}
532
#ifndef NFS_NOSYMLINK
533
bcopy(&nfs_root_node, currfd, sizeof(*currfd));
534
newfd = NULL;
535
536
cp = path = strdup(upath);
537
if (path == NULL) {
538
error = ENOMEM;
539
goto out;
540
}
541
while (*cp) {
542
/*
543
* Remove extra separators
544
*/
545
while (*cp == '/')
546
cp++;
547
548
if (*cp == '\0')
549
break;
550
/*
551
* Check that current node is a directory.
552
*/
553
if (currfd->fa.fa_type != htonl(NFDIR)) {
554
error = ENOTDIR;
555
goto out;
556
}
557
558
/* allocate file system specific data structure */
559
newfd = malloc(sizeof(*newfd));
560
if (newfd == NULL) {
561
error = ENOMEM;
562
goto out;
563
}
564
newfd->iodesc = currfd->iodesc;
565
566
/*
567
* Get next component of path name.
568
*/
569
{
570
int len = 0;
571
572
ncp = cp;
573
while ((c = *cp) != '\0' && c != '/') {
574
if (++len > NFS_MAXNAMLEN) {
575
error = ENOENT;
576
goto out;
577
}
578
cp++;
579
}
580
*cp = '\0';
581
}
582
583
/* lookup a file handle */
584
error = nfs_lookupfh(currfd, ncp, newfd);
585
*cp = c;
586
if (error)
587
goto out;
588
589
/*
590
* Check for symbolic link
591
*/
592
if (newfd->fa.fa_type == htonl(NFLNK)) {
593
int link_len, len;
594
595
error = nfs_readlink(newfd, linkbuf);
596
if (error)
597
goto out;
598
599
link_len = strlen(linkbuf);
600
len = strlen(cp);
601
602
if (link_len + len > MAXPATHLEN
603
|| ++nlinks > MAXSYMLINKS) {
604
error = ENOENT;
605
goto out;
606
}
607
608
bcopy(cp, &namebuf[link_len], len + 1);
609
bcopy(linkbuf, namebuf, link_len);
610
611
/*
612
* If absolute pathname, restart at root.
613
* If relative pathname, restart at parent directory.
614
*/
615
cp = namebuf;
616
if (*cp == '/')
617
bcopy(&nfs_root_node, currfd, sizeof(*currfd));
618
619
free(newfd);
620
newfd = NULL;
621
622
continue;
623
}
624
625
free(currfd);
626
currfd = newfd;
627
newfd = NULL;
628
}
629
630
error = 0;
631
632
out:
633
free(newfd);
634
free(path);
635
#else
636
currfd->iodesc = desc;
637
638
error = nfs_lookupfh(&nfs_root_node, upath, currfd);
639
#endif
640
if (!error) {
641
currfd->off = 0;
642
currfd->cookie = 0;
643
f->f_fsdata = (void *)currfd;
644
return (0);
645
}
646
647
#ifdef NFS_DEBUG
648
if (debug)
649
printf("nfs_open: %s lookupfh failed: %s\n",
650
path, strerror(error));
651
#endif
652
free(currfd);
653
654
return (error);
655
}
656
657
int
658
nfs_close(struct open_file *f)
659
{
660
struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
661
662
#ifdef NFS_DEBUG
663
if (debug)
664
printf("nfs_close: fp=0x%lx\n", (u_long)fp);
665
#endif
666
667
free(fp);
668
f->f_fsdata = NULL;
669
670
return (0);
671
}
672
673
/*
674
* read a portion of a file
675
*/
676
int
677
nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
678
{
679
struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
680
ssize_t cc;
681
char *addr = buf;
682
683
#ifdef NFS_DEBUG
684
if (debug)
685
printf("nfs_read: size=%lu off=%d\n", (u_long)size,
686
(int)fp->off);
687
#endif
688
while ((int)size > 0) {
689
twiddle(16);
690
cc = nfs_readdata(fp, fp->off, (void *)addr, size);
691
/* XXX maybe should retry on certain errors */
692
if (cc == -1) {
693
#ifdef NFS_DEBUG
694
if (debug)
695
printf("nfs_read: read: %s\n", strerror(errno));
696
#endif
697
return (errno); /* XXX - from nfs_readdata */
698
}
699
if (cc == 0) {
700
#ifdef NFS_DEBUG
701
if (debug)
702
printf("nfs_read: hit EOF unexpectedly\n");
703
#endif
704
goto ret;
705
}
706
fp->off += cc;
707
addr += cc;
708
size -= cc;
709
}
710
ret:
711
if (resid)
712
*resid = size;
713
714
return (0);
715
}
716
717
off_t
718
nfs_seek(struct open_file *f, off_t offset, int where)
719
{
720
struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
721
uint32_t size = ntohl(d->fa.fa_size.val[1]);
722
723
switch (where) {
724
case SEEK_SET:
725
d->off = offset;
726
break;
727
case SEEK_CUR:
728
d->off += offset;
729
break;
730
case SEEK_END:
731
d->off = size - offset;
732
break;
733
default:
734
errno = EINVAL;
735
return (-1);
736
}
737
738
return (d->off);
739
}
740
741
/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
742
int nfs_stat_types[9] = {
743
0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
744
745
int
746
nfs_stat(struct open_file *f, struct stat *sb)
747
{
748
struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
749
uint32_t ftype, mode;
750
751
ftype = ntohl(fp->fa.fa_type);
752
mode = ntohl(fp->fa.fa_mode);
753
mode |= nfs_stat_types[ftype & 7];
754
755
sb->st_mode = mode;
756
sb->st_nlink = ntohl(fp->fa.fa_nlink);
757
sb->st_uid = ntohl(fp->fa.fa_uid);
758
sb->st_gid = ntohl(fp->fa.fa_gid);
759
sb->st_size = ntohl(fp->fa.fa_size.val[1]);
760
761
return (0);
762
}
763
764
static int
765
nfs_readdir(struct open_file *f, struct dirent *d)
766
{
767
struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
768
struct nfsv3_readdir_repl *repl;
769
struct nfsv3_readdir_entry *rent;
770
static void *pkt = NULL;
771
static char *buf;
772
static struct nfs_iodesc *pfp = NULL;
773
static uint64_t cookie = 0;
774
size_t cc;
775
int pos, rc;
776
777
struct args {
778
uint32_t fhsize;
779
uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
780
} *args;
781
struct {
782
uint32_t h[RPC_HEADER_WORDS];
783
struct args d;
784
} sdata;
785
786
if (fp != pfp || fp->off != cookie) {
787
pfp = NULL;
788
refill:
789
free(pkt);
790
pkt = NULL;
791
args = &sdata.d;
792
bzero(args, sizeof(*args));
793
794
args->fhsize = htonl(fp->fhsize);
795
bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
796
pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
797
args->fhpluscookie[pos++] = htonl(fp->off >> 32);
798
args->fhpluscookie[pos++] = htonl(fp->off);
799
args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
800
args->fhpluscookie[pos++] = htonl(fp->cookie);
801
args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
802
803
cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
804
args, 6 * sizeof(uint32_t) +
805
roundup(fp->fhsize, sizeof(uint32_t)),
806
(void **)&buf, &pkt);
807
if (cc == -1) {
808
rc = errno;
809
goto err;
810
}
811
repl = (struct nfsv3_readdir_repl *)buf;
812
if (repl->errno != 0) {
813
rc = ntohl(repl->errno);
814
goto err;
815
}
816
pfp = fp;
817
cookie = fp->off;
818
fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
819
ntohl(repl->cookiev1);
820
buf += sizeof (struct nfsv3_readdir_repl);
821
}
822
rent = (struct nfsv3_readdir_entry *)buf;
823
824
if (rent->follows == 0) {
825
/* fid0 is actually eof */
826
if (rent->fid0 != 0) {
827
rc = ENOENT;
828
goto err;
829
}
830
goto refill;
831
}
832
833
d->d_namlen = ntohl(rent->len);
834
bcopy(rent->nameplus, d->d_name, d->d_namlen);
835
d->d_name[d->d_namlen] = '\0';
836
837
pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
838
fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
839
ntohl(rent->nameplus[pos + 1]);
840
pos += 2;
841
buf = (char *)&rent->nameplus[pos];
842
return (0);
843
844
err:
845
free(pkt);
846
pkt = NULL;
847
pfp = NULL;
848
cookie = 0;
849
return (rc);
850
}
851
852