1 /* $NetBSD: netbsd32_fs.c,v 1.55 2008/06/24 11:18:15 ad Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2001 Matthew R. Green
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.55 2008/06/24 11:18:15 ad Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/socketvar.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <sys/ktrace.h>
41 #include <sys/resourcevar.h>
42 #include <sys/vnode.h>
43 #include <sys/file.h>
44 #include <sys/filedesc.h>
45 #include <sys/namei.h>
46 #include <sys/statvfs.h>
47 #include <sys/syscallargs.h>
48 #include <sys/proc.h>
49 #include <sys/dirent.h>
50 #include <sys/kauth.h>
51 #include <sys/vfs_syscalls.h>
52
53 #include <compat/netbsd32/netbsd32.h>
54 #include <compat/netbsd32/netbsd32_syscallargs.h>
55 #include <compat/netbsd32/netbsd32_conv.h>
56 #include <compat/sys/mount.h>
57
58
59 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *,
60 int, off_t *, int, register_t *);
61 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *,
62 int, off_t *, int, register_t *);
63
64 struct iovec *
65 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov,
66 int aiov_len)
67 {
68 #define N_IOV32 8
69 struct netbsd32_iovec aiov32[N_IOV32];
70 struct iovec *iov = aiov;
71 struct iovec *iovp;
72 int i, n, j;
73 int error;
74
75 if (iovlen < 0 || iovlen > IOV_MAX)
76 return NULL;
77
78 if (iovlen > aiov_len)
79 iov = malloc(iovlen * sizeof (*iov), M_TEMP, M_WAITOK);
80
81 iovp = iov;
82 for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) {
83 n = iovlen - i;
84 if (n > N_IOV32)
85 n = N_IOV32;
86 error = copyin(iov32, aiov32, n * sizeof (*iov32));
87 if (error != 0) {
88 if (iov != aiov)
89 free(iov, M_TEMP);
90 return NULL;
91 }
92 for (j = 0; j < n; iovp++, j++) {
93 iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base);
94 iovp->iov_len = aiov32[j].iov_len;
95 }
96 }
97 return iov;
98 #undef N_IOV32
99 }
100
101 int
102 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval)
103 {
104 /* {
105 syscallarg(int) fd;
106 syscallarg(const netbsd32_iovecp_t) iovp;
107 syscallarg(int) iovcnt;
108 } */
109 int fd = SCARG(uap, fd);
110 file_t *fp;
111
112 if ((fp = fd_getfile(fd)) == NULL)
113 return (EBADF);
114
115 if ((fp->f_flag & FREAD) == 0) {
116 fd_putfile(fd);
117 return (EBADF);
118 }
119
120 return (dofilereadv32(fd, fp,
121 (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
122 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
123 }
124
125 /* Damn thing copies in the iovec! */
126 int
127 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
128 {
129 struct uio auio;
130 struct iovec *iov;
131 struct iovec *needfree;
132 struct iovec aiov[UIO_SMALLIOV];
133 long i, cnt, error = 0;
134 u_int iovlen;
135 struct iovec *ktriov = NULL;
136
137 /* note: can't use iovlen until iovcnt is validated */
138 iovlen = iovcnt * sizeof(struct iovec);
139 if ((u_int)iovcnt > UIO_SMALLIOV) {
140 if ((u_int)iovcnt > IOV_MAX) {
141 error = EINVAL;
142 goto out;
143 }
144 iov = malloc(iovlen, M_IOV, M_WAITOK);
145 needfree = iov;
146 } else if ((u_int)iovcnt > 0) {
147 iov = aiov;
148 needfree = NULL;
149 } else {
150 error = EINVAL;
151 goto out;
152 }
153
154 auio.uio_iov = iov;
155 auio.uio_iovcnt = iovcnt;
156 auio.uio_rw = UIO_READ;
157 auio.uio_vmspace = curproc->p_vmspace;
158 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
159 if (error)
160 goto done;
161 auio.uio_resid = 0;
162 for (i = 0; i < iovcnt; i++) {
163 auio.uio_resid += iov->iov_len;
164 /*
165 * Reads return ssize_t because -1 is returned on error.
166 * Therefore we must restrict the length to SSIZE_MAX to
167 * avoid garbage return values.
168 */
169 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
170 error = EINVAL;
171 goto done;
172 }
173 iov++;
174 }
175
176 /*
177 * if tracing, save a copy of iovec
178 */
179 if (ktrpoint(KTR_GENIO)) {
180 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
181 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
182 }
183
184 cnt = auio.uio_resid;
185 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
186 if (error)
187 if (auio.uio_resid != cnt && (error == ERESTART ||
188 error == EINTR || error == EWOULDBLOCK))
189 error = 0;
190 cnt -= auio.uio_resid;
191
192 if (ktriov != NULL) {
193 ktrgeniov(fd, UIO_READ, ktriov, cnt, error);
194 free(ktriov, M_TEMP);
195 }
196
197 *retval = cnt;
198 done:
199 if (needfree)
200 free(needfree, M_IOV);
201 out:
202 fd_putfile(fd);
203 return (error);
204 }
205
206 int
207 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval)
208 {
209 /* {
210 syscallarg(int) fd;
211 syscallarg(const netbsd32_iovecp_t) iovp;
212 syscallarg(int) iovcnt;
213 } */
214 int fd = SCARG(uap, fd);
215 file_t *fp;
216
217 if ((fp = fd_getfile(fd)) == NULL)
218 return (EBADF);
219
220 if ((fp->f_flag & FWRITE) == 0) {
221 fd_putfile(fd);
222 return (EBADF);
223 }
224
225 return (dofilewritev32(fd, fp,
226 (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
227 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
228 }
229
230 int
231 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
232 {
233 struct uio auio;
234 struct iovec *iov;
235 struct iovec *needfree;
236 struct iovec aiov[UIO_SMALLIOV];
237 long i, cnt, error = 0;
238 u_int iovlen;
239 struct iovec *ktriov = NULL;
240
241 /* note: can't use iovlen until iovcnt is validated */
242 iovlen = iovcnt * sizeof(struct iovec);
243 if ((u_int)iovcnt > UIO_SMALLIOV) {
244 if ((u_int)iovcnt > IOV_MAX) {
245 error = EINVAL;
246 goto out;
247 }
248 iov = malloc(iovlen, M_IOV, M_WAITOK);
249 needfree = iov;
250 } else if ((u_int)iovcnt > 0) {
251 iov = aiov;
252 needfree = NULL;
253 } else {
254 error = EINVAL;
255 goto out;
256 }
257
258 auio.uio_iov = iov;
259 auio.uio_iovcnt = iovcnt;
260 auio.uio_rw = UIO_WRITE;
261 auio.uio_vmspace = curproc->p_vmspace;
262 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
263 if (error)
264 goto done;
265 auio.uio_resid = 0;
266 for (i = 0; i < iovcnt; i++) {
267 auio.uio_resid += iov->iov_len;
268 /*
269 * Writes return ssize_t because -1 is returned on error.
270 * Therefore we must restrict the length to SSIZE_MAX to
271 * avoid garbage return values.
272 */
273 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
274 error = EINVAL;
275 goto done;
276 }
277 iov++;
278 }
279
280 /*
281 * if tracing, save a copy of iovec
282 */
283 if (ktrpoint(KTR_GENIO)) {
284 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
285 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
286 }
287
288 cnt = auio.uio_resid;
289 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
290 if (error) {
291 if (auio.uio_resid != cnt && (error == ERESTART ||
292 error == EINTR || error == EWOULDBLOCK))
293 error = 0;
294 if (error == EPIPE) {
295 mutex_enter(proc_lock);
296 psignal(curproc, SIGPIPE);
297 mutex_exit(proc_lock);
298 }
299 }
300 cnt -= auio.uio_resid;
301 if (ktriov != NULL) {
302 ktrgenio(fd, UIO_WRITE, ktriov, cnt, error);
303 free(ktriov, M_TEMP);
304 }
305 *retval = cnt;
306 done:
307 if (needfree)
308 free(needfree, M_IOV);
309 out:
310 fd_putfile(fd);
311 return (error);
312 }
313
314 /*
315 * Common routine to set access and modification times given a vnode.
316 */
317 static int
318 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv,
319 struct timeval **tvp)
320 {
321 int error;
322 struct netbsd32_timeval tv32[2];
323
324 if (tptr == NULL) {
325 *tvp = NULL;
326 return 0;
327 }
328
329 error = copyin(tptr, tv32, sizeof(tv32));
330 if (error)
331 return error;
332 netbsd32_to_timeval(&tv32[0], &tv[0]);
333 netbsd32_to_timeval(&tv32[1], &tv[1]);
334
335 *tvp = tv;
336 return 0;
337 }
338
339 int
340 netbsd32_utimes(struct lwp *l, const struct netbsd32_utimes_args *uap, register_t *retval)
341 {
342 /* {
343 syscallarg(const netbsd32_charp) path;
344 syscallarg(const netbsd32_timevalp_t) tptr;
345 } */
346 int error;
347 struct timeval tv[2], *tvp;
348
349 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
350 if (error != 0)
351 return error;
352
353 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
354 tvp, UIO_SYSSPACE);
355 }
356
357 static int
358 netbds32_copyout_statvfs(const void *kp, void *up, size_t len)
359 {
360 struct netbsd32_statvfs *sbuf_32;
361 int error;
362
363 sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK);
364 netbsd32_from_statvfs(kp, sbuf_32);
365 error = copyout(sbuf_32, up, sizeof(*sbuf_32));
366 free(sbuf_32, M_TEMP);
367
368 return error;
369 }
370
371 int
372 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval)
373 {
374 /* {
375 syscallarg(const netbsd32_charp) path;
376 syscallarg(netbsd32_statvfsp_t) buf;
377 syscallarg(int) flags;
378 } */
379 struct statvfs *sb;
380 int error;
381
382 sb = STATVFSBUF_GET();
383 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb);
384 if (error == 0)
385 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
386 STATVFSBUF_PUT(sb);
387 return error;
388 }
389
390 int
391 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval)
392 {
393 /* {
394 syscallarg(int) fd;
395 syscallarg(netbsd32_statvfsp_t) buf;
396 syscallarg(int) flags;
397 } */
398 struct statvfs *sb;
399 int error;
400
401 sb = STATVFSBUF_GET();
402 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
403 if (error == 0)
404 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
405 STATVFSBUF_PUT(sb);
406 return error;
407 }
408
409 int
410 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval)
411 {
412 /* {
413 syscallarg(netbsd32_statvfsp_t) buf;
414 syscallarg(netbsd32_size_t) bufsize;
415 syscallarg(int) flags;
416 } */
417
418 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize),
419 SCARG(uap, flags), netbds32_copyout_statvfs,
420 sizeof (struct netbsd32_statvfs), retval);
421 }
422
423 int
424 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval)
425 {
426 /* {
427 syscallarg(const netbsd32_pointer_t) fhp;
428 syscallarg(netbsd32_size_t) fh_size;
429 syscallarg(netbsd32_statvfsp_t) buf;
430 syscallarg(int) flags;
431 } */
432 struct statvfs *sb;
433 int error;
434
435 sb = STATVFSBUF_GET();
436 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb,
437 SCARG(uap, flags));
438
439 if (error == 0)
440 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
441 STATVFSBUF_PUT(sb);
442
443 return error;
444 }
445
446 int
447 netbsd32_futimes(struct lwp *l, const struct netbsd32_futimes_args *uap, register_t *retval)
448 {
449 /* {
450 syscallarg(int) fd;
451 syscallarg(const netbsd32_timevalp_t) tptr;
452 } */
453 int error;
454 file_t *fp;
455 struct timeval tv[2], *tvp;
456
457 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
458 if (error != 0)
459 return error;
460
461 /* fd_getvnode() will use the descriptor for us */
462 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
463 return (error);
464
465 error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE);
466
467 fd_putfile(SCARG(uap, fd));
468 return (error);
469 }
470
471 int
472 netbsd32_sys___getdents30(struct lwp *l, const struct netbsd32_sys___getdents30_args *uap, register_t *retval)
473 {
474 /* {
475 syscallarg(int) fd;
476 syscallarg(netbsd32_charp) buf;
477 syscallarg(netbsd32_size_t) count;
478 } */
479 file_t *fp;
480 int error, done;
481
482 /* fd_getvnode() will use the descriptor for us */
483 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
484 return (error);
485 if ((fp->f_flag & FREAD) == 0) {
486 error = EBADF;
487 goto out;
488 }
489 error = vn_readdir(fp, SCARG_P32(uap, buf),
490 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
491 *retval = done;
492 out:
493 fd_putfile(SCARG(uap, fd));
494 return (error);
495 }
496
497 int
498 netbsd32_lutimes(struct lwp *l, const struct netbsd32_lutimes_args *uap, register_t *retval)
499 {
500 /* {
501 syscallarg(const netbsd32_charp) path;
502 syscallarg(const netbsd32_timevalp_t) tptr;
503 } */
504 int error;
505 struct timeval tv[2], *tvp;
506
507 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
508 if (error != 0)
509 return error;
510
511 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW,
512 tvp, UIO_SYSSPACE);
513 }
514
515 int
516 netbsd32_sys___stat30(struct lwp *l, const struct netbsd32_sys___stat30_args *uap, register_t *retval)
517 {
518 /* {
519 syscallarg(const netbsd32_charp) path;
520 syscallarg(netbsd32_statp_t) ub;
521 } */
522 struct netbsd32_stat sb32;
523 struct stat sb;
524 int error;
525 const char *path;
526
527 path = SCARG_P32(uap, path);
528
529 error = do_sys_stat(path, FOLLOW, &sb);
530 if (error)
531 return (error);
532 netbsd32_from___stat30(&sb, &sb32);
533 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
534 return (error);
535 }
536
537 int
538 netbsd32_sys___fstat30(struct lwp *l, const struct netbsd32_sys___fstat30_args *uap, register_t *retval)
539 {
540 /* {
541 syscallarg(int) fd;
542 syscallarg(netbsd32_statp_t) sb;
543 } */
544 int fd = SCARG(uap, fd);
545 file_t *fp;
546 struct netbsd32_stat sb32;
547 struct stat ub;
548 int error = 0;
549
550 if ((fp = fd_getfile(fd)) == NULL)
551 return (EBADF);
552 error = (*fp->f_ops->fo_stat)(fp, &ub);
553 fd_putfile(fd);
554 if (error == 0) {
555 netbsd32_from___stat30(&ub, &sb32);
556 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32));
557 }
558 return (error);
559 }
560
561 int
562 netbsd32_sys___lstat30(struct lwp *l, const struct netbsd32_sys___lstat30_args *uap, register_t *retval)
563 {
564 /* {
565 syscallarg(const netbsd32_charp) path;
566 syscallarg(netbsd32_statp_t) ub;
567 } */
568 struct netbsd32_stat sb32;
569 struct stat sb;
570 int error;
571 const char *path;
572
573 path = SCARG_P32(uap, path);
574
575 error = do_sys_stat(path, NOFOLLOW, &sb);
576 if (error)
577 return (error);
578 netbsd32_from___stat30(&sb, &sb32);
579 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
580 return (error);
581 }
582
583 int
584 netbsd32___fhstat40(struct lwp *l, const struct netbsd32___fhstat40_args *uap, register_t *retval)
585 {
586 /* {
587 syscallarg(const netbsd32_pointer_t) fhp;
588 syscallarg(netbsd32_size_t) fh_size;
589 syscallarg(netbsd32_statp_t) sb;
590 } */
591 struct stat sb;
592 struct netbsd32_stat sb32;
593 int error;
594
595 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb);
596 if (error != 0) {
597 netbsd32_from___stat30(&sb, &sb32);
598 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb));
599 }
600 return error;
601 }
602
603 int
604 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval)
605 {
606 /* {
607 syscallarg(int) fd;
608 syscallarg(const netbsd32_iovecp_t) iovp;
609 syscallarg(int) iovcnt;
610 syscallarg(int) pad;
611 syscallarg(off_t) offset;
612 } */
613 file_t *fp;
614 struct vnode *vp;
615 off_t offset;
616 int error, fd = SCARG(uap, fd);
617
618 if ((fp = fd_getfile(fd)) == NULL)
619 return (EBADF);
620
621 if ((fp->f_flag & FREAD) == 0) {
622 fd_putfile(fd);
623 return (EBADF);
624 }
625
626 vp = fp->f_data;
627 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
628 error = ESPIPE;
629 goto out;
630 }
631
632 offset = SCARG(uap, offset);
633
634 /*
635 * XXX This works because no file systems actually
636 * XXX take any action on the seek operation.
637 */
638 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
639 goto out;
640
641 return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp),
642 SCARG(uap, iovcnt), &offset, 0, retval));
643
644 out:
645 fd_putfile(fd);
646 return (error);
647 }
648
649 int
650 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval)
651 {
652 /* {
653 syscallarg(int) fd;
654 syscallarg(const netbsd32_iovecp_t) iovp;
655 syscallarg(int) iovcnt;
656 syscallarg(int) pad;
657 syscallarg(off_t) offset;
658 } */
659 file_t *fp;
660 struct vnode *vp;
661 off_t offset;
662 int error, fd = SCARG(uap, fd);
663
664 if ((fp = fd_getfile(fd)) == NULL)
665 return (EBADF);
666
667 if ((fp->f_flag & FWRITE) == 0) {
668 fd_putfile(fd);
669 return (EBADF);
670 }
671
672 vp = fp->f_data;
673 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
674 error = ESPIPE;
675 goto out;
676 }
677
678 offset = SCARG(uap, offset);
679
680 /*
681 * XXX This works because no file systems actually
682 * XXX take any action on the seek operation.
683 */
684 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
685 goto out;
686
687 return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp),
688 SCARG(uap, iovcnt), &offset, 0, retval));
689
690 out:
691 fd_putfile(fd);
692 return (error);
693 }
694
695 /*
696 * Find pathname of process's current directory.
697 *
698 * Use vfs vnode-to-name reverse cache; if that fails, fall back
699 * to reading directory contents.
700 */
701 /* XXX NH Why does this exist */
702 int
703 getcwd_common(struct vnode *, struct vnode *,
704 char **, char *, int, int, struct lwp *);
705
706 int
707 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval)
708 {
709 /* {
710 syscallarg(char *) bufp;
711 syscallarg(size_t) length;
712 } */
713 struct proc *p = l->l_proc;
714 int error;
715 char *path;
716 char *bp, *bend;
717 int len = (int)SCARG(uap, length);
718 int lenused;
719 struct cwdinfo *cwdi;
720
721 if (len > MAXPATHLEN*4)
722 len = MAXPATHLEN*4;
723 else if (len < 2)
724 return ERANGE;
725
726 path = (char *)malloc(len, M_TEMP, M_WAITOK);
727 if (!path)
728 return ENOMEM;
729
730 bp = &path[len];
731 bend = bp;
732 *(--bp) = '\0';
733
734 /*
735 * 5th argument here is "max number of vnodes to traverse".
736 * Since each entry takes up at least 2 bytes in the output buffer,
737 * limit it to N/2 vnodes for an N byte buffer.
738 */
739 #define GETCWD_CHECK_ACCESS 0x0001
740 cwdi = p->p_cwdi;
741 rw_enter(&cwdi->cwdi_lock, RW_READER);
742 error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2,
743 GETCWD_CHECK_ACCESS, l);
744 rw_exit(&cwdi->cwdi_lock);
745
746 if (error)
747 goto out;
748 lenused = bend - bp;
749 *retval = lenused;
750 /* put the result into user buffer */
751 error = copyout(bp, SCARG_P32(uap, bufp), lenused);
752
753 out:
754 free(path, M_TEMP);
755 return error;
756 }
Cache object: 3441c1d0025948f5b53c13242389b5c7
|