Line data Source code
1 : /* $OpenBSD: vfs_vnops.c,v 1.97 2018/08/20 16:00:22 mpi Exp $ */
2 : /* $NetBSD: vfs_vnops.c,v 1.20 1996/02/04 02:18:41 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1982, 1986, 1989, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : * (c) UNIX System Laboratories, Inc.
8 : * All or some portions of this file are derived from material licensed
9 : * to the University of California by American Telephone and Telegraph
10 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 : * the permission of UNIX System Laboratories, Inc.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)vfs_vnops.c 8.5 (Berkeley) 12/8/94
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/kernel.h>
43 : #include <sys/malloc.h>
44 : #include <sys/fcntl.h>
45 : #include <sys/file.h>
46 : #include <sys/stat.h>
47 : #include <sys/proc.h>
48 : #include <sys/resourcevar.h>
49 : #include <sys/signalvar.h>
50 : #include <sys/mount.h>
51 : #include <sys/namei.h>
52 : #include <sys/lock.h>
53 : #include <sys/vnode.h>
54 : #include <sys/ioctl.h>
55 : #include <sys/tty.h>
56 : #include <sys/cdio.h>
57 : #include <sys/poll.h>
58 : #include <sys/filedesc.h>
59 : #include <sys/specdev.h>
60 : #include <sys/unistd.h>
61 :
62 : int vn_read(struct file *, struct uio *, int);
63 : int vn_write(struct file *, struct uio *, int);
64 : int vn_poll(struct file *, int, struct proc *);
65 : int vn_kqfilter(struct file *, struct knote *);
66 : int vn_closefile(struct file *, struct proc *);
67 : int vn_seek(struct file *, off_t *, int, struct proc *);
68 :
69 : struct fileops vnops = {
70 : .fo_read = vn_read,
71 : .fo_write = vn_write,
72 : .fo_ioctl = vn_ioctl,
73 : .fo_poll = vn_poll,
74 : .fo_kqfilter = vn_kqfilter,
75 : .fo_stat = vn_statfile,
76 : .fo_close = vn_closefile,
77 : .fo_seek = vn_seek,
78 : };
79 :
80 : /*
81 : * Common code for vnode open operations.
82 : * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
83 : */
84 : int
85 0 : vn_open(struct nameidata *ndp, int fmode, int cmode)
86 : {
87 : struct vnode *vp;
88 0 : struct proc *p = ndp->ni_cnd.cn_proc;
89 0 : struct ucred *cred = p->p_ucred;
90 0 : struct vattr va;
91 : struct cloneinfo *cip;
92 : int error;
93 :
94 0 : if ((fmode & (FREAD|FWRITE)) == 0)
95 0 : return (EINVAL);
96 0 : if ((fmode & (O_TRUNC | FWRITE)) == O_TRUNC)
97 0 : return (EINVAL);
98 0 : if (fmode & O_CREAT) {
99 0 : ndp->ni_cnd.cn_nameiop = CREATE;
100 0 : ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
101 0 : if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
102 0 : ndp->ni_cnd.cn_flags |= FOLLOW;
103 0 : if ((error = namei(ndp)) != 0)
104 0 : return (error);
105 :
106 0 : if (ndp->ni_vp == NULL) {
107 0 : VATTR_NULL(&va);
108 0 : va.va_type = VREG;
109 0 : va.va_mode = cmode;
110 0 : if (fmode & O_EXCL)
111 0 : va.va_vaflags |= VA_EXCLUSIVE;
112 0 : error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
113 : &ndp->ni_cnd, &va);
114 0 : vput(ndp->ni_dvp);
115 0 : if (error)
116 0 : return (error);
117 0 : fmode &= ~O_TRUNC;
118 0 : vp = ndp->ni_vp;
119 0 : } else {
120 0 : VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
121 0 : if (ndp->ni_dvp == ndp->ni_vp)
122 0 : vrele(ndp->ni_dvp);
123 : else
124 0 : vput(ndp->ni_dvp);
125 0 : ndp->ni_dvp = NULL;
126 0 : vp = ndp->ni_vp;
127 0 : if (fmode & O_EXCL) {
128 : error = EEXIST;
129 0 : goto bad;
130 : }
131 0 : fmode &= ~O_CREAT;
132 : }
133 : } else {
134 0 : ndp->ni_cnd.cn_nameiop = LOOKUP;
135 0 : ndp->ni_cnd.cn_flags =
136 0 : ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF;
137 0 : if ((error = namei(ndp)) != 0)
138 0 : return (error);
139 0 : vp = ndp->ni_vp;
140 : }
141 0 : if (vp->v_type == VSOCK) {
142 : error = EOPNOTSUPP;
143 0 : goto bad;
144 : }
145 0 : if (vp->v_type == VLNK) {
146 : error = ELOOP;
147 0 : goto bad;
148 : }
149 0 : if ((fmode & O_DIRECTORY) && vp->v_type != VDIR) {
150 : error = ENOTDIR;
151 0 : goto bad;
152 : }
153 0 : if ((fmode & O_CREAT) == 0) {
154 0 : if (fmode & FREAD) {
155 0 : if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
156 : goto bad;
157 : }
158 0 : if (fmode & FWRITE) {
159 0 : if (vp->v_type == VDIR) {
160 : error = EISDIR;
161 0 : goto bad;
162 : }
163 0 : if ((error = vn_writechk(vp)) != 0 ||
164 0 : (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
165 : goto bad;
166 : }
167 : }
168 0 : if ((fmode & O_TRUNC) && vp->v_type == VREG) {
169 0 : VATTR_NULL(&va);
170 0 : va.va_size = 0;
171 0 : if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
172 : goto bad;
173 : }
174 0 : if ((error = VOP_OPEN(vp, fmode, cred, p)) != 0)
175 : goto bad;
176 :
177 0 : if (vp->v_flag & VCLONED) {
178 0 : cip = (struct cloneinfo *)vp->v_data;
179 :
180 0 : vp->v_flag &= ~VCLONED;
181 :
182 0 : ndp->ni_vp = cip->ci_vp; /* return cloned vnode */
183 0 : vp->v_data = cip->ci_data; /* restore v_data */
184 0 : VOP_UNLOCK(vp); /* keep a reference */
185 0 : vp = ndp->ni_vp; /* for the increment below */
186 :
187 0 : free(cip, M_TEMP, sizeof(*cip));
188 0 : }
189 :
190 0 : if (fmode & FWRITE)
191 0 : vp->v_writecount++;
192 0 : return (0);
193 : bad:
194 0 : vput(vp);
195 0 : return (error);
196 0 : }
197 :
198 : /*
199 : * Check for write permissions on the specified vnode.
200 : * Prototype text segments cannot be written.
201 : */
202 : int
203 0 : vn_writechk(struct vnode *vp)
204 : {
205 : /*
206 : * Disallow write attempts on read-only file systems;
207 : * unless the file is a socket or a block or character
208 : * device resident on the file system.
209 : */
210 0 : if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
211 0 : switch (vp->v_type) {
212 : case VREG:
213 : case VDIR:
214 : case VLNK:
215 0 : return (EROFS);
216 : case VNON:
217 : case VCHR:
218 : case VSOCK:
219 : case VFIFO:
220 : case VBAD:
221 : case VBLK:
222 : break;
223 : }
224 : }
225 : /*
226 : * If there's shared text associated with
227 : * the vnode, try to free it up once. If
228 : * we fail, we can't allow writing.
229 : */
230 0 : if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
231 0 : return (ETXTBSY);
232 :
233 0 : return (0);
234 0 : }
235 :
236 : /*
237 : * Check whether a write operation would exceed the file size rlimit
238 : * for the process, if one should be applied for this operation.
239 : * If a partial write should take place, the uio is adjusted and the
240 : * amount by which the request would have exceeded the limit is returned
241 : * via the 'overrun' argument.
242 : */
243 : int
244 0 : vn_fsizechk(struct vnode *vp, struct uio *uio, int ioflag, ssize_t *overrun)
245 : {
246 0 : struct proc *p = uio->uio_procp;
247 :
248 0 : *overrun = 0;
249 0 : if (vp->v_type == VREG && p != NULL && !(ioflag & IO_NOLIMIT)) {
250 0 : rlim_t limit = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
251 :
252 : /* if already at or over the limit, send the signal and fail */
253 0 : if (uio->uio_offset >= limit) {
254 0 : psignal(p, SIGXFSZ);
255 0 : return (EFBIG);
256 : }
257 :
258 : /* otherwise, clamp the write to stay under the limit */
259 0 : if (uio->uio_resid > limit - uio->uio_offset) {
260 0 : *overrun = uio->uio_resid - (limit - uio->uio_offset);
261 0 : uio->uio_resid = limit - uio->uio_offset;
262 0 : }
263 0 : }
264 :
265 0 : return (0);
266 0 : }
267 :
268 :
269 : /*
270 : * Mark a vnode as being the text image of a running process.
271 : */
272 : void
273 0 : vn_marktext(struct vnode *vp)
274 : {
275 0 : vp->v_flag |= VTEXT;
276 0 : }
277 :
278 : /*
279 : * Vnode close call
280 : */
281 : int
282 0 : vn_close(struct vnode *vp, int flags, struct ucred *cred, struct proc *p)
283 : {
284 : int error;
285 :
286 0 : if (flags & FWRITE)
287 0 : vp->v_writecount--;
288 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
289 0 : error = VOP_CLOSE(vp, flags, cred, p);
290 0 : vput(vp);
291 0 : return (error);
292 : }
293 :
294 : /*
295 : * Package up an I/O request on a vnode into a uio and do it.
296 : */
297 : int
298 0 : vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, int len, off_t offset,
299 : enum uio_seg segflg, int ioflg, struct ucred *cred, size_t *aresid,
300 : struct proc *p)
301 : {
302 0 : struct uio auio;
303 0 : struct iovec aiov;
304 : int error;
305 :
306 0 : auio.uio_iov = &aiov;
307 0 : auio.uio_iovcnt = 1;
308 0 : aiov.iov_base = base;
309 0 : aiov.iov_len = len;
310 0 : auio.uio_resid = len;
311 0 : auio.uio_offset = offset;
312 0 : auio.uio_segflg = segflg;
313 0 : auio.uio_rw = rw;
314 0 : auio.uio_procp = p;
315 :
316 0 : if ((ioflg & IO_NODELOCKED) == 0)
317 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
318 0 : if (rw == UIO_READ) {
319 0 : error = VOP_READ(vp, &auio, ioflg, cred);
320 0 : } else {
321 0 : error = VOP_WRITE(vp, &auio, ioflg, cred);
322 : }
323 0 : if ((ioflg & IO_NODELOCKED) == 0)
324 0 : VOP_UNLOCK(vp);
325 :
326 0 : if (aresid)
327 0 : *aresid = auio.uio_resid;
328 : else
329 0 : if (auio.uio_resid && error == 0)
330 0 : error = EIO;
331 0 : return (error);
332 0 : }
333 :
334 : /*
335 : * File table vnode read routine.
336 : */
337 : int
338 0 : vn_read(struct file *fp, struct uio *uio, int fflags)
339 : {
340 0 : struct vnode *vp = fp->f_data;
341 0 : struct ucred *cred = fp->f_cred;
342 0 : size_t count = uio->uio_resid;
343 : off_t offset;
344 : int error;
345 :
346 : /*
347 : * Check below can race. We can block on the vnode lock
348 : * and resume with a different `fp->f_offset' value.
349 : */
350 0 : if ((fflags & FO_POSITION) == 0)
351 0 : offset = fp->f_offset;
352 : else
353 0 : offset = uio->uio_offset;
354 :
355 : /* no wrap around of offsets except on character devices */
356 0 : if (vp->v_type != VCHR && count > LLONG_MAX - offset)
357 0 : return (EINVAL);
358 :
359 0 : if (vp->v_type == VDIR)
360 0 : return (EISDIR);
361 :
362 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
363 0 : if ((fflags & FO_POSITION) == 0)
364 0 : uio->uio_offset = fp->f_offset;
365 0 : error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
366 : cred);
367 0 : if ((fflags & FO_POSITION) == 0)
368 0 : fp->f_offset += count - uio->uio_resid;
369 0 : VOP_UNLOCK(vp);
370 0 : return (error);
371 0 : }
372 :
373 : /*
374 : * File table vnode write routine.
375 : */
376 : int
377 0 : vn_write(struct file *fp, struct uio *uio, int fflags)
378 : {
379 0 : struct vnode *vp = fp->f_data;
380 0 : struct ucred *cred = fp->f_cred;
381 : int error, ioflag = IO_UNIT;
382 : size_t count;
383 :
384 : /* note: pwrite/pwritev are unaffected by O_APPEND */
385 0 : if (vp->v_type == VREG && (fp->f_flag & O_APPEND) &&
386 0 : (fflags & FO_POSITION) == 0)
387 0 : ioflag |= IO_APPEND;
388 0 : if (fp->f_flag & FNONBLOCK)
389 0 : ioflag |= IO_NDELAY;
390 0 : if ((fp->f_flag & FFSYNC) ||
391 0 : (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
392 0 : ioflag |= IO_SYNC;
393 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
394 0 : if ((fflags & FO_POSITION) == 0)
395 0 : uio->uio_offset = fp->f_offset;
396 0 : count = uio->uio_resid;
397 0 : error = VOP_WRITE(vp, uio, ioflag, cred);
398 0 : if ((fflags & FO_POSITION) == 0) {
399 0 : if (ioflag & IO_APPEND)
400 0 : fp->f_offset = uio->uio_offset;
401 : else
402 0 : fp->f_offset += count - uio->uio_resid;
403 : }
404 0 : VOP_UNLOCK(vp);
405 0 : return (error);
406 : }
407 :
408 : /*
409 : * File table wrapper for vn_stat
410 : */
411 : int
412 0 : vn_statfile(struct file *fp, struct stat *sb, struct proc *p)
413 : {
414 0 : struct vnode *vp = fp->f_data;
415 0 : return vn_stat(vp, sb, p);
416 : }
417 :
418 : /*
419 : * vnode stat routine.
420 : */
421 : int
422 0 : vn_stat(struct vnode *vp, struct stat *sb, struct proc *p)
423 : {
424 0 : struct vattr va;
425 : int error;
426 : mode_t mode;
427 :
428 0 : error = VOP_GETATTR(vp, &va, p->p_ucred, p);
429 0 : if (error)
430 0 : return (error);
431 : /*
432 : * Copy from vattr table
433 : */
434 0 : memset(sb, 0, sizeof(*sb));
435 0 : sb->st_dev = va.va_fsid;
436 0 : sb->st_ino = va.va_fileid;
437 0 : mode = va.va_mode;
438 0 : switch (vp->v_type) {
439 : case VREG:
440 0 : mode |= S_IFREG;
441 0 : break;
442 : case VDIR:
443 0 : mode |= S_IFDIR;
444 0 : break;
445 : case VBLK:
446 0 : mode |= S_IFBLK;
447 0 : break;
448 : case VCHR:
449 0 : mode |= S_IFCHR;
450 0 : break;
451 : case VLNK:
452 0 : mode |= S_IFLNK;
453 0 : break;
454 : case VSOCK:
455 0 : mode |= S_IFSOCK;
456 0 : break;
457 : case VFIFO:
458 0 : mode |= S_IFIFO;
459 0 : break;
460 : default:
461 0 : return (EBADF);
462 : }
463 0 : sb->st_mode = mode;
464 0 : sb->st_nlink = va.va_nlink;
465 0 : sb->st_uid = va.va_uid;
466 0 : sb->st_gid = va.va_gid;
467 0 : sb->st_rdev = va.va_rdev;
468 0 : sb->st_size = va.va_size;
469 0 : sb->st_atim.tv_sec = va.va_atime.tv_sec;
470 0 : sb->st_atim.tv_nsec = va.va_atime.tv_nsec;
471 0 : sb->st_mtim.tv_sec = va.va_mtime.tv_sec;
472 0 : sb->st_mtim.tv_nsec = va.va_mtime.tv_nsec;
473 0 : sb->st_ctim.tv_sec = va.va_ctime.tv_sec;
474 0 : sb->st_ctim.tv_nsec = va.va_ctime.tv_nsec;
475 0 : sb->st_blksize = va.va_blocksize;
476 0 : sb->st_flags = va.va_flags;
477 0 : sb->st_gen = va.va_gen;
478 0 : sb->st_blocks = va.va_bytes / S_BLKSIZE;
479 0 : return (0);
480 0 : }
481 :
482 : /*
483 : * File table vnode ioctl routine.
484 : */
485 : int
486 0 : vn_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
487 : {
488 0 : struct vnode *vp = fp->f_data;
489 0 : struct vattr vattr;
490 : int error;
491 :
492 0 : switch (vp->v_type) {
493 :
494 : case VREG:
495 : case VDIR:
496 0 : if (com == FIONREAD) {
497 0 : error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
498 0 : if (error)
499 0 : return (error);
500 0 : *(int *)data = vattr.va_size - fp->f_offset;
501 0 : return (0);
502 : }
503 0 : if (com == FIONBIO || com == FIOASYNC) /* XXX */
504 0 : return (0); /* XXX */
505 : /* FALLTHROUGH */
506 : default:
507 0 : return (ENOTTY);
508 :
509 : case VFIFO:
510 : case VCHR:
511 : case VBLK:
512 0 : error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
513 60 : if (error == 0 && com == TIOCSCTTY) {
514 0 : struct session *s = p->p_p->ps_session;
515 0 : struct vnode *ovp = s->s_ttyvp;
516 0 : s->s_ttyvp = vp;
517 0 : vref(vp);
518 0 : if (ovp)
519 0 : vrele(ovp);
520 0 : }
521 0 : return (error);
522 : }
523 0 : }
524 :
525 : /*
526 : * File table vnode poll routine.
527 : */
528 : int
529 0 : vn_poll(struct file *fp, int events, struct proc *p)
530 : {
531 0 : return (VOP_POLL(fp->f_data, fp->f_flag, events, p));
532 : }
533 :
534 : /*
535 : * Check that the vnode is still valid, and if so
536 : * acquire requested lock.
537 : */
538 : int
539 0 : vn_lock(struct vnode *vp, int flags)
540 : {
541 : int error;
542 :
543 0 : do {
544 0 : if (vp->v_flag & VXLOCK) {
545 0 : vp->v_flag |= VXWANT;
546 0 : tsleep(vp, PINOD, "vn_lock", 0);
547 : error = ENOENT;
548 0 : } else {
549 0 : error = VOP_LOCK(vp, flags);
550 0 : if (error == 0)
551 0 : return (error);
552 : }
553 0 : } while (flags & LK_RETRY);
554 0 : return (error);
555 0 : }
556 :
557 : /*
558 : * File table vnode close routine.
559 : */
560 : int
561 0 : vn_closefile(struct file *fp, struct proc *p)
562 : {
563 0 : struct vnode *vp = fp->f_data;
564 0 : struct flock lf;
565 : int error;
566 :
567 0 : KERNEL_LOCK();
568 0 : if ((fp->f_iflags & FIF_HASLOCK)) {
569 0 : lf.l_whence = SEEK_SET;
570 0 : lf.l_start = 0;
571 0 : lf.l_len = 0;
572 0 : lf.l_type = F_UNLCK;
573 0 : (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
574 0 : }
575 0 : error = vn_close(vp, fp->f_flag, fp->f_cred, p);
576 0 : KERNEL_UNLOCK();
577 0 : return (error);
578 0 : }
579 :
580 : int
581 0 : vn_kqfilter(struct file *fp, struct knote *kn)
582 : {
583 0 : return (VOP_KQFILTER(fp->f_data, kn));
584 : }
585 :
586 : int
587 0 : vn_seek(struct file *fp, off_t *offset, int whence, struct proc *p)
588 : {
589 0 : struct ucred *cred = p->p_ucred;
590 0 : struct vnode *vp = fp->f_data;
591 0 : struct vattr vattr;
592 : off_t newoff;
593 : int error, special;
594 :
595 0 : if (vp->v_type == VFIFO)
596 0 : return (ESPIPE);
597 0 : if (vp->v_type == VCHR)
598 0 : special = 1;
599 : else
600 : special = 0;
601 :
602 0 : switch (whence) {
603 : case SEEK_CUR:
604 0 : newoff = fp->f_offset + *offset;
605 0 : break;
606 : case SEEK_END:
607 0 : error = VOP_GETATTR(vp, &vattr, cred, p);
608 0 : if (error)
609 0 : return (error);
610 0 : newoff = *offset + (off_t)vattr.va_size;
611 0 : break;
612 : case SEEK_SET:
613 0 : newoff = *offset;
614 0 : break;
615 : default:
616 0 : return (EINVAL);
617 : }
618 0 : if (!special) {
619 0 : if (newoff < 0)
620 0 : return(EINVAL);
621 : }
622 0 : fp->f_offset = *offset = newoff;
623 0 : return (0);
624 0 : }
625 :
626 : /*
627 : * Common code for vnode access operations.
628 : */
629 :
630 : /* Check if a directory can be found inside another in the hierarchy */
631 : int
632 0 : vn_isunder(struct vnode *lvp, struct vnode *rvp, struct proc *p)
633 : {
634 : int error;
635 :
636 0 : error = vfs_getcwd_common(lvp, rvp, NULL, NULL, MAXPATHLEN/2, 0, p);
637 :
638 0 : if (!error)
639 0 : return (1);
640 :
641 0 : return (0);
642 0 : }
|