vfs_syscalls_43.c revision 1.1 1 /* $NetBSD: vfs_syscalls_43.c,v 1.1 1995/06/24 20:16:25 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
66 /*
67 * Convert from an old to a new stat structure.
68 */
69 static int
70 cvtstat(st, ost)
71 struct stat *st;
72 struct ostat *ost;
73 {
74
75 ost->st_dev = st->st_dev;
76 ost->st_ino = st->st_ino;
77 ost->st_mode = st->st_mode;
78 ost->st_nlink = st->st_nlink;
79 ost->st_uid = st->st_uid;
80 ost->st_gid = st->st_gid;
81 ost->st_rdev = st->st_rdev;
82 if (st->st_size < (quad_t)1 << 32)
83 ost->st_size = st->st_size;
84 else
85 ost->st_size = -2;
86 ost->st_atime = st->st_atime;
87 ost->st_mtime = st->st_mtime;
88 ost->st_ctime = st->st_ctime;
89 ost->st_blksize = st->st_blksize;
90 ost->st_blocks = st->st_blocks;
91 ost->st_flags = st->st_flags;
92 ost->st_gen = st->st_gen;
93 }
94
95 /*
96 * Get file status; this version follows links.
97 */
98 /* ARGSUSED */
99 int
100 compat_43_stat(p, uap, retval)
101 struct proc *p;
102 register struct compat_43_stat_args /* {
103 syscallarg(char *) path;
104 syscallarg(struct ostat *) ub;
105 } */ *uap;
106 register_t *retval;
107 {
108 struct stat sb;
109 struct ostat osb;
110 int error;
111 struct nameidata nd;
112
113 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
114 SCARG(uap, path), p);
115 if (error = namei(&nd))
116 return (error);
117 error = vn_stat(nd.ni_vp, &sb, p);
118 vput(nd.ni_vp);
119 if (error)
120 return (error);
121 cvtstat(&sb, &osb);
122 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
123 return (error);
124 }
125
126
127 /*
128 * Get file status; this version does not follow links.
129 */
130 /* ARGSUSED */
131 int
132 compat_43_lstat(p, uap, retval)
133 struct proc *p;
134 register struct compat_43_lstat_args /* {
135 syscallarg(char *) path;
136 syscallarg(struct ostat *) ub;
137 } */ *uap;
138 register_t *retval;
139 {
140 struct vnode *vp, *dvp;
141 struct stat sb, sb1;
142 struct ostat osb;
143 int error;
144 struct nameidata nd;
145
146 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
147 SCARG(uap, path), p);
148 if (error = namei(&nd))
149 return (error);
150 /*
151 * For symbolic links, always return the attributes of its
152 * containing directory, except for mode, size, and links.
153 */
154 vp = nd.ni_vp;
155 dvp = nd.ni_dvp;
156 if (vp->v_type != VLNK) {
157 if (dvp == vp)
158 vrele(dvp);
159 else
160 vput(dvp);
161 error = vn_stat(vp, &sb, p);
162 vput(vp);
163 if (error)
164 return (error);
165 } else {
166 error = vn_stat(dvp, &sb, p);
167 vput(dvp);
168 if (error) {
169 vput(vp);
170 return (error);
171 }
172 error = vn_stat(vp, &sb1, p);
173 vput(vp);
174 if (error)
175 return (error);
176 sb.st_mode &= ~S_IFDIR;
177 sb.st_mode |= S_IFLNK;
178 sb.st_nlink = sb1.st_nlink;
179 sb.st_size = sb1.st_size;
180 sb.st_blocks = sb1.st_blocks;
181 }
182 cvtstat(&sb, &osb);
183 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
184 return (error);
185 }
186
187
188 /*
189 * Return status information about a file descriptor.
190 */
191 /* ARGSUSED */
192 compat_43_fstat(p, uap, retval)
193 struct proc *p;
194 register struct compat_43_fstat_args /* {
195 syscallarg(int) fd;
196 syscallarg(struct ostat *) sb;
197 } */ *uap;
198 register_t *retval;
199 {
200 int fd = SCARG(uap, fd);
201 register struct filedesc *fdp = p->p_fd;
202 register struct file *fp;
203 struct stat ub;
204 struct ostat oub;
205 int error;
206
207 if ((u_int)fd >= fdp->fd_nfiles ||
208 (fp = fdp->fd_ofiles[fd]) == NULL)
209 return (EBADF);
210 switch (fp->f_type) {
211
212 case DTYPE_VNODE:
213 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
214 break;
215
216 case DTYPE_SOCKET:
217 error = soo_stat((struct socket *)fp->f_data, &ub);
218 break;
219
220 default:
221 panic("ofstat");
222 /*NOTREACHED*/
223 }
224 cvtstat(&ub, &oub);
225 if (error == 0)
226 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
227 sizeof (oub));
228 return (error);
229 }
230
231
232 /*
233 * Truncate a file given a file descriptor.
234 */
235 /* ARGSUSED */
236 int
237 compat_43_ftruncate(p, uap, retval)
238 struct proc *p;
239 register struct compat_43_ftruncate_args /* {
240 syscallarg(int) fd;
241 syscallarg(long) length;
242 } */ *uap;
243 register_t *retval;
244 {
245 struct ftruncate_args /* {
246 syscallarg(int) fd;
247 syscallarg(int) pad;
248 syscallarg(off_t) length;
249 } */ nuap;
250
251 SCARG(&nuap, fd) = SCARG(uap, fd);
252 SCARG(&nuap, length) = SCARG(uap, length);
253 return (ftruncate(p, &nuap, retval));
254 }
255
256 /*
257 * Truncate a file given its path name.
258 */
259 /* ARGSUSED */
260 int
261 compat_43_truncate(p, uap, retval)
262 struct proc *p;
263 register struct compat_43_truncate_args /* {
264 syscallarg(char *) path;
265 syscallarg(long) length;
266 } */ *uap;
267 register_t *retval;
268 {
269 struct truncate_args /* {
270 syscallarg(char *) path;
271 syscallarg(int) pad;
272 syscallarg(off_t) length;
273 } */ nuap;
274
275 SCARG(&nuap, path) = SCARG(uap, path);
276 SCARG(&nuap, length) = SCARG(uap, length);
277 return (truncate(p, &nuap, retval));
278 }
279
280
281 /*
282 * Reposition read/write file offset.
283 */
284 int
285 compat_43_lseek(p, uap, retval)
286 struct proc *p;
287 register struct compat_43_lseek_args /* {
288 syscallarg(int) fd;
289 syscallarg(long) offset;
290 syscallarg(int) whence;
291 } */ *uap;
292 register_t *retval;
293 {
294 struct lseek_args /* {
295 syscallarg(int) fd;
296 syscallarg(int) pad;
297 syscallarg(off_t) offset;
298 syscallarg(int) whence;
299 } */ nuap;
300 off_t qret;
301 int error;
302
303 SCARG(&nuap, fd) = SCARG(uap, fd);
304 SCARG(&nuap, offset) = SCARG(uap, offset);
305 SCARG(&nuap, whence) = SCARG(uap, whence);
306 error = lseek(p, &nuap, &qret);
307 *(long *)retval = qret;
308 return (error);
309 }
310
311
312 /*
313 * Create a file.
314 */
315 int
316 compat_43_creat(p, uap, retval)
317 struct proc *p;
318 register struct compat_43_creat_args /* {
319 syscallarg(char *) path;
320 syscallarg(int) mode;
321 } */ *uap;
322 register_t *retval;
323 {
324 struct open_args /* {
325 syscallarg(char *) path;
326 syscallarg(int) flags;
327 syscallarg(int) mode;
328 } */ nuap;
329
330 SCARG(&nuap, path) = SCARG(uap, path);
331 SCARG(&nuap, mode) = SCARG(uap, mode);
332 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
333 return (open(p, &nuap, retval));
334 }
335
336 /*ARGSUSED*/
337 int
338 compat_43_quota(p, uap, retval)
339 struct proc *p;
340 void *uap;
341 register_t *retval;
342 {
343
344 return (ENOSYS);
345 }
346
347
348 /*
349 * Read a block of directory entries in a file system independent format.
350 */
351 int
352 compat_43_getdirentries(p, uap, retval)
353 struct proc *p;
354 register struct compat_43_getdirentries_args /* {
355 syscallarg(int) fd;
356 syscallarg(char *) buf;
357 syscallarg(u_int) count;
358 syscallarg(long *) basep;
359 } */ *uap;
360 register_t *retval;
361 {
362 register struct vnode *vp;
363 struct file *fp;
364 struct uio auio, kuio;
365 struct iovec aiov, kiov;
366 struct dirent *dp, *edp;
367 caddr_t dirbuf;
368 int error, eofflag, readcnt;
369 long loff;
370
371 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
372 return (error);
373 if ((fp->f_flag & FREAD) == 0)
374 return (EBADF);
375 vp = (struct vnode *)fp->f_data;
376 unionread:
377 if (vp->v_type != VDIR)
378 return (EINVAL);
379 aiov.iov_base = SCARG(uap, buf);
380 aiov.iov_len = SCARG(uap, count);
381 auio.uio_iov = &aiov;
382 auio.uio_iovcnt = 1;
383 auio.uio_rw = UIO_READ;
384 auio.uio_segflg = UIO_USERSPACE;
385 auio.uio_procp = p;
386 auio.uio_resid = SCARG(uap, count);
387 VOP_LOCK(vp);
388 loff = auio.uio_offset = fp->f_offset;
389 # if (BYTE_ORDER != LITTLE_ENDIAN)
390 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
391 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
392 (u_long *)0, 0);
393 fp->f_offset = auio.uio_offset;
394 } else
395 # endif
396 {
397 kuio = auio;
398 kuio.uio_iov = &kiov;
399 kuio.uio_segflg = UIO_SYSSPACE;
400 kiov.iov_len = SCARG(uap, count);
401 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
402 kiov.iov_base = dirbuf;
403 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
404 (u_long *)0, 0);
405 fp->f_offset = kuio.uio_offset;
406 if (error == 0) {
407 readcnt = SCARG(uap, count) - kuio.uio_resid;
408 edp = (struct dirent *)&dirbuf[readcnt];
409 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
410 # if (BYTE_ORDER == LITTLE_ENDIAN)
411 /*
412 * The expected low byte of
413 * dp->d_namlen is our dp->d_type.
414 * The high MBZ byte of dp->d_namlen
415 * is our dp->d_namlen.
416 */
417 dp->d_type = dp->d_namlen;
418 dp->d_namlen = 0;
419 # else
420 /*
421 * The dp->d_type is the high byte
422 * of the expected dp->d_namlen,
423 * so must be zero'ed.
424 */
425 dp->d_type = 0;
426 # endif
427 if (dp->d_reclen > 0) {
428 dp = (struct dirent *)
429 ((char *)dp + dp->d_reclen);
430 } else {
431 error = EIO;
432 break;
433 }
434 }
435 if (dp >= edp)
436 error = uiomove(dirbuf, readcnt, &auio);
437 }
438 FREE(dirbuf, M_TEMP);
439 }
440 VOP_UNLOCK(vp);
441 if (error)
442 return (error);
443
444 #ifdef UNION
445 {
446 extern int (**union_vnodeop_p)();
447 extern struct vnode *union_dircache __P((struct vnode *));
448
449 if ((SCARG(uap, count) == auio.uio_resid) &&
450 (vp->v_op == union_vnodeop_p)) {
451 struct vnode *lvp;
452
453 lvp = union_dircache(vp);
454 if (lvp != NULLVP) {
455 struct vattr va;
456
457 /*
458 * If the directory is opaque,
459 * then don't show lower entries
460 */
461 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
462 if (va.va_flags & OPAQUE) {
463 vput(lvp);
464 lvp = NULL;
465 }
466 }
467
468 if (lvp != NULLVP) {
469 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
470 VOP_UNLOCK(lvp);
471
472 if (error) {
473 vrele(lvp);
474 return (error);
475 }
476 fp->f_data = (caddr_t) lvp;
477 fp->f_offset = 0;
478 error = vn_close(vp, FREAD, fp->f_cred, p);
479 if (error)
480 return (error);
481 vp = lvp;
482 goto unionread;
483 }
484 }
485 }
486 #endif /* UNION */
487
488 if ((SCARG(uap, count) == auio.uio_resid) &&
489 (vp->v_flag & VROOT) &&
490 (vp->v_mount->mnt_flag & MNT_UNION)) {
491 struct vnode *tvp = vp;
492 vp = vp->v_mount->mnt_vnodecovered;
493 VREF(vp);
494 fp->f_data = (caddr_t) vp;
495 fp->f_offset = 0;
496 vrele(tvp);
497 goto unionread;
498 }
499 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
500 sizeof(long));
501 *retval = SCARG(uap, count) - auio.uio_resid;
502 return (error);
503 }
504