xref: /netbsd-src/sys/compat/common/vfs_syscalls_43.c (revision fdecd6a253f999ae92b139670d9e15cc9df4497c)
1 /*	$NetBSD: vfs_syscalls_43.c,v 1.5 1997/06/06 19:36:31 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)vfs_syscalls.c	8.28 (Berkeley) 12/10/94
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/filedesc.h>
46 #include <sys/kernel.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/vnode.h>
50 #include <sys/namei.h>
51 #include <sys/dirent.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/stat.h>
55 #include <sys/ioctl.h>
56 #include <sys/fcntl.h>
57 #include <sys/malloc.h>
58 #include <sys/syslog.h>
59 #include <sys/unistd.h>
60 #include <sys/resourcevar.h>
61 
62 #include <sys/mount.h>
63 #include <sys/syscallargs.h>
64 
65 static void cvtstat __P((struct stat *, struct ostat *));
66 
67 /*
68  * Convert from an old to a new stat structure.
69  */
70 static void
71 cvtstat(st, ost)
72 	struct stat *st;
73 	struct ostat *ost;
74 {
75 
76 	ost->st_dev = st->st_dev;
77 	ost->st_ino = st->st_ino;
78 	ost->st_mode = st->st_mode;
79 	ost->st_nlink = st->st_nlink;
80 	ost->st_uid = st->st_uid;
81 	ost->st_gid = st->st_gid;
82 	ost->st_rdev = st->st_rdev;
83 	if (st->st_size < (quad_t)1 << 32)
84 		ost->st_size = st->st_size;
85 	else
86 		ost->st_size = -2;
87 	ost->st_atime = st->st_atime;
88 	ost->st_mtime = st->st_mtime;
89 	ost->st_ctime = st->st_ctime;
90 	ost->st_blksize = st->st_blksize;
91 	ost->st_blocks = st->st_blocks;
92 	ost->st_flags = st->st_flags;
93 	ost->st_gen = st->st_gen;
94 }
95 
96 /*
97  * Get file status; this version follows links.
98  */
99 /* ARGSUSED */
100 int
101 compat_43_sys_stat(p, v, retval)
102 	struct proc *p;
103 	void *v;
104 	register_t *retval;
105 {
106 	register struct compat_43_sys_stat_args /* {
107 		syscallarg(char *) path;
108 		syscallarg(struct ostat *) ub;
109 	} */ *uap = v;
110 	struct stat sb;
111 	struct ostat osb;
112 	int error;
113 	struct nameidata nd;
114 
115 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
116 	    SCARG(uap, path), p);
117 	if ((error = namei(&nd)) != 0)
118 		return (error);
119 	error = vn_stat(nd.ni_vp, &sb, p);
120 	vput(nd.ni_vp);
121 	if (error)
122 		return (error);
123 	cvtstat(&sb, &osb);
124 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
125 	return (error);
126 }
127 
128 
129 /*
130  * Get file status; this version does not follow links.
131  */
132 /* ARGSUSED */
133 int
134 compat_43_sys_lstat(p, v, retval)
135 	struct proc *p;
136 	void *v;
137 	register_t *retval;
138 {
139 	register struct compat_43_sys_lstat_args /* {
140 		syscallarg(char *) path;
141 		syscallarg(struct ostat *) ub;
142 	} */ *uap = v;
143 	struct stat sb;
144 	struct ostat osb;
145 	int error;
146 	struct nameidata nd;
147 
148 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
149 	    SCARG(uap, path), p);
150 	if ((error = namei(&nd)) != 0)
151 		return (error);
152 	error = vn_stat(nd.ni_vp, &sb, p);
153 	vput(nd.ni_vp);
154 	if (error)
155 		return (error);
156 	cvtstat(&sb, &osb);
157 	error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
158 	return (error);
159 }
160 
161 
162 /*
163  * Return status information about a file descriptor.
164  */
165 /* ARGSUSED */
166 int
167 compat_43_sys_fstat(p, v, retval)
168 	struct proc *p;
169 	void *v;
170 	register_t *retval;
171 {
172 	register struct compat_43_sys_fstat_args /* {
173 		syscallarg(int) fd;
174 		syscallarg(struct ostat *) sb;
175 	} */ *uap = v;
176 	int fd = SCARG(uap, fd);
177 	register struct filedesc *fdp = p->p_fd;
178 	register struct file *fp;
179 	struct stat ub;
180 	struct ostat oub;
181 	int error;
182 
183 	if ((u_int)fd >= fdp->fd_nfiles ||
184 	    (fp = fdp->fd_ofiles[fd]) == NULL)
185 		return (EBADF);
186 	switch (fp->f_type) {
187 
188 	case DTYPE_VNODE:
189 		error = vn_stat((struct vnode *)fp->f_data, &ub, p);
190 		break;
191 
192 	case DTYPE_SOCKET:
193 		error = soo_stat((struct socket *)fp->f_data, &ub);
194 		break;
195 
196 	default:
197 		panic("ofstat");
198 		/*NOTREACHED*/
199 	}
200 	cvtstat(&ub, &oub);
201 	if (error == 0)
202 		error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
203 		    sizeof (oub));
204 	return (error);
205 }
206 
207 
208 /*
209  * Truncate a file given a file descriptor.
210  */
211 /* ARGSUSED */
212 int
213 compat_43_sys_ftruncate(p, v, retval)
214 	struct proc *p;
215 	void *v;
216 	register_t *retval;
217 {
218 	register struct compat_43_sys_ftruncate_args /* {
219 		syscallarg(int) fd;
220 		syscallarg(long) length;
221 	} */ *uap = v;
222 	struct sys_ftruncate_args /* {
223 		syscallarg(int) fd;
224 		syscallarg(int) pad;
225 		syscallarg(off_t) length;
226 	} */ nuap;
227 
228 	SCARG(&nuap, fd) = SCARG(uap, fd);
229 	SCARG(&nuap, length) = SCARG(uap, length);
230 	return (sys_ftruncate(p, &nuap, retval));
231 }
232 
233 /*
234  * Truncate a file given its path name.
235  */
236 /* ARGSUSED */
237 int
238 compat_43_sys_truncate(p, v, retval)
239 	struct proc *p;
240 	void *v;
241 	register_t *retval;
242 {
243 	register struct compat_43_sys_truncate_args /* {
244 		syscallarg(char *) path;
245 		syscallarg(long) length;
246 	} */ *uap = v;
247 	struct sys_truncate_args /* {
248 		syscallarg(char *) path;
249 		syscallarg(int) pad;
250 		syscallarg(off_t) length;
251 	} */ nuap;
252 
253 	SCARG(&nuap, path) = SCARG(uap, path);
254 	SCARG(&nuap, length) = SCARG(uap, length);
255 	return (sys_truncate(p, &nuap, retval));
256 }
257 
258 
259 /*
260  * Reposition read/write file offset.
261  */
262 int
263 compat_43_sys_lseek(p, v, retval)
264 	struct proc *p;
265 	void *v;
266 	register_t *retval;
267 {
268 	register struct compat_43_sys_lseek_args /* {
269 		syscallarg(int) fd;
270 		syscallarg(long) offset;
271 		syscallarg(int) whence;
272 	} */ *uap = v;
273 	struct sys_lseek_args /* {
274 		syscallarg(int) fd;
275 		syscallarg(int) pad;
276 		syscallarg(off_t) offset;
277 		syscallarg(int) whence;
278 	} */ nuap;
279 	off_t qret;
280 	int error;
281 
282 	SCARG(&nuap, fd) = SCARG(uap, fd);
283 	SCARG(&nuap, offset) = SCARG(uap, offset);
284 	SCARG(&nuap, whence) = SCARG(uap, whence);
285 	error = sys_lseek(p, &nuap, (register_t *)&qret);
286 	*(long *)retval = qret;
287 	return (error);
288 }
289 
290 
291 /*
292  * Create a file.
293  */
294 int
295 compat_43_sys_creat(p, v, retval)
296 	struct proc *p;
297 	void *v;
298 	register_t *retval;
299 {
300 	register struct compat_43_sys_creat_args /* {
301 		syscallarg(char *) path;
302 		syscallarg(int) mode;
303 	} */ *uap = v;
304 	struct sys_open_args /* {
305 		syscallarg(char *) path;
306 		syscallarg(int) flags;
307 		syscallarg(int) mode;
308 	} */ nuap;
309 
310 	SCARG(&nuap, path) = SCARG(uap, path);
311 	SCARG(&nuap, mode) = SCARG(uap, mode);
312 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
313 	return (sys_open(p, &nuap, retval));
314 }
315 
316 /*ARGSUSED*/
317 int
318 compat_43_sys_quota(p, v, retval)
319 	struct proc *p;
320 	void *v;
321 	register_t *retval;
322 {
323 
324 	return (ENOSYS);
325 }
326 
327 
328 /*
329  * Read a block of directory entries in a file system independent format.
330  */
331 int
332 compat_43_sys_getdirentries(p, v, retval)
333 	struct proc *p;
334 	void *v;
335 	register_t *retval;
336 {
337 	register struct compat_43_sys_getdirentries_args /* {
338 		syscallarg(int) fd;
339 		syscallarg(char *) buf;
340 		syscallarg(u_int) count;
341 		syscallarg(long *) basep;
342 	} */ *uap = v;
343 	register struct vnode *vp;
344 	struct file *fp;
345 	struct uio auio, kuio;
346 	struct iovec aiov, kiov;
347 	struct dirent *dp, *edp;
348 	caddr_t dirbuf;
349 	int error, eofflag, readcnt;
350 	long loff;
351 
352 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
353 		return (error);
354 	if ((fp->f_flag & FREAD) == 0)
355 		return (EBADF);
356 	vp = (struct vnode *)fp->f_data;
357 unionread:
358 	if (vp->v_type != VDIR)
359 		return (EINVAL);
360 	aiov.iov_base = SCARG(uap, buf);
361 	aiov.iov_len = SCARG(uap, count);
362 	auio.uio_iov = &aiov;
363 	auio.uio_iovcnt = 1;
364 	auio.uio_rw = UIO_READ;
365 	auio.uio_segflg = UIO_USERSPACE;
366 	auio.uio_procp = p;
367 	auio.uio_resid = SCARG(uap, count);
368 	VOP_LOCK(vp);
369 	loff = auio.uio_offset = fp->f_offset;
370 #	if (BYTE_ORDER != LITTLE_ENDIAN)
371 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
372 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
373 			    (u_long *)0, 0);
374 			fp->f_offset = auio.uio_offset;
375 		} else
376 #	endif
377 	{
378 		kuio = auio;
379 		kuio.uio_iov = &kiov;
380 		kuio.uio_segflg = UIO_SYSSPACE;
381 		kiov.iov_len = SCARG(uap, count);
382 		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
383 		kiov.iov_base = dirbuf;
384 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
385 			    (u_long *)0, 0);
386 		fp->f_offset = kuio.uio_offset;
387 		if (error == 0) {
388 			readcnt = SCARG(uap, count) - kuio.uio_resid;
389 			edp = (struct dirent *)&dirbuf[readcnt];
390 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
391 #				if (BYTE_ORDER == LITTLE_ENDIAN)
392 					/*
393 					 * The expected low byte of
394 					 * dp->d_namlen is our dp->d_type.
395 					 * The high MBZ byte of dp->d_namlen
396 					 * is our dp->d_namlen.
397 					 */
398 					dp->d_type = dp->d_namlen;
399 					dp->d_namlen = 0;
400 #				else
401 					/*
402 					 * The dp->d_type is the high byte
403 					 * of the expected dp->d_namlen,
404 					 * so must be zero'ed.
405 					 */
406 					dp->d_type = 0;
407 #				endif
408 				if (dp->d_reclen > 0) {
409 					dp = (struct dirent *)
410 					    ((char *)dp + dp->d_reclen);
411 				} else {
412 					error = EIO;
413 					break;
414 				}
415 			}
416 			if (dp >= edp)
417 				error = uiomove(dirbuf, readcnt, &auio);
418 		}
419 		FREE(dirbuf, M_TEMP);
420 	}
421 	VOP_UNLOCK(vp);
422 	if (error)
423 		return (error);
424 
425 #ifdef UNION
426 {
427 	extern int (**union_vnodeop_p) __P((void *));
428 	extern struct vnode *union_dircache __P((struct vnode *));
429 
430 	if ((SCARG(uap, count) == auio.uio_resid) &&
431 	    (vp->v_op == union_vnodeop_p)) {
432 		struct vnode *lvp;
433 
434 		lvp = union_dircache(vp);
435 		if (lvp != NULLVP) {
436 			struct vattr va;
437 
438 			/*
439 			 * If the directory is opaque,
440 			 * then don't show lower entries
441 			 */
442 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
443 			if (va.va_flags & OPAQUE) {
444 				vput(lvp);
445 				lvp = NULL;
446 			}
447 		}
448 
449 		if (lvp != NULLVP) {
450 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
451 			VOP_UNLOCK(lvp);
452 
453 			if (error) {
454 				vrele(lvp);
455 				return (error);
456 			}
457 			fp->f_data = (caddr_t) lvp;
458 			fp->f_offset = 0;
459 			error = vn_close(vp, FREAD, fp->f_cred, p);
460 			if (error)
461 				return (error);
462 			vp = lvp;
463 			goto unionread;
464 		}
465 	}
466 }
467 #endif /* UNION */
468 
469 	if ((SCARG(uap, count) == auio.uio_resid) &&
470 	    (vp->v_flag & VROOT) &&
471 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
472 		struct vnode *tvp = vp;
473 		vp = vp->v_mount->mnt_vnodecovered;
474 		VREF(vp);
475 		fp->f_data = (caddr_t) vp;
476 		fp->f_offset = 0;
477 		vrele(tvp);
478 		goto unionread;
479 	}
480 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
481 	    sizeof(long));
482 	*retval = SCARG(uap, count) - auio.uio_resid;
483 	return (error);
484 }
485