xref: /netbsd-src/sys/rump/kern/lib/libsys_sunos/rump_sunos_compat.c (revision d91f98a8715141154279122ae81737cb65179572)
1*d91f98a8Spgoyette /*	$NetBSD: rump_sunos_compat.c,v 1.4 2019/01/27 02:08:49 pgoyette Exp $	*/
2b86d8c27Spooka 
3b86d8c27Spooka /*
4b86d8c27Spooka  * Copyright (c) 2013 Antti Kantee.  All Rights Reserved.
5b86d8c27Spooka  *
6b86d8c27Spooka  * Redistribution and use in source and binary forms, with or without
7b86d8c27Spooka  * modification, are permitted provided that the following conditions
8b86d8c27Spooka  * are met:
9b86d8c27Spooka  * 1. Redistributions of source code must retain the above copyright
10b86d8c27Spooka  *    notice, this list of conditions and the following disclaimer.
11b86d8c27Spooka  * 2. Redistributions in binary form must reproduce the above copyright
12b86d8c27Spooka  *    notice, this list of conditions and the following disclaimer in the
13b86d8c27Spooka  *    documentation and/or other materials provided with the distribution.
14b86d8c27Spooka  *
15b86d8c27Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16b86d8c27Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17b86d8c27Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18b86d8c27Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19b86d8c27Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20b86d8c27Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21b86d8c27Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22b86d8c27Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23b86d8c27Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24b86d8c27Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25b86d8c27Spooka  * SUCH DAMAGE.
26b86d8c27Spooka  */
27b86d8c27Spooka 
28a57097d0Salnsn #include <sys/cdefs.h>
29*d91f98a8Spgoyette __KERNEL_RCSID(0, "$NetBSD: rump_sunos_compat.c,v 1.4 2019/01/27 02:08:49 pgoyette Exp $");
30a57097d0Salnsn 
31b86d8c27Spooka #include <sys/param.h>
32b86d8c27Spooka #include <sys/dirent.h>
33b86d8c27Spooka #include <sys/fcntl.h>
34b86d8c27Spooka #include <sys/file.h>
35b86d8c27Spooka #include <sys/filedesc.h>
36b86d8c27Spooka #include <sys/malloc.h>
37b86d8c27Spooka #include <sys/namei.h>
38b86d8c27Spooka #include <sys/stat.h>
39b86d8c27Spooka #include <sys/syscallargs.h>
40b86d8c27Spooka #include <sys/vnode.h>
41b86d8c27Spooka #include <sys/vfs_syscalls.h>
42b86d8c27Spooka 
43b86d8c27Spooka #include <compat/sys/time_types.h>
44b86d8c27Spooka 
45b86d8c27Spooka #include "rump_sunos_syscallargs.h"
46b86d8c27Spooka 
47b86d8c27Spooka #define SUNOS_MAXNAMLEN 255
48b86d8c27Spooka 
49b86d8c27Spooka struct sunos_dirent {
50b86d8c27Spooka 	uint64_t	d_fileno;
51b86d8c27Spooka 	int64_t		d_off;
52b86d8c27Spooka 	unsigned short	d_reclen;
53b86d8c27Spooka 	char		d_name[SUNOS_MAXNAMLEN + 1];
54b86d8c27Spooka };
55b86d8c27Spooka 
56b86d8c27Spooka #define SUNOS_NAMEOFF(dp)	((char *)&(dp)->d_name - (char *)dp)
57b86d8c27Spooka #define SUNOS_RECLEN(de,namlen)	ALIGN((SUNOS_NAMEOFF(de) + (namlen) + 1))
58b86d8c27Spooka 
59b86d8c27Spooka /*
60b86d8c27Spooka  * Rump kernels always use the _FILE_OFFSET_BITS=64 API.
61b86d8c27Spooka  */
62b86d8c27Spooka #ifdef __LP64__
63b86d8c27Spooka struct sunos_stat {
64b86d8c27Spooka         unsigned long	st_dev;
65b86d8c27Spooka         uint64_t	st_ino;
66b86d8c27Spooka         unsigned int	st_mode;
67b86d8c27Spooka         unsigned int	st_nlink;
68b86d8c27Spooka         unsigned int	st_uid;
69b86d8c27Spooka         unsigned int	st_gid;
70b86d8c27Spooka         unsigned long	st_rdev;
71b86d8c27Spooka         off_t		st_size;
72b86d8c27Spooka 
73b86d8c27Spooka         struct timespec	st_atim;
74b86d8c27Spooka         struct timespec	st_mtim;
75b86d8c27Spooka         struct timespec	st_ctim;
76b86d8c27Spooka         int		st_blksize;
77b86d8c27Spooka         uint64_t	st_blocks;
78b86d8c27Spooka         char		st_fstype[16];
79b86d8c27Spooka };
80b86d8c27Spooka #else
81b86d8c27Spooka struct sunos_stat {
82b86d8c27Spooka         unsigned long	st_dev;
83b86d8c27Spooka 	long		st_pad1[3];
84b86d8c27Spooka         uint64_t	st_ino;
85b86d8c27Spooka         unsigned int	st_mode;
86b86d8c27Spooka         unsigned int	st_nlink;
87b86d8c27Spooka         unsigned int	st_uid;
88b86d8c27Spooka         unsigned int	st_gid;
89b86d8c27Spooka         unsigned long	st_rdev;
90b86d8c27Spooka 	long		st_pad2[2];
91b86d8c27Spooka         off_t		st_size;
92b86d8c27Spooka 
93b86d8c27Spooka         struct timespec50 st_atim;
94b86d8c27Spooka         struct timespec50 st_mtim;
95b86d8c27Spooka         struct timespec50 st_ctim;
96b86d8c27Spooka 
97b86d8c27Spooka         int		st_blksize;
98b86d8c27Spooka         uint64_t	st_blocks;
99b86d8c27Spooka         char            st_fstype[16];
100b86d8c27Spooka 	long		st_pad4[8];
101b86d8c27Spooka };
102b86d8c27Spooka #endif
103b86d8c27Spooka 
104b86d8c27Spooka #define PARCOPY(a) ssb->a = sb->a
105b86d8c27Spooka static void
bsd_to_sunos_stat(const struct stat * sb,struct sunos_stat * ssb)106b86d8c27Spooka bsd_to_sunos_stat(const struct stat *sb, struct sunos_stat *ssb)
107b86d8c27Spooka {
108b86d8c27Spooka 
109b86d8c27Spooka 	memset(ssb, 0, sizeof(*ssb));
110b86d8c27Spooka 	PARCOPY(st_dev);
111b86d8c27Spooka 	PARCOPY(st_ino);
112b86d8c27Spooka 	PARCOPY(st_mode);
113b86d8c27Spooka 	PARCOPY(st_nlink);
114b86d8c27Spooka 	PARCOPY(st_uid);
115b86d8c27Spooka 	PARCOPY(st_gid);
116b86d8c27Spooka 	PARCOPY(st_rdev);
117b86d8c27Spooka 	PARCOPY(st_size);
118b86d8c27Spooka 	PARCOPY(st_blksize);
119b86d8c27Spooka 	PARCOPY(st_blocks);
120b86d8c27Spooka 
121b86d8c27Spooka #ifdef __LP64__
122b86d8c27Spooka 	ssb->st_atim = sb->st_atimespec;
123b86d8c27Spooka 	ssb->st_mtim = sb->st_mtimespec;
124b86d8c27Spooka 	ssb->st_ctim = sb->st_ctimespec;
125b86d8c27Spooka #else
126b86d8c27Spooka 	timespec_to_timespec50(&sb->st_atimespec, &ssb->st_atim);
127b86d8c27Spooka 	timespec_to_timespec50(&sb->st_mtimespec, &ssb->st_mtim);
128b86d8c27Spooka 	timespec_to_timespec50(&sb->st_ctimespec, &ssb->st_ctim);
129b86d8c27Spooka #endif
130b86d8c27Spooka }
131b86d8c27Spooka 
132b86d8c27Spooka int
rump_sunos_sys_stat(struct lwp * l,const struct rump_sunos_sys_stat_args * uap,register_t * retval)133b86d8c27Spooka rump_sunos_sys_stat(struct lwp *l, const struct rump_sunos_sys_stat_args *uap,
134b86d8c27Spooka 	register_t *retval)
135b86d8c27Spooka {
136b86d8c27Spooka 	struct sunos_stat ssb;
137b86d8c27Spooka 	struct stat sb;
138b86d8c27Spooka 	int error;
139b86d8c27Spooka 
140b86d8c27Spooka 	error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
141b86d8c27Spooka 	if (error)
142b86d8c27Spooka 		return error;
143b86d8c27Spooka 
144b86d8c27Spooka 	bsd_to_sunos_stat(&sb, &ssb);
145b86d8c27Spooka 
146b86d8c27Spooka 	return copyout(&ssb, SCARG(uap, sp), sizeof(ssb));
147b86d8c27Spooka }
148b86d8c27Spooka 
149b86d8c27Spooka int
rump_sunos_sys_fstat(struct lwp * l,const struct rump_sunos_sys_fstat_args * uap,register_t * retval)150b86d8c27Spooka rump_sunos_sys_fstat(struct lwp *l, const struct rump_sunos_sys_fstat_args *uap,
151b86d8c27Spooka 	register_t *retval)
152b86d8c27Spooka {
153b86d8c27Spooka 	struct sunos_stat ssb;
154b86d8c27Spooka 	struct stat sb;
155b86d8c27Spooka 	int error;
156b86d8c27Spooka 
157b86d8c27Spooka 	error = do_sys_fstat(SCARG(uap, fd), &sb);
158b86d8c27Spooka 	if (error)
159b86d8c27Spooka 		return error;
160b86d8c27Spooka 
161b86d8c27Spooka 	bsd_to_sunos_stat(&sb, &ssb);
162b86d8c27Spooka 
163b86d8c27Spooka 	return copyout(&ssb, SCARG(uap, sp), sizeof(ssb));
164b86d8c27Spooka }
165b86d8c27Spooka 
166b86d8c27Spooka int
rump_sunos_sys_lstat(struct lwp * l,const struct rump_sunos_sys_lstat_args * uap,register_t * retval)167b86d8c27Spooka rump_sunos_sys_lstat(struct lwp *l, const struct rump_sunos_sys_lstat_args *uap,
168b86d8c27Spooka 	register_t *retval)
169b86d8c27Spooka {
170b86d8c27Spooka 	struct sunos_stat ssb;
171b86d8c27Spooka 	struct stat sb;
172b86d8c27Spooka 	int error;
173b86d8c27Spooka 
174b86d8c27Spooka 	error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb);
175b86d8c27Spooka 	if (error)
176b86d8c27Spooka 		return error;
177b86d8c27Spooka 
178b86d8c27Spooka 	bsd_to_sunos_stat(&sb, &ssb);
179b86d8c27Spooka 
180b86d8c27Spooka 	return copyout(&ssb, SCARG(uap, sp), sizeof(ssb));
181b86d8c27Spooka }
182b86d8c27Spooka 
183b86d8c27Spooka int
rump_sunos_sys_open(struct lwp * l,const struct rump_sunos_sys_open_args * uap,register_t * retval)184b86d8c27Spooka rump_sunos_sys_open(struct lwp *l, const struct rump_sunos_sys_open_args *uap,
185b86d8c27Spooka 	register_t *retval)
186b86d8c27Spooka {
187b86d8c27Spooka 	/* {
188b86d8c27Spooka 		syscallarg(const char *) path;
189b86d8c27Spooka 		syscallarg(int) flags;
190b86d8c27Spooka 		syscallarg(int) mode;
191b86d8c27Spooka 	} */
192b86d8c27Spooka 	struct sys_open_args ua;
193b86d8c27Spooka 	int sflags, flags;
194b86d8c27Spooka 
195b86d8c27Spooka 	sflags = SCARG(uap, flags);
196b86d8c27Spooka 	flags =  (sflags & (0x8 | 0x4 | 0x3)); /* nonblock/append/rw */
197b86d8c27Spooka 	flags |= (sflags & 0x10)	? O_SYNC : 0;
198b86d8c27Spooka 	flags |= (sflags & 0x40)	? O_DSYNC : 0;
199b86d8c27Spooka 	flags |= (sflags & 0x8000)	? O_RSYNC : 0;
200b86d8c27Spooka 	flags |= (sflags & 0x80)	? O_NONBLOCK : 0;
201b86d8c27Spooka 	flags |= (sflags & 0x100)	? O_CREAT : 0;
202b86d8c27Spooka 	flags |= (sflags & 0x200)	? O_TRUNC : 0;
203b86d8c27Spooka 	flags |= (sflags & 0x400)	? O_EXCL : 0;
204b86d8c27Spooka 	flags |= (sflags & 0x20000)	? O_NOFOLLOW : 0;
205b86d8c27Spooka 
206b86d8c27Spooka 	SCARG(&ua, path) = SCARG(uap, path);
207b86d8c27Spooka 	SCARG(&ua, flags) = flags;
208b86d8c27Spooka 	SCARG(&ua, mode) = SCARG(uap, mode);
209b86d8c27Spooka 
210b86d8c27Spooka 	return sys_open(l, &ua, retval);
211b86d8c27Spooka }
212b86d8c27Spooka 
213b86d8c27Spooka /*-
214b86d8c27Spooka  * Copyright (c) 1992, 1993
215b86d8c27Spooka  *      The Regents of the University of California.  All rights reserved.
216b86d8c27Spooka  *
217b86d8c27Spooka  * This software was developed by the Computer Systems Engineering group
218b86d8c27Spooka  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
219b86d8c27Spooka  * contributed to Berkeley.
220b86d8c27Spooka  *
221b86d8c27Spooka  * All advertising materials mentioning features or use of this software
222b86d8c27Spooka  * must display the following acknowledgement:
223b86d8c27Spooka  *      This product includes software developed by the University of
224b86d8c27Spooka  *      California, Lawrence Berkeley Laboratory.
225b86d8c27Spooka  *
226b86d8c27Spooka  * Redistribution and use in source and binary forms, with or without
227b86d8c27Spooka  * modification, are permitted provided that the following conditions
228b86d8c27Spooka  * are met:
229b86d8c27Spooka  * 1. Redistributions of source code must retain the above copyright
230b86d8c27Spooka  *    notice, this list of conditions and the following disclaimer.
231b86d8c27Spooka  * 2. Redistributions in binary form must reproduce the above copyright
232b86d8c27Spooka  *    notice, this list of conditions and the following disclaimer in the
233b86d8c27Spooka  *    documentation and/or other materials provided with the distribution.
234b86d8c27Spooka  * 3. Neither the name of the University nor the names of its contributors
235b86d8c27Spooka  *    may be used to endorse or promote products derived from this software
236b86d8c27Spooka  *    without specific prior written permission.
237b86d8c27Spooka  *
238b86d8c27Spooka  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239b86d8c27Spooka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
240b86d8c27Spooka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241b86d8c27Spooka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
242b86d8c27Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
243b86d8c27Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
244b86d8c27Spooka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245b86d8c27Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
246b86d8c27Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247b86d8c27Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248b86d8c27Spooka  * SUCH DAMAGE.
249b86d8c27Spooka  *
250b86d8c27Spooka  *      @(#)sunos_misc.c        8.1 (Berkeley) 6/18/93
251b86d8c27Spooka  *
252b86d8c27Spooka  *      Header: sunos_misc.c,v 1.16 93/04/07 02:46:27 torek Exp
253b86d8c27Spooka  */
254b86d8c27Spooka 
255b86d8c27Spooka int
rump_sunos_sys_getdents(struct lwp * l,const struct rump_sunos_sys_getdents_args * uap,register_t * retval)256b86d8c27Spooka rump_sunos_sys_getdents(struct lwp *l,
257b86d8c27Spooka 	const struct rump_sunos_sys_getdents_args *uap, register_t *retval)
258b86d8c27Spooka {
259b86d8c27Spooka 	struct dirent *bdp;
260b86d8c27Spooka 	struct vnode *vp;
261b86d8c27Spooka 	char *inp, *buf;	/* BSD-format */
262b86d8c27Spooka 	int len, reclen;	/* BSD-format */
263b86d8c27Spooka 	char *outp;		/* Sun-format */
264b86d8c27Spooka 	int resid, sunos_reclen;/* Sun-format */
265b86d8c27Spooka 	struct file *fp;
266b86d8c27Spooka 	struct uio auio;
267b86d8c27Spooka 	struct iovec aiov;
268b86d8c27Spooka 	struct sunos_dirent idb;
269b86d8c27Spooka 	off_t off;			/* true file offset */
270b86d8c27Spooka 	int buflen, error, eofflag;
271b86d8c27Spooka 	off_t *cookiebuf, *cookie;
272b86d8c27Spooka 	int ncookies;
273b86d8c27Spooka 
274b86d8c27Spooka 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
275b86d8c27Spooka 		return (error);
276b86d8c27Spooka 
277b86d8c27Spooka 	if ((fp->f_flag & FREAD) == 0) {
278b86d8c27Spooka 		error = EBADF;
279b86d8c27Spooka 		goto out1;
280b86d8c27Spooka 	}
281b86d8c27Spooka 
282b86d8c27Spooka 	vp = fp->f_data;
283b86d8c27Spooka 	if (vp->v_type != VDIR) {
284b86d8c27Spooka 		error = EINVAL;
285b86d8c27Spooka 		goto out1;
286b86d8c27Spooka 	}
287b86d8c27Spooka 
288b86d8c27Spooka 	buflen = min(MAXBSIZE, SCARG(uap, nbytes));
289b86d8c27Spooka 	buf = malloc(buflen, M_TEMP, M_WAITOK);
290b86d8c27Spooka 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
291b86d8c27Spooka 	off = fp->f_offset;
292b86d8c27Spooka again:
293b86d8c27Spooka 	aiov.iov_base = buf;
294b86d8c27Spooka 	aiov.iov_len = buflen;
295b86d8c27Spooka 	auio.uio_iov = &aiov;
296b86d8c27Spooka 	auio.uio_iovcnt = 1;
297b86d8c27Spooka 	auio.uio_rw = UIO_READ;
298b86d8c27Spooka 	auio.uio_resid = buflen;
299b86d8c27Spooka 	auio.uio_offset = off;
300b86d8c27Spooka 	UIO_SETUP_SYSSPACE(&auio);
301b86d8c27Spooka 	/*
302b86d8c27Spooka 	 * First we read into the malloc'ed buffer, then
303b86d8c27Spooka 	 * we massage it into user space, one record at a time.
304b86d8c27Spooka 	 */
305b86d8c27Spooka 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
306b86d8c27Spooka 	    &ncookies);
307b86d8c27Spooka 	if (error)
308b86d8c27Spooka 		goto out;
309b86d8c27Spooka 
310b86d8c27Spooka 	inp = buf;
311b86d8c27Spooka 	outp = SCARG(uap, buf);
312b86d8c27Spooka 	resid = SCARG(uap, nbytes);
313b86d8c27Spooka 	if ((len = buflen - auio.uio_resid) == 0)
314b86d8c27Spooka 		goto eof;
315b86d8c27Spooka 
316b86d8c27Spooka 	for (cookie = cookiebuf; len > 0; len -= reclen) {
317b86d8c27Spooka 		bdp = (struct dirent *)inp;
318b86d8c27Spooka 		reclen = bdp->d_reclen;
31939f1e868Sriastradh 		if (reclen & 3) {
32039f1e868Sriastradh 			error = EIO;
32139f1e868Sriastradh 			goto out;
32239f1e868Sriastradh 		}
323b86d8c27Spooka 		if ((*cookie >> 32) != 0) {
324b86d8c27Spooka 			printf("rump_sunos_sys_getdents: offset too large\n");
325b86d8c27Spooka 			error = EINVAL;
326b86d8c27Spooka 			goto out;
327b86d8c27Spooka 		}
328b86d8c27Spooka 		if (bdp->d_fileno == 0) {
329b86d8c27Spooka 			inp += reclen;	/* it is a hole; squish it out */
330b86d8c27Spooka 			if (cookie)
331b86d8c27Spooka 				off = *cookie++;
332b86d8c27Spooka 			else
333b86d8c27Spooka 				off += reclen;
334b86d8c27Spooka 			continue;
335b86d8c27Spooka 		}
336b86d8c27Spooka 		sunos_reclen = SUNOS_RECLEN(&idb, bdp->d_namlen);
337b86d8c27Spooka 		if (reclen > len || resid < sunos_reclen) {
338b86d8c27Spooka 			/* entry too big for buffer, so just stop */
339b86d8c27Spooka 			outp++;
340b86d8c27Spooka 			break;
341b86d8c27Spooka 		}
342b86d8c27Spooka 		if (cookie)
343b86d8c27Spooka 			off = *cookie++;	/* each entry points to next */
344b86d8c27Spooka 		else
345b86d8c27Spooka 			off += reclen;
346b86d8c27Spooka 		/*
347b86d8c27Spooka 		 * Massage in place to make a Sun-shaped dirent (otherwise
348b86d8c27Spooka 		 * we have to worry about touching user memory outside of
349b86d8c27Spooka 		 * the copyout() call).
350b86d8c27Spooka 		 */
351b86d8c27Spooka 		idb.d_fileno = bdp->d_fileno;
352b86d8c27Spooka 		idb.d_off = off;
353b86d8c27Spooka 		idb.d_reclen = sunos_reclen;
354b86d8c27Spooka 		strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
355b86d8c27Spooka 		if ((error = copyout((void *)&idb, outp, sunos_reclen)) != 0)
356b86d8c27Spooka 			goto out;
357b86d8c27Spooka 		/* advance past this real entry */
358b86d8c27Spooka 		inp += reclen;
359b86d8c27Spooka 		/* advance output past Sun-shaped entry */
360b86d8c27Spooka 		outp += sunos_reclen;
361b86d8c27Spooka 		resid -= sunos_reclen;
362b86d8c27Spooka 	}
363b86d8c27Spooka 
364b86d8c27Spooka 	/* if we squished out the whole block, try again */
365b86d8c27Spooka 	if (outp == SCARG(uap, buf)) {
366b86d8c27Spooka 		if (cookiebuf)
367b86d8c27Spooka 			free(cookiebuf, M_TEMP);
368b86d8c27Spooka 		cookiebuf = NULL;
369b86d8c27Spooka 		goto again;
370b86d8c27Spooka 	}
371b86d8c27Spooka 	fp->f_offset = off;		/* update the vnode offset */
372b86d8c27Spooka 
373b86d8c27Spooka eof:
374b86d8c27Spooka 	*retval = SCARG(uap, nbytes) - resid;
375b86d8c27Spooka out:
376b86d8c27Spooka 	VOP_UNLOCK(vp);
377b86d8c27Spooka 	free(cookiebuf, M_TEMP);
378b86d8c27Spooka 	free(buf, M_TEMP);
379b86d8c27Spooka  out1:
380b86d8c27Spooka  	fd_putfile(SCARG(uap, fd));
381b86d8c27Spooka 	return (error);
382b86d8c27Spooka }
383