xref: /netbsd-src/sys/fs/udf/udf_vnops.c (revision 975a152cfcdb39ae6e496af647af0c7275ca0b61)
1 /* $NetBSD: udf_vnops.c,v 1.85 2013/07/10 15:10:56 reinoud Exp $ */
2 
3 /*
4  * Copyright (c) 2006, 2008 Reinoud Zandijk
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, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Generic parts are derived from software contributed to The NetBSD Foundation
28  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
29  * 2005 program.
30  *
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.85 2013/07/10 15:10:56 reinoud Exp $");
36 #endif /* not lint */
37 
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/namei.h>
42 #include <sys/resourcevar.h>	/* defines plimit structure in proc struct */
43 #include <sys/kernel.h>
44 #include <sys/file.h>		/* define FWRITE ... */
45 #include <sys/stat.h>
46 #include <sys/buf.h>
47 #include <sys/proc.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/signalvar.h>
51 #include <sys/malloc.h>
52 #include <sys/dirent.h>
53 #include <sys/lockf.h>
54 #include <sys/kauth.h>
55 
56 #include <miscfs/genfs/genfs.h>
57 #include <uvm/uvm_extern.h>
58 
59 #include <fs/udf/ecma167-udf.h>
60 #include <fs/udf/udf_mount.h>
61 #include <sys/dirhash.h>
62 
63 #include "udf.h"
64 #include "udf_subr.h"
65 #include "udf_bswap.h"
66 
67 
68 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
69 
70 
71 /* externs */
72 extern int prtactive;
73 
74 /* implementations of vnode functions; table follows at end */
75 /* --------------------------------------------------------------------- */
76 
77 int
78 udf_inactive(void *v)
79 {
80 	struct vop_inactive_args /* {
81 		struct vnode *a_vp;
82 		bool         *a_recycle;
83 	} */ *ap = v;
84 	struct vnode *vp = ap->a_vp;
85 	struct udf_node *udf_node = VTOI(vp);
86 	int refcnt;
87 
88 	DPRINTF(NODE, ("udf_inactive called for udf_node %p\n", VTOI(vp)));
89 
90 	if (udf_node == NULL) {
91 		DPRINTF(NODE, ("udf_inactive: inactive NULL UDF node\n"));
92 		VOP_UNLOCK(vp);
93 		return 0;
94 	}
95 
96 	/*
97 	 * Optionally flush metadata to disc. If the file has not been
98 	 * referenced anymore in a directory we ought to free up the resources
99 	 * on disc if applicable.
100 	 */
101 	if (udf_node->fe) {
102 		refcnt = udf_rw16(udf_node->fe->link_cnt);
103 	} else {
104 		assert(udf_node->efe);
105 		refcnt = udf_rw16(udf_node->efe->link_cnt);
106 	}
107 
108 	if ((refcnt == 0) && (vp->v_vflag & VV_SYSTEM)) {
109 		DPRINTF(VOLUMES, ("UDF_INACTIVE deleting VV_SYSTEM\n"));
110 		/* system nodes are not writen out on inactive, so flush */
111 		udf_node->i_flags = 0;
112 	}
113 
114 	*ap->a_recycle = false;
115 	if ((refcnt == 0) && ((vp->v_vflag & VV_SYSTEM) == 0)) {
116 	 	/* remove this file's allocation */
117 		DPRINTF(NODE, ("udf_inactive deleting unlinked file\n"));
118 		*ap->a_recycle = true;
119 		udf_delete_node(udf_node);
120 		VOP_UNLOCK(vp);
121 		vrecycle(vp, NULL, curlwp);
122 		return 0;
123 	}
124 
125 	/* write out its node */
126 	if (udf_node->i_flags & (IN_CHANGE | IN_UPDATE | IN_MODIFIED))
127 		udf_update(vp, NULL, NULL, NULL, 0);
128 	VOP_UNLOCK(vp);
129 
130 	return 0;
131 }
132 
133 /* --------------------------------------------------------------------- */
134 
135 int udf_sync(struct mount *mp, int waitfor, kauth_cred_t cred, struct lwp *lwp);
136 
137 int
138 udf_reclaim(void *v)
139 {
140 	struct vop_reclaim_args /* {
141 		struct vnode *a_vp;
142 	} */ *ap = v;
143 	struct vnode *vp = ap->a_vp;
144 	struct udf_node *udf_node = VTOI(vp);
145 
146 	DPRINTF(NODE, ("udf_reclaim called for node %p\n", udf_node));
147 	if (prtactive && vp->v_usecount > 1)
148 		vprint("udf_reclaim(): pushing active", vp);
149 
150 	if (udf_node == NULL) {
151 		DPRINTF(NODE, ("udf_reclaim(): null udfnode\n"));
152 		return 0;
153 	}
154 
155 	/* update note for closure */
156 	udf_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
157 
158 	/* async check to see if all node descriptors are written out */
159 	while ((volatile int) udf_node->outstanding_nodedscr > 0) {
160 		vprint("udf_reclaim(): waiting for writeout\n", vp);
161 		tsleep(&udf_node->outstanding_nodedscr, PRIBIO, "recl wait", hz/8);
162 	}
163 
164 	/* dispose all node knowledge */
165 	udf_dispose_node(udf_node);
166 
167 	return 0;
168 }
169 
170 /* --------------------------------------------------------------------- */
171 
172 int
173 udf_read(void *v)
174 {
175 	struct vop_read_args /* {
176 		struct vnode *a_vp;
177 		struct uio *a_uio;
178 		int a_ioflag;
179 		kauth_cred_t a_cred;
180 	} */ *ap = v;
181 	struct vnode *vp     = ap->a_vp;
182 	struct uio   *uio    = ap->a_uio;
183 	int           ioflag = ap->a_ioflag;
184 	int           advice = IO_ADV_DECODE(ap->a_ioflag);
185 	struct uvm_object    *uobj;
186 	struct udf_node      *udf_node = VTOI(vp);
187 	struct file_entry    *fe;
188 	struct extfile_entry *efe;
189 	uint64_t file_size;
190 	vsize_t len;
191 	int error;
192 
193 	/*
194 	 * XXX reading from extended attributes not yet implemented. FreeBSD
195 	 * has it in mind to forward the IO_EXT read call to the
196 	 * VOP_READEXTATTR().
197 	 */
198 
199 	DPRINTF(READ, ("udf_read called\n"));
200 
201 	/* can this happen? some filingsystems have this check */
202 	if (uio->uio_offset < 0)
203 		return EINVAL;
204 	if (uio->uio_resid == 0)
205 		return 0;
206 
207 	/* protect against rogue programs reading raw directories and links */
208 	if ((ioflag & IO_ALTSEMANTICS) == 0) {
209 		if (vp->v_type == VDIR)
210 			return EISDIR;
211 		/* all but regular files just give EINVAL */
212 		if (vp->v_type != VREG)
213 			return EINVAL;
214 	}
215 
216 	assert(udf_node);
217 	assert(udf_node->fe || udf_node->efe);
218 
219 	/* get file/directory filesize */
220 	if (udf_node->fe) {
221 		fe = udf_node->fe;
222 		file_size = udf_rw64(fe->inf_len);
223 	} else {
224 		assert(udf_node->efe);
225 		efe = udf_node->efe;
226 		file_size = udf_rw64(efe->inf_len);
227 	}
228 
229 	/* read contents using buffercache */
230 	uobj = &vp->v_uobj;
231 	error = 0;
232 	while (uio->uio_resid > 0) {
233 		/* reached end? */
234 		if (file_size <= uio->uio_offset)
235 			break;
236 
237 		/* maximise length to file extremity */
238 		len = MIN(file_size - uio->uio_offset, uio->uio_resid);
239 		if (len == 0)
240 			break;
241 
242 		/* ubc, here we come, prepare to trap */
243 		error = ubc_uiomove(uobj, uio, len, advice,
244 		    UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
245 		if (error)
246 			break;
247 	}
248 
249 	/* note access time unless not requested */
250 	if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
251 		udf_node->i_flags |= IN_ACCESS;
252 		if ((ioflag & IO_SYNC) == IO_SYNC)
253 			error = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT);
254 	}
255 
256 	return error;
257 }
258 
259 /* --------------------------------------------------------------------- */
260 
261 int
262 udf_write(void *v)
263 {
264 	struct vop_write_args /* {
265 		struct vnode *a_vp;
266 		struct uio *a_uio;
267 		int a_ioflag;
268 		kauth_cred_t a_cred;
269 	} */ *ap = v;
270 	struct vnode *vp     = ap->a_vp;
271 	struct uio   *uio    = ap->a_uio;
272 	int           ioflag = ap->a_ioflag;
273 	kauth_cred_t  cred   = ap->a_cred;
274 	int           advice = IO_ADV_DECODE(ap->a_ioflag);
275 	struct uvm_object    *uobj;
276 	struct udf_node      *udf_node = VTOI(vp);
277 	struct file_entry    *fe;
278 	struct extfile_entry *efe;
279 	uint64_t file_size, old_size, old_offset;
280 	vsize_t len;
281 	int aflag = ioflag & IO_SYNC ? B_SYNC : 0;
282 	int error;
283 	int resid, extended;
284 
285 	/*
286 	 * XXX writing to extended attributes not yet implemented. FreeBSD has
287 	 * it in mind to forward the IO_EXT read call to the
288 	 * VOP_READEXTATTR().
289 	 */
290 
291 	DPRINTF(WRITE, ("udf_write called\n"));
292 
293 	/* can this happen? some filingsystems have this check */
294 	if (uio->uio_offset < 0)
295 		return EINVAL;
296 	if (uio->uio_resid == 0)
297 		return 0;
298 
299 	/* protect against rogue programs writing raw directories or links */
300 	if ((ioflag & IO_ALTSEMANTICS) == 0) {
301 		if (vp->v_type == VDIR)
302 			return EISDIR;
303 		/* all but regular files just give EINVAL for now */
304 		if (vp->v_type != VREG)
305 			return EINVAL;
306 	}
307 
308 	assert(udf_node);
309 	assert(udf_node->fe || udf_node->efe);
310 
311 	/* get file/directory filesize */
312 	if (udf_node->fe) {
313 		fe = udf_node->fe;
314 		file_size = udf_rw64(fe->inf_len);
315 	} else {
316 		assert(udf_node->efe);
317 		efe = udf_node->efe;
318 		file_size = udf_rw64(efe->inf_len);
319 	}
320 	old_size = file_size;
321 
322 	/* if explicitly asked to append, uio_offset can be wrong? */
323 	if (ioflag & IO_APPEND)
324 		uio->uio_offset = file_size;
325 
326 	extended = (uio->uio_offset + uio->uio_resid > file_size);
327 	if (extended) {
328 		DPRINTF(WRITE, ("extending file from %"PRIu64" to %"PRIu64"\n",
329 			file_size, uio->uio_offset + uio->uio_resid));
330 		error = udf_grow_node(udf_node, uio->uio_offset + uio->uio_resid);
331 		if (error)
332 			return error;
333 		file_size = uio->uio_offset + uio->uio_resid;
334 	}
335 
336 	/* write contents using buffercache */
337 	uobj = &vp->v_uobj;
338 	resid = uio->uio_resid;
339 	error = 0;
340 
341 	uvm_vnp_setwritesize(vp, file_size);
342 	old_offset = uio->uio_offset;
343 	while (uio->uio_resid > 0) {
344 		/* maximise length to file extremity */
345 		len = MIN(file_size - uio->uio_offset, uio->uio_resid);
346 		if (len == 0)
347 			break;
348 
349 		genfs_node_wrlock(vp);
350 		error = GOP_ALLOC(vp, uio->uio_offset, len, aflag, cred);
351 		genfs_node_unlock(vp);
352 		if (error)
353 			break;
354 
355 		/* ubc, here we come, prepare to trap */
356 		error = ubc_uiomove(uobj, uio, len, advice,
357 		    UBC_WRITE | UBC_UNMAP_FLAG(vp));
358 		if (error)
359 			break;
360 
361 		/*
362 		 * flush what we just wrote if necessary.
363 		 * XXXUBC simplistic async flushing.
364 		 *
365 		 * Directories are excluded since its file data that we want
366 		 * to purge.
367 		 */
368 		if ((vp->v_type != VDIR) &&
369 		  (old_offset >> 16 != uio->uio_offset >> 16)) {
370 			mutex_enter(vp->v_interlock);
371 			error = VOP_PUTPAGES(vp, (old_offset >> 16) << 16,
372 			    (uio->uio_offset >> 16) << 16,
373 			    PGO_CLEANIT | PGO_LAZY);
374 			old_offset = uio->uio_offset;
375 		}
376 	}
377 	uvm_vnp_setsize(vp, file_size);
378 
379 	/* mark node changed and request update */
380 	udf_node->i_flags |= IN_CHANGE | IN_UPDATE;
381 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
382 		udf_node->i_flags |= IN_ACCESS;
383 
384 	/*
385 	 * XXX TODO FFS has code here to reset setuid & setgid when we're not
386 	 * the superuser as a precaution against tampering.
387 	 */
388 
389 	/* if we wrote a thing, note write action on vnode */
390 	if (resid > uio->uio_resid)
391 		VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
392 
393 	if (error) {
394 		/* bring back file size to its former size */
395 		/* take notice of its errors? */
396 		(void) udf_chsize(vp, (u_quad_t) old_size, cred);
397 
398 		/* roll back uio */
399 		uio->uio_offset -= resid - uio->uio_resid;
400 		uio->uio_resid = resid;
401 	} else {
402 		/* if we write and we're synchronous, update node */
403 		if ((resid > uio->uio_resid) && ((ioflag & IO_SYNC) == IO_SYNC))
404 			error = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT);
405 	}
406 
407 	return error;
408 }
409 
410 
411 /* --------------------------------------------------------------------- */
412 
413 /*
414  * `Special' bmap functionality that translates all incomming requests to
415  * translate to vop_strategy() calls with the same blocknumbers effectively
416  * not translating at all.
417  */
418 
419 int
420 udf_trivial_bmap(void *v)
421 {
422 	struct vop_bmap_args /* {
423 		struct vnode *a_vp;
424 		daddr_t a_bn;
425 		struct vnode **a_vpp;
426 		daddr_t *a_bnp;
427 		int *a_runp;
428 	} */ *ap = v;
429 	struct vnode  *vp  = ap->a_vp;	/* our node	*/
430 	struct vnode **vpp = ap->a_vpp;	/* return node	*/
431 	daddr_t *bnp  = ap->a_bnp;	/* translated	*/
432 	daddr_t  bn   = ap->a_bn;	/* origional	*/
433 	int     *runp = ap->a_runp;
434 	struct udf_node *udf_node = VTOI(vp);
435 	uint32_t lb_size;
436 
437 	/* get logical block size */
438 	lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
439 
440 	/* could return `-1' to indicate holes/zeros */
441 	/* translate 1:1 */
442 	*bnp = bn;
443 
444 	/* set the vnode to read the data from with strategy on itself */
445 	if (vpp)
446 		*vpp = vp;
447 
448 	/* set runlength of maximum block size */
449 	if (runp)
450 		*runp = MAXPHYS / lb_size;	/* or with -1 ? */
451 
452 	/* return success */
453 	return 0;
454 }
455 
456 /* --------------------------------------------------------------------- */
457 
458 int
459 udf_vfsstrategy(void *v)
460 {
461 	struct vop_strategy_args /* {
462 		struct vnode *a_vp;
463 		struct buf *a_bp;
464 	} */ *ap = v;
465 	struct vnode *vp = ap->a_vp;
466 	struct buf   *bp = ap->a_bp;
467 	struct udf_node *udf_node = VTOI(vp);
468 	uint32_t lb_size, from, sectors;
469 	int error;
470 
471 	DPRINTF(STRATEGY, ("udf_strategy called\n"));
472 
473 	/* check if we ought to be here */
474 	if (vp->v_type == VBLK || vp->v_type == VCHR)
475 		panic("udf_strategy: spec");
476 
477 	/* only filebuffers ought to be read/write by this, no descriptors */
478 	assert(bp->b_blkno >= 0);
479 
480 	/* get sector size */
481 	lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
482 
483 	/* calculate sector to start from */
484 	from = bp->b_blkno;
485 
486 	/* calculate length to fetch/store in sectors */
487 	sectors = bp->b_bcount / lb_size;
488 	assert(bp->b_bcount > 0);
489 
490 	/* NEVER assume later that this buffer is already translated */
491 	/* bp->b_lblkno = bp->b_blkno; */
492 
493 	/* check assertions: we OUGHT to always get multiples of this */
494 	assert(sectors * lb_size == bp->b_bcount);
495 
496 	/* issue buffer */
497 	error = 0;
498 	if (bp->b_flags & B_READ) {
499 		DPRINTF(STRATEGY, ("\tread vp %p buf %p (blk no %"PRIu64")"
500 		    ", sector %d for %d sectors\n",
501 		    vp, bp, bp->b_blkno, from, sectors));
502 
503 		/* read buffer from the udf_node, translate vtop on the way*/
504 		udf_read_filebuf(udf_node, bp);
505 	} else {
506 		DPRINTF(STRATEGY, ("\twrite vp %p buf %p (blk no %"PRIu64")"
507 		    ", sector %d for %d sectors\n",
508 		    vp, bp, bp->b_blkno, from, sectors));
509 
510 		/* write buffer to the udf_node, translate vtop on the way*/
511 		udf_write_filebuf(udf_node, bp);
512 	}
513 
514 	return bp->b_error;
515 }
516 
517 /* --------------------------------------------------------------------- */
518 
519 int
520 udf_readdir(void *v)
521 {
522 	struct vop_readdir_args /* {
523 		struct vnode *a_vp;
524 		struct uio *a_uio;
525 		kauth_cred_t a_cred;
526 		int *a_eofflag;
527 		off_t **a_cookies;
528 		int *a_ncookies;
529 	} */ *ap = v;
530 	struct uio *uio = ap->a_uio;
531 	struct vnode *vp = ap->a_vp;
532 	struct udf_node *udf_node = VTOI(vp);
533 	struct file_entry    *fe;
534 	struct extfile_entry *efe;
535 	struct fileid_desc *fid;
536 	struct dirent *dirent;
537 	uint64_t file_size, diroffset, transoffset;
538 	uint32_t lb_size;
539 	int error;
540 
541 	DPRINTF(READDIR, ("udf_readdir called\n"));
542 
543 	/* This operation only makes sense on directory nodes. */
544 	if (vp->v_type != VDIR)
545 		return ENOTDIR;
546 
547 	/* get directory filesize */
548 	if (udf_node->fe) {
549 		fe = udf_node->fe;
550 		file_size = udf_rw64(fe->inf_len);
551 	} else {
552 		assert(udf_node->efe);
553 		efe = udf_node->efe;
554 		file_size = udf_rw64(efe->inf_len);
555 	}
556 
557 	dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK | M_ZERO);
558 
559 	/*
560 	 * Add `.' pseudo entry if at offset zero since its not in the fid
561 	 * stream
562 	 */
563 	if (uio->uio_offset == 0) {
564 		DPRINTF(READDIR, ("\t'.' inserted\n"));
565 		strcpy(dirent->d_name, ".");
566 		dirent->d_fileno = udf_get_node_id(&udf_node->loc);
567 		dirent->d_type = DT_DIR;
568 		dirent->d_namlen = strlen(dirent->d_name);
569 		dirent->d_reclen = _DIRENT_SIZE(dirent);
570 		uiomove(dirent, _DIRENT_SIZE(dirent), uio);
571 
572 		/* mark with magic value that we have done the dummy */
573 		uio->uio_offset = UDF_DIRCOOKIE_DOT;
574 	}
575 
576 	/* we are called just as long as we keep on pushing data in */
577 	error = 0;
578 	if (uio->uio_offset < file_size) {
579 		/* allocate temporary space for fid */
580 		lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
581 		fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
582 
583 		if (uio->uio_offset == UDF_DIRCOOKIE_DOT)
584 			uio->uio_offset = 0;
585 
586 		diroffset   = uio->uio_offset;
587 		transoffset = diroffset;
588 		while (diroffset < file_size) {
589 			DPRINTF(READDIR, ("\tread in fid stream\n"));
590 			/* transfer a new fid/dirent */
591 			error = udf_read_fid_stream(vp, &diroffset, fid, dirent);
592 			DPRINTFIF(READDIR, error, ("read error in read fid "
593 			    "stream : %d\n", error));
594 			if (error)
595 				break;
596 
597 			/*
598 			 * If there isn't enough space in the uio to return a
599 			 * whole dirent, break off read
600 			 */
601 			if (uio->uio_resid < _DIRENT_SIZE(dirent))
602 				break;
603 
604 			/* remember the last entry we transfered */
605 			transoffset = diroffset;
606 
607 			/* skip deleted entries */
608 			if (fid->file_char & UDF_FILE_CHAR_DEL)
609 				continue;
610 
611 			/* skip not visible files */
612 			if (fid->file_char & UDF_FILE_CHAR_VIS)
613 				continue;
614 
615 			/* copy dirent to the caller */
616 			DPRINTF(READDIR, ("\tread dirent `%s', type %d\n",
617 			    dirent->d_name, dirent->d_type));
618 			uiomove(dirent, _DIRENT_SIZE(dirent), uio);
619 		}
620 
621 		/* pass on last transfered offset */
622 		uio->uio_offset = transoffset;
623 		free(fid, M_UDFTEMP);
624 	}
625 
626 	if (ap->a_eofflag)
627 		*ap->a_eofflag = (uio->uio_offset >= file_size);
628 
629 #ifdef DEBUG
630 	if (udf_verbose & UDF_DEBUG_READDIR) {
631 		printf("returning offset %d\n", (uint32_t) uio->uio_offset);
632 		if (ap->a_eofflag)
633 			printf("returning EOF ? %d\n", *ap->a_eofflag);
634 		if (error)
635 			printf("readdir returning error %d\n", error);
636 	}
637 #endif
638 
639 	free(dirent, M_UDFTEMP);
640 	return error;
641 }
642 
643 /* --------------------------------------------------------------------- */
644 
645 int
646 udf_lookup(void *v)
647 {
648 	struct vop_lookup_args /* {
649 		struct vnode *a_dvp;
650 		struct vnode **a_vpp;
651 		struct componentname *a_cnp;
652 	} */ *ap = v;
653 	struct vnode *dvp = ap->a_dvp;
654 	struct vnode **vpp = ap->a_vpp;
655 	struct componentname *cnp = ap->a_cnp;
656 	struct udf_node  *dir_node, *res_node;
657 	struct udf_mount *ump;
658 	struct long_ad    icb_loc;
659 	mode_t mode;
660 	uid_t d_uid;
661 	gid_t d_gid;
662 	const char *name;
663 	int namelen, nameiop, islastcn, mounted_ro;
664 	int error, found;
665 
666 	dir_node = VTOI(dvp);
667 	ump = dir_node->ump;
668 	*vpp = NULL;
669 
670 	DPRINTF(LOOKUP, ("udf_lookup called, lookup `%s`\n",
671 		cnp->cn_nameptr));
672 
673 	/* simplify/clarification flags */
674 	nameiop     = cnp->cn_nameiop;
675 	islastcn    = cnp->cn_flags & ISLASTCN;
676 	mounted_ro  = dvp->v_mount->mnt_flag & MNT_RDONLY;
677 
678 	/* check exec/dirread permissions first */
679 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
680 	if (error)
681 		return error;
682 
683 	DPRINTF(LOOKUP, ("\taccess ok\n"));
684 
685 	/*
686 	 * If requesting a modify on the last path element on a read-only
687 	 * filingsystem, reject lookup; XXX why is this repeated in every FS ?
688 	 */
689 	if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME))
690 		return EROFS;
691 
692 	DPRINTF(LOOKUP, ("\tlooking up cnp->cn_nameptr '%s'\n",
693 	    cnp->cn_nameptr));
694 	/* look in the namecache */
695 	if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
696 			 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
697 		return *vpp == NULLVP ? ENOENT : 0;
698 	}
699 
700 	DPRINTF(LOOKUP, ("\tNOT found in cache\n"));
701 
702 	/*
703 	 * Obviously, the file is not (anymore) in the namecache, we have to
704 	 * search for it. There are three basic cases: '.', '..' and others.
705 	 *
706 	 * Following the guidelines of VOP_LOOKUP manpage and tmpfs.
707 	 */
708 	error = 0;
709 	if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) {
710 		DPRINTF(LOOKUP, ("\tlookup '.'\n"));
711 		/* special case 1 '.' */
712 		if (islastcn && cnp->cn_nameiop == RENAME) {
713 			error = EISDIR;
714 			goto out;
715 		}
716 		vref(dvp);
717 		*vpp = dvp;
718 		/* done */
719 		goto done;
720 	} else if (cnp->cn_flags & ISDOTDOT) {
721 		/* special case 2 '..' */
722 		DPRINTF(LOOKUP, ("\tlookup '..'\n"));
723 
724 		if (islastcn && cnp->cn_nameiop == RENAME) {
725 			error = EINVAL;
726 			goto out;
727 		}
728 
729 		/* get our node */
730 		name    = "..";
731 		namelen = 2;
732 		error = udf_lookup_name_in_dir(dvp, name, namelen,
733 				&icb_loc, &found);
734 		if (error)
735 			goto out;
736 		if (!found)
737 			error = ENOENT;
738 
739 		/* first unlock parent */
740 		VOP_UNLOCK(dvp);
741 
742 		if (error == 0) {
743 			DPRINTF(LOOKUP, ("\tfound '..'\n"));
744 			/* try to create/reuse the node */
745 			error = udf_get_node(ump, &icb_loc, &res_node);
746 
747 			if (!error) {
748 				DPRINTF(LOOKUP,
749 					("\tnode retrieved/created OK\n"));
750 				*vpp = res_node->vnode;
751 			}
752 		}
753 
754 		/* try to relock parent */
755 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
756 		goto out;
757 	}
758 
759 	/* all other files */
760 	DPRINTF(LOOKUP, ("\tlookup file/dir in directory\n"));
761 
762 	/* lookup filename in the directory; location icb_loc */
763 	name    = cnp->cn_nameptr;
764 	namelen = cnp->cn_namelen;
765 	error = udf_lookup_name_in_dir(dvp, name, namelen,
766 			&icb_loc, &found);
767 	if (error)
768 		goto out;
769 	if (!found) {
770 		DPRINTF(LOOKUP, ("\tNOT found\n"));
771 		/*
772 		 * The entry was not found in the directory.  This is
773 		 * valid if we are creating or renaming an entry and
774 		 * are working on the last component of the path name.
775 		 */
776 		if (islastcn && (cnp->cn_nameiop == CREATE ||
777 				 cnp->cn_nameiop == RENAME)) {
778 			error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
779 			if (error) {
780 				goto out;
781 			}
782 			error = EJUSTRETURN;
783 		} else {
784 			error = ENOENT;
785 		}
786 		/* done */
787 		goto done;
788 	}
789 
790 	/*
791 	 * XXX NOTE tmpfs has a test here that tests that intermediate
792 	 * components i.e. not the last one ought to be either a directory or
793 	 * a link. It seems to function well without this code.
794 	 */
795 
796 	/* try to create/reuse the node */
797 	error = udf_get_node(ump, &icb_loc, &res_node);
798 	if (error)
799 		goto out;
800 
801 	/* check permissions */
802 	if (islastcn && (cnp->cn_nameiop == DELETE ||
803 			 cnp->cn_nameiop == RENAME)  ) {
804 		error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
805 		if (error) {
806 			vput(res_node->vnode);
807 			goto out;
808 		}
809 
810 		/*
811 		 * Check if the directory has its sticky bit set. If so, ask
812 		 * for clearance since only the owner of a file or directory
813 		 * can remove/rename from taht directory.
814 		 */
815 		mode = udf_getaccessmode(dir_node);
816 		if ((mode & S_ISTXT) != 0) {
817 			udf_getownership(dir_node, &d_uid, &d_gid);
818 			error = kauth_authorize_vnode(cnp->cn_cred,
819 			    KAUTH_VNODE_DELETE, res_node->vnode,
820 			    dir_node->vnode, genfs_can_sticky(cnp->cn_cred,
821 			    d_uid, d_uid));
822 			if (error) {
823 				error = EPERM;
824 				vput(res_node->vnode);
825 				goto out;
826 			}
827 		}
828 	}
829 
830 	*vpp = res_node->vnode;
831 
832 done:
833 	/*
834 	 * Store result in the cache if requested. If we are creating a file,
835 	 * the file might not be found and thus putting it into the namecache
836 	 * might be seen as negative caching.
837 	 */
838 	if (nameiop != CREATE)
839 		cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
840 			    cnp->cn_flags);
841 
842 out:
843 	DPRINTFIF(LOOKUP, error, ("udf_lookup returing error %d\n", error));
844 
845 	return error;
846 }
847 
848 /* --------------------------------------------------------------------- */
849 
850 int
851 udf_getattr(void *v)
852 {
853 	struct vop_getattr_args /* {
854 		struct vnode *a_vp;
855 		struct vattr *a_vap;
856 		kauth_cred_t a_cred;
857 		struct lwp   *a_l;
858 	} */ *ap = v;
859 	struct vnode *vp = ap->a_vp;
860 	struct udf_node *udf_node = VTOI(vp);
861 	struct udf_mount *ump = udf_node->ump;
862 	struct file_entry    *fe  = udf_node->fe;
863 	struct extfile_entry *efe = udf_node->efe;
864 	struct filetimes_extattr_entry *ft_extattr;
865 	struct device_extattr_entry *devattr;
866 	struct vattr *vap = ap->a_vap;
867 	struct timestamp *atime, *mtime, *attrtime, *creatime;
868 	uint64_t filesize, blkssize;
869 	uint32_t nlink;
870 	uint32_t offset, a_l;
871 	uint8_t *filedata;
872 	uid_t uid;
873 	gid_t gid;
874 	int error;
875 
876 	DPRINTF(CALL, ("udf_getattr called\n"));
877 
878 	/* update times before we returning values */
879 	udf_itimes(udf_node, NULL, NULL, NULL);
880 
881 	/* get descriptor information */
882 	if (fe) {
883 		nlink    = udf_rw16(fe->link_cnt);
884 		uid      = (uid_t)udf_rw32(fe->uid);
885 		gid      = (gid_t)udf_rw32(fe->gid);
886 		filesize = udf_rw64(fe->inf_len);
887 		blkssize = udf_rw64(fe->logblks_rec);
888 		atime    = &fe->atime;
889 		mtime    = &fe->mtime;
890 		attrtime = &fe->attrtime;
891 		filedata = fe->data;
892 
893 		/* initial guess */
894 		creatime = mtime;
895 
896 		/* check our extended attribute if present */
897 		error = udf_extattr_search_intern(udf_node,
898 			UDF_FILETIMES_ATTR_NO, "", &offset, &a_l);
899 		if (!error) {
900 			ft_extattr = (struct filetimes_extattr_entry *)
901 				(filedata + offset);
902 			if (ft_extattr->existence & UDF_FILETIMES_FILE_CREATION)
903 				creatime = &ft_extattr->times[0];
904 		}
905 	} else {
906 		assert(udf_node->efe);
907 		nlink    = udf_rw16(efe->link_cnt);
908 		uid      = (uid_t)udf_rw32(efe->uid);
909 		gid      = (gid_t)udf_rw32(efe->gid);
910 		filesize = udf_rw64(efe->inf_len);	/* XXX or obj_size? */
911 		blkssize = udf_rw64(efe->logblks_rec);
912 		atime    = &efe->atime;
913 		mtime    = &efe->mtime;
914 		attrtime = &efe->attrtime;
915 		creatime = &efe->ctime;
916 		filedata = efe->data;
917 	}
918 
919 	/* do the uid/gid translation game */
920 	if (uid == (uid_t) -1)
921 		uid = ump->mount_args.anon_uid;
922 	if (gid == (gid_t) -1)
923 		gid = ump->mount_args.anon_gid;
924 
925 	/* fill in struct vattr with values from the node */
926 	vattr_null(vap);
927 	vap->va_type      = vp->v_type;
928 	vap->va_mode      = udf_getaccessmode(udf_node);
929 	vap->va_nlink     = nlink;
930 	vap->va_uid       = uid;
931 	vap->va_gid       = gid;
932 	vap->va_fsid      = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
933 	vap->va_fileid    = udf_get_node_id(&udf_node->loc);   /* inode hash XXX */
934 	vap->va_size      = filesize;
935 	vap->va_blocksize = udf_node->ump->discinfo.sector_size;  /* wise? */
936 
937 	/*
938 	 * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
939 	 * 1 to the link count if its a directory we're requested attributes
940 	 * of.
941 	 */
942 	if (vap->va_type == VDIR)
943 		vap->va_nlink++;
944 
945 	/* access times */
946 	udf_timestamp_to_timespec(ump, atime,    &vap->va_atime);
947 	udf_timestamp_to_timespec(ump, mtime,    &vap->va_mtime);
948 	udf_timestamp_to_timespec(ump, attrtime, &vap->va_ctime);
949 	udf_timestamp_to_timespec(ump, creatime, &vap->va_birthtime);
950 
951 	vap->va_gen       = 1;		/* no multiple generations yes (!?) */
952 	vap->va_flags     = 0;		/* no flags */
953 	vap->va_bytes     = blkssize * udf_node->ump->discinfo.sector_size;
954 	vap->va_filerev   = 1;		/* TODO file revision numbers? */
955 	vap->va_vaflags   = 0;
956 	/* TODO get vaflags from the extended attributes? */
957 
958 	if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) {
959 		error = udf_extattr_search_intern(udf_node,
960 				UDF_DEVICESPEC_ATTR_NO, "",
961 				&offset, &a_l);
962 		/* if error, deny access */
963 		if (error || (filedata == NULL)) {
964 			vap->va_mode = 0;	/* or v_type = VNON?  */
965 		} else {
966 			devattr = (struct device_extattr_entry *)
967 				filedata + offset;
968 			vap->va_rdev = makedev(
969 				udf_rw32(devattr->major),
970 				udf_rw32(devattr->minor)
971 				);
972 			/* TODO we could check the implementator */
973 		}
974 	}
975 
976 	return 0;
977 }
978 
979 /* --------------------------------------------------------------------- */
980 
981 static int
982 udf_chown(struct vnode *vp, uid_t new_uid, gid_t new_gid,
983 	  kauth_cred_t cred)
984 {
985 	struct udf_node  *udf_node = VTOI(vp);
986 	uid_t uid;
987 	gid_t gid;
988 	int error;
989 
990 #ifdef notyet
991 	/* TODO get vaflags from the extended attributes? */
992 	/* Immutable or append-only files cannot be modified, either. */
993 	if (udf_node->flags & (IMMUTABLE | APPEND))
994 		return EPERM;
995 #endif
996 
997 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
998 		return EROFS;
999 
1000 	/* retrieve old values */
1001 	udf_getownership(udf_node, &uid, &gid);
1002 
1003 	/* only one could be specified */
1004 	if (new_uid == VNOVAL)
1005 		new_uid = uid;
1006 	if (new_gid == VNOVAL)
1007 		new_gid = gid;
1008 
1009 	/* check if we can fit it in an 32 bits */
1010 	if ((uid_t) ((uint32_t) new_uid) != new_uid)
1011 		return EINVAL;
1012 	if ((gid_t) ((uint32_t) new_gid) != new_gid)
1013 		return EINVAL;
1014 
1015 	/* check permissions */
1016 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP,
1017 	    vp, NULL, genfs_can_chown(cred, uid, gid, new_uid, new_gid));
1018 	if (error)
1019 		return (error);
1020 
1021 	/* change the ownership */
1022 	udf_setownership(udf_node, new_uid, new_gid);
1023 
1024 	/* mark node changed */
1025 	udf_node->i_flags |= IN_CHANGE;
1026 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
1027 		udf_node->i_flags |= IN_ACCESS;
1028 
1029 	return 0;
1030 }
1031 
1032 
1033 static int
1034 udf_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred)
1035 {
1036 	struct udf_node  *udf_node = VTOI(vp);
1037 	uid_t uid;
1038 	gid_t gid;
1039 	int error;
1040 
1041 #ifdef notyet
1042 	/* TODO get vaflags from the extended attributes? */
1043 	/* Immutable or append-only files cannot be modified, either. */
1044 	if (udf_node->flags & (IMMUTABLE | APPEND))
1045 		return EPERM;
1046 #endif
1047 
1048 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1049 		return EROFS;
1050 
1051 	/* retrieve uid/gid values */
1052 	udf_getownership(udf_node, &uid, &gid);
1053 
1054 	/* check permissions */
1055 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
1056 	    NULL, genfs_can_chmod(vp->v_type, cred, uid, gid, mode));
1057 	if (error)
1058 		return (error);
1059 
1060 	/* change mode */
1061 	udf_setaccessmode(udf_node, mode);
1062 
1063 	/* mark node changed */
1064 	udf_node->i_flags |= IN_CHANGE;
1065 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
1066 		udf_node->i_flags |= IN_ACCESS;
1067 
1068 	return 0;
1069 }
1070 
1071 
1072 /* exported */
1073 int
1074 udf_chsize(struct vnode *vp, u_quad_t newsize, kauth_cred_t cred)
1075 {
1076 	struct udf_node  *udf_node = VTOI(vp);
1077 	int error, extended;
1078 
1079 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1080 		return EROFS;
1081 
1082 	/* Decide whether this is a valid operation based on the file type. */
1083 	switch (vp->v_type) {
1084 	case VDIR:
1085 		return EISDIR;
1086 	case VREG:
1087 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
1088 			return EROFS;
1089 		break;
1090 	case VBLK:
1091 		/* FALLTHROUGH */
1092 	case VCHR:
1093 		/* FALLTHROUGH */
1094 	case VFIFO:
1095 		/* Allow modifications of special files even if in the file
1096 		 * system is mounted read-only (we are not modifying the
1097 		 * files themselves, but the objects they represent). */
1098 		return 0;
1099 	default:
1100 		/* Anything else is unsupported. */
1101 		return EOPNOTSUPP;
1102 	}
1103 
1104 #if notyet
1105 	/* TODO get vaflags from the extended attributes? */
1106 	/* Immutable or append-only files cannot be modified, either. */
1107 	if (node->flags & (IMMUTABLE | APPEND))
1108 		return EPERM;
1109 #endif
1110 
1111 	/* resize file to the requested size */
1112 	error = udf_resize_node(udf_node, newsize, &extended);
1113 
1114 	if (error == 0) {
1115 		/* mark change */
1116 		udf_node->i_flags |= IN_CHANGE | IN_MODIFY;
1117 		if (vp->v_mount->mnt_flag & MNT_RELATIME)
1118 			udf_node->i_flags |= IN_ACCESS;
1119 		VN_KNOTE(vp, NOTE_ATTRIB | (extended ? NOTE_EXTEND : 0));
1120 		udf_update(vp, NULL, NULL, NULL, 0);
1121 	}
1122 
1123 	return error;
1124 }
1125 
1126 
1127 static int
1128 udf_chflags(struct vnode *vp, mode_t mode, kauth_cred_t cred)
1129 {
1130 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1131 		return EROFS;
1132 
1133 	/*
1134 	 * XXX we can't do this yet, as its not described in the standard yet
1135 	 */
1136 
1137 	return EOPNOTSUPP;
1138 }
1139 
1140 
1141 static int
1142 udf_chtimes(struct vnode *vp,
1143 	struct timespec *atime, struct timespec *mtime,
1144 	struct timespec *birthtime, int setattrflags,
1145 	kauth_cred_t cred)
1146 {
1147 	struct udf_node  *udf_node = VTOI(vp);
1148 	uid_t uid;
1149 	gid_t gid;
1150 	int error;
1151 
1152 #ifdef notyet
1153 	/* TODO get vaflags from the extended attributes? */
1154 	/* Immutable or append-only files cannot be modified, either. */
1155 	if (udf_node->flags & (IMMUTABLE | APPEND))
1156 		return EPERM;
1157 #endif
1158 
1159 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1160 		return EROFS;
1161 
1162 	/* retrieve uid/gid values */
1163 	udf_getownership(udf_node, &uid, &gid);
1164 
1165 	/* check permissions */
1166 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
1167 	    NULL, genfs_can_chtimes(vp, setattrflags, uid, cred));
1168 	if (error)
1169 		return (error);
1170 
1171 	/* update node flags depending on what times are passed */
1172 	if (atime->tv_sec != VNOVAL)
1173 		if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
1174 			udf_node->i_flags |= IN_ACCESS;
1175 	if ((mtime->tv_sec != VNOVAL) || (birthtime->tv_sec != VNOVAL)) {
1176 		udf_node->i_flags |= IN_CHANGE | IN_UPDATE;
1177 		if (vp->v_mount->mnt_flag & MNT_RELATIME)
1178 			udf_node->i_flags |= IN_ACCESS;
1179 	}
1180 
1181 	return udf_update(vp, atime, mtime, birthtime, 0);
1182 }
1183 
1184 
1185 int
1186 udf_setattr(void *v)
1187 {
1188 	struct vop_setattr_args /* {
1189 		struct vnode *a_vp;
1190 		struct vattr *a_vap;
1191 		kauth_cred_t a_cred;
1192 		struct lwp   *a_l;
1193 	} */ *ap = v;
1194 	struct vnode *vp = ap->a_vp;
1195 /*	struct udf_node  *udf_node = VTOI(vp); */
1196 /*	struct udf_mount *ump = udf_node->ump; */
1197 	kauth_cred_t cred = ap->a_cred;
1198 	struct vattr *vap = ap->a_vap;
1199 	int error;
1200 
1201 	DPRINTF(CALL, ("udf_setattr called\n"));
1202 
1203 	/* Abort if any unsettable attribute is given. */
1204 	error = 0;
1205 	if (vap->va_type != VNON ||
1206 	    vap->va_nlink != VNOVAL ||
1207 	    vap->va_fsid != VNOVAL ||
1208 	    vap->va_fileid != VNOVAL ||
1209 	    vap->va_blocksize != VNOVAL ||
1210 #ifdef notyet
1211 	    /* checks are debated */
1212 	    vap->va_ctime.tv_sec != VNOVAL ||
1213 	    vap->va_ctime.tv_nsec != VNOVAL ||
1214 	    vap->va_birthtime.tv_sec != VNOVAL ||
1215 	    vap->va_birthtime.tv_nsec != VNOVAL ||
1216 #endif
1217 	    vap->va_gen != VNOVAL ||
1218 	    vap->va_rdev != VNOVAL ||
1219 	    vap->va_bytes != VNOVAL)
1220 		error = EINVAL;
1221 
1222 	DPRINTF(ATTR, ("setattr changing:\n"));
1223 	if (error == 0 && (vap->va_flags != VNOVAL)) {
1224 		DPRINTF(ATTR, ("\tchflags\n"));
1225 	 	error = udf_chflags(vp, vap->va_flags, cred);
1226 	}
1227 
1228 	if (error == 0 && (vap->va_size != VNOVAL)) {
1229 		DPRINTF(ATTR, ("\tchsize\n"));
1230 		error = udf_chsize(vp, vap->va_size, cred);
1231 	}
1232 
1233 	if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) {
1234 		DPRINTF(ATTR, ("\tchown\n"));
1235 		error = udf_chown(vp, vap->va_uid, vap->va_gid, cred);
1236 	}
1237 
1238 	if (error == 0 && (vap->va_mode != VNOVAL)) {
1239 		DPRINTF(ATTR, ("\tchmod\n"));
1240 		error = udf_chmod(vp, vap->va_mode, cred);
1241 	}
1242 
1243 	if (error == 0 &&
1244 	    ((vap->va_atime.tv_sec != VNOVAL &&
1245 	      vap->va_atime.tv_nsec != VNOVAL)   ||
1246 	     (vap->va_mtime.tv_sec != VNOVAL &&
1247 	      vap->va_mtime.tv_nsec != VNOVAL))
1248 	    ) {
1249 		DPRINTF(ATTR, ("\tchtimes\n"));
1250 		error = udf_chtimes(vp, &vap->va_atime, &vap->va_mtime,
1251 		    &vap->va_birthtime, vap->va_vaflags, cred);
1252 	}
1253 	VN_KNOTE(vp, NOTE_ATTRIB);
1254 
1255 	return error;
1256 }
1257 
1258 /* --------------------------------------------------------------------- */
1259 
1260 /*
1261  * Return POSIX pathconf information for UDF file systems.
1262  */
1263 int
1264 udf_pathconf(void *v)
1265 {
1266 	struct vop_pathconf_args /* {
1267 		struct vnode *a_vp;
1268 		int a_name;
1269 		register_t *a_retval;
1270 	} */ *ap = v;
1271 	uint32_t bits;
1272 
1273 	DPRINTF(CALL, ("udf_pathconf called\n"));
1274 
1275 	switch (ap->a_name) {
1276 	case _PC_LINK_MAX:
1277 		*ap->a_retval = (1<<16)-1;	/* 16 bits */
1278 		return 0;
1279 	case _PC_NAME_MAX:
1280 		*ap->a_retval = UDF_MAXNAMLEN;
1281 		return 0;
1282 	case _PC_PATH_MAX:
1283 		*ap->a_retval = PATH_MAX;
1284 		return 0;
1285 	case _PC_PIPE_BUF:
1286 		*ap->a_retval = PIPE_BUF;
1287 		return 0;
1288 	case _PC_CHOWN_RESTRICTED:
1289 		*ap->a_retval = 1;
1290 		return 0;
1291 	case _PC_NO_TRUNC:
1292 		*ap->a_retval = 1;
1293 		return 0;
1294 	case _PC_SYNC_IO:
1295 		*ap->a_retval = 0;     /* synchronised is off for performance */
1296 		return 0;
1297 	case _PC_FILESIZEBITS:
1298 		/* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */
1299 		bits = 64; /* XXX ought to deliver 65 */
1300 #if 0
1301 		if (udf_node)
1302 			bits = 64 * vp->v_mount->mnt_dev_bshift;
1303 #endif
1304 		*ap->a_retval = bits;
1305 		return 0;
1306 	}
1307 
1308 	return EINVAL;
1309 }
1310 
1311 
1312 /* --------------------------------------------------------------------- */
1313 
1314 int
1315 udf_open(void *v)
1316 {
1317 	struct vop_open_args /* {
1318 		struct vnode *a_vp;
1319 		int a_mode;
1320 		kauth_cred_t a_cred;
1321 		struct proc *a_p;
1322 	} */ *ap = v;
1323 	int flags;
1324 
1325 	DPRINTF(CALL, ("udf_open called\n"));
1326 
1327 	/*
1328 	 * Files marked append-only must be opened for appending.
1329 	 * TODO: get chflags(2) flags from extened attribute.
1330 	 */
1331 	flags = 0;
1332 	if ((flags & APPEND) && (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
1333 		return (EPERM);
1334 
1335 	return 0;
1336 }
1337 
1338 
1339 /* --------------------------------------------------------------------- */
1340 
1341 int
1342 udf_close(void *v)
1343 {
1344 	struct vop_close_args /* {
1345 		struct vnode *a_vp;
1346 		int a_fflag;
1347 		kauth_cred_t a_cred;
1348 		struct proc *a_p;
1349 	} */ *ap = v;
1350 	struct vnode *vp = ap->a_vp;
1351 	struct udf_node *udf_node = VTOI(vp);
1352 	int async = vp->v_mount->mnt_flag & MNT_ASYNC;
1353 	int error;
1354 
1355 	DPRINTF(CALL, ("udf_close called\n"));
1356 	udf_node = udf_node;	/* shut up gcc */
1357 
1358 	if (!async && (vp->v_type != VDIR)) {
1359 		mutex_enter(vp->v_interlock);
1360 		error = VOP_PUTPAGES(vp, 0, 0, PGO_CLEANIT);
1361 		if (error)
1362 			return error;
1363 	}
1364 
1365 	mutex_enter(vp->v_interlock);
1366 		if (vp->v_usecount > 1)
1367 			udf_itimes(udf_node, NULL, NULL, NULL);
1368 	mutex_exit(vp->v_interlock);
1369 
1370 	return 0;
1371 }
1372 
1373 
1374 /* --------------------------------------------------------------------- */
1375 
1376 static int
1377 udf_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode)
1378 {
1379 	int flags;
1380 
1381 	/* check if we are allowed to write */
1382 	switch (vap->va_type) {
1383 	case VDIR:
1384 	case VLNK:
1385 	case VREG:
1386 		/*
1387 		 * normal nodes: check if we're on a read-only mounted
1388 		 * filingsystem and bomb out if we're trying to write.
1389 		 */
1390 		if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
1391 			return EROFS;
1392 		break;
1393 	case VBLK:
1394 	case VCHR:
1395 	case VSOCK:
1396 	case VFIFO:
1397 		/*
1398 		 * special nodes: even on read-only mounted filingsystems
1399 		 * these are allowed to be written to if permissions allow.
1400 		 */
1401 		break;
1402 	default:
1403 		/* no idea what this is */
1404 		return EINVAL;
1405 	}
1406 
1407 	/* noone may write immutable files */
1408 	/* TODO: get chflags(2) flags from extened attribute. */
1409 	flags = 0;
1410 	if ((mode & VWRITE) && (flags & IMMUTABLE))
1411 		return EPERM;
1412 
1413 	return 0;
1414 }
1415 
1416 static int
1417 udf_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode,
1418     kauth_cred_t cred)
1419 {
1420 	/* ask the generic genfs_can_access to advice on security */
1421 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
1422 	    vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp->v_type,
1423 	    vap->va_mode, vap->va_uid, vap->va_gid, mode, cred));
1424 }
1425 
1426 int
1427 udf_access(void *v)
1428 {
1429 	struct vop_access_args /* {
1430 		struct vnode *a_vp;
1431 		int a_mode;
1432 		kauth_cred_t a_cred;
1433 		struct proc *a_p;
1434 	} */ *ap = v;
1435 	struct vnode    *vp   = ap->a_vp;
1436 	mode_t	         mode = ap->a_mode;
1437 	kauth_cred_t     cred = ap->a_cred;
1438 	/* struct udf_node *udf_node = VTOI(vp); */
1439 	struct vattr vap;
1440 	int error;
1441 
1442 	DPRINTF(CALL, ("udf_access called\n"));
1443 
1444 	error = VOP_GETATTR(vp, &vap, NULL);
1445 	if (error)
1446 		return error;
1447 
1448 	error = udf_check_possible(vp, &vap, mode);
1449 	if (error)
1450 		return error;
1451 
1452 	error = udf_check_permitted(vp, &vap, mode, cred);
1453 
1454 	return error;
1455 }
1456 
1457 /* --------------------------------------------------------------------- */
1458 
1459 int
1460 udf_create(void *v)
1461 {
1462 	struct vop_create_args /* {
1463 		struct vnode *a_dvp;
1464 		struct vnode **a_vpp;
1465 		struct componentname *a_cnp;
1466 		struct vattr *a_vap;
1467 	} */ *ap = v;
1468 	struct vnode  *dvp = ap->a_dvp;
1469 	struct vnode **vpp = ap->a_vpp;
1470 	struct vattr  *vap  = ap->a_vap;
1471 	struct componentname *cnp = ap->a_cnp;
1472 	int error;
1473 
1474 	DPRINTF(CALL, ("udf_create called\n"));
1475 	error = udf_create_node(dvp, vpp, vap, cnp);
1476 
1477 	vput(dvp);
1478 	return error;
1479 }
1480 
1481 /* --------------------------------------------------------------------- */
1482 
1483 int
1484 udf_mknod(void *v)
1485 {
1486 	struct vop_mknod_args /* {
1487 		struct vnode *a_dvp;
1488 		struct vnode **a_vpp;
1489 		struct componentname *a_cnp;
1490 		struct vattr *a_vap;
1491 	} */ *ap = v;
1492 	struct vnode  *dvp = ap->a_dvp;
1493 	struct vnode **vpp = ap->a_vpp;
1494 	struct vattr  *vap  = ap->a_vap;
1495 	struct componentname *cnp = ap->a_cnp;
1496 	int error;
1497 
1498 	DPRINTF(CALL, ("udf_mknod called\n"));
1499 	error = udf_create_node(dvp, vpp, vap, cnp);
1500 
1501 	vput(dvp);
1502 	return error;
1503 }
1504 
1505 /* --------------------------------------------------------------------- */
1506 
1507 int
1508 udf_mkdir(void *v)
1509 {
1510 	struct vop_mkdir_args /* {
1511 		struct vnode *a_dvp;
1512 		struct vnode **a_vpp;
1513 		struct componentname *a_cnp;
1514 		struct vattr *a_vap;
1515 	} */ *ap = v;
1516 	struct vnode  *dvp = ap->a_dvp;
1517 	struct vnode **vpp = ap->a_vpp;
1518 	struct vattr  *vap  = ap->a_vap;
1519 	struct componentname *cnp = ap->a_cnp;
1520 	int error;
1521 
1522 	DPRINTF(CALL, ("udf_mkdir called\n"));
1523 	error = udf_create_node(dvp, vpp, vap, cnp);
1524 
1525 	vput(dvp);
1526 	return error;
1527 }
1528 
1529 /* --------------------------------------------------------------------- */
1530 
1531 static int
1532 udf_do_link(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
1533 {
1534 	struct udf_node *udf_node, *dir_node;
1535 	struct vattr vap;
1536 	int error;
1537 
1538 	DPRINTF(CALL, ("udf_link called\n"));
1539 	KASSERT(dvp != vp);
1540 	KASSERT(vp->v_type != VDIR);
1541 	KASSERT(dvp->v_mount == vp->v_mount);
1542 
1543 	/* get attributes */
1544 	dir_node = VTOI(dvp);
1545 	udf_node = VTOI(vp);
1546 
1547 	error = VOP_GETATTR(vp, &vap, FSCRED);
1548 	if (error) {
1549 		VOP_UNLOCK(vp);
1550 		return error;
1551 	}
1552 
1553 	/* check link count overflow */
1554 	if (vap.va_nlink >= (1<<16)-1) {	/* uint16_t */
1555 		VOP_UNLOCK(vp);
1556 		return EMLINK;
1557 	}
1558 
1559 	error = udf_dir_attach(dir_node->ump, dir_node, udf_node, &vap, cnp);
1560 	if (error)
1561 		VOP_UNLOCK(vp);
1562 	return error;
1563 }
1564 
1565 int
1566 udf_link(void *v)
1567 {
1568 	struct vop_link_args /* {
1569 		struct vnode *a_dvp;
1570 		struct vnode *a_vp;
1571 		struct componentname *a_cnp;
1572 	} */ *ap = v;
1573 	struct vnode *dvp = ap->a_dvp;
1574 	struct vnode *vp  = ap->a_vp;
1575 	struct componentname *cnp = ap->a_cnp;
1576 	int error;
1577 
1578 	error = udf_do_link(dvp, vp, cnp);
1579 	if (error)
1580 		VOP_ABORTOP(dvp, cnp);
1581 
1582 	VN_KNOTE(vp, NOTE_LINK);
1583 	VN_KNOTE(dvp, NOTE_WRITE);
1584 	vput(dvp);
1585 
1586 	return error;
1587 }
1588 
1589 /* --------------------------------------------------------------------- */
1590 
1591 static int
1592 udf_do_symlink(struct udf_node *udf_node, char *target)
1593 {
1594 	struct pathcomp pathcomp;
1595 	uint8_t *pathbuf, *pathpos, *compnamepos;
1596 	char *mntonname;
1597 	int pathlen, len, compnamelen, mntonnamelen;
1598 	int error;
1599 
1600 	/* process `target' to an UDF structure */
1601 	pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK);
1602 	pathpos = pathbuf;
1603 	pathlen = 0;
1604 
1605 	if (*target == '/') {
1606 		/* symlink starts from the root */
1607 		len = UDF_PATH_COMP_SIZE;
1608 		memset(&pathcomp, 0, len);
1609 		pathcomp.type = UDF_PATH_COMP_ROOT;
1610 
1611 		/* check if its mount-point relative! */
1612 		mntonname    = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1613 		mntonnamelen = strlen(mntonname);
1614 		if (strlen(target) >= mntonnamelen) {
1615 			if (strncmp(target, mntonname, mntonnamelen) == 0) {
1616 				pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
1617 				target += mntonnamelen;
1618 			}
1619 		} else {
1620 			target++;
1621 		}
1622 
1623 		memcpy(pathpos, &pathcomp, len);
1624 		pathpos += len;
1625 		pathlen += len;
1626 	}
1627 
1628 	error = 0;
1629 	while (*target) {
1630 		/* ignore multiple '/' */
1631 		while (*target == '/') {
1632 			target++;
1633 		}
1634 		if (!*target)
1635 			break;
1636 
1637 		/* extract component name */
1638 		compnamelen = 0;
1639 		compnamepos = target;
1640 		while ((*target) && (*target != '/')) {
1641 			target++;
1642 			compnamelen++;
1643 		}
1644 
1645 		/* just trunc if too long ?? (security issue) */
1646 		if (compnamelen >= 127) {
1647 			error = ENAMETOOLONG;
1648 			break;
1649 		}
1650 
1651 		/* convert unix name to UDF name */
1652 		len = sizeof(struct pathcomp);
1653 		memset(&pathcomp, 0, len);
1654 		pathcomp.type = UDF_PATH_COMP_NAME;
1655 		len = UDF_PATH_COMP_SIZE;
1656 
1657 		if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
1658 			pathcomp.type = UDF_PATH_COMP_PARENTDIR;
1659 		if ((compnamelen == 1) && (*compnamepos == '.'))
1660 			pathcomp.type = UDF_PATH_COMP_CURDIR;
1661 
1662 		if (pathcomp.type == UDF_PATH_COMP_NAME) {
1663 			unix_to_udf_name(
1664 				(char *) &pathcomp.ident, &pathcomp.l_ci,
1665 				compnamepos, compnamelen,
1666 				&udf_node->ump->logical_vol->desc_charset);
1667 			len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
1668 		}
1669 
1670 		if (pathlen + len >= UDF_SYMLINKBUFLEN) {
1671 			error = ENAMETOOLONG;
1672 			break;
1673 		}
1674 
1675 		memcpy(pathpos, &pathcomp, len);
1676 		pathpos += len;
1677 		pathlen += len;
1678 	}
1679 
1680 	if (error) {
1681 		/* aparently too big */
1682 		free(pathbuf, M_UDFTEMP);
1683 		return error;
1684 	}
1685 
1686 	error = udf_grow_node(udf_node, pathlen);
1687 	if (error) {
1688 		/* failed to pregrow node */
1689 		free(pathbuf, M_UDFTEMP);
1690 		return error;
1691 	}
1692 
1693 	/* write out structure on the new file */
1694 	error = vn_rdwr(UIO_WRITE, udf_node->vnode,
1695 		pathbuf, pathlen, 0,
1696 		UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS,
1697 		FSCRED, NULL, NULL);
1698 
1699 	/* return status of symlink contents writeout */
1700 	free(pathbuf, M_UDFTEMP);
1701 	return error;
1702 }
1703 
1704 
1705 int
1706 udf_symlink(void *v)
1707 {
1708 	struct vop_symlink_args /* {
1709 		struct vnode *a_dvp;
1710 		struct vnode **a_vpp;
1711 		struct componentname *a_cnp;
1712 		struct vattr *a_vap;
1713 		char *a_target;
1714 	} */ *ap = v;
1715 	struct vnode  *dvp = ap->a_dvp;
1716 	struct vnode **vpp = ap->a_vpp;
1717 	struct vattr  *vap  = ap->a_vap;
1718 	struct componentname *cnp = ap->a_cnp;
1719 	struct udf_node *dir_node;
1720 	struct udf_node *udf_node;
1721 	int error;
1722 
1723 	DPRINTF(CALL, ("udf_symlink called\n"));
1724 	DPRINTF(CALL, ("\tlinking to `%s`\n",  ap->a_target));
1725 	error = udf_create_node(dvp, vpp, vap, cnp);
1726 	KASSERT(((error == 0) && (*vpp != NULL)) || ((error && (*vpp == NULL))));
1727 	if (!error) {
1728 		dir_node = VTOI(dvp);
1729 		udf_node = VTOI(*vpp);
1730 		KASSERT(udf_node);
1731 		error = udf_do_symlink(udf_node, ap->a_target);
1732 		if (error) {
1733 			/* remove node */
1734 			udf_shrink_node(udf_node, 0);
1735 			udf_dir_detach(udf_node->ump, dir_node, udf_node, cnp);
1736 		}
1737 	}
1738 	vput(dvp);
1739 	return error;
1740 }
1741 
1742 /* --------------------------------------------------------------------- */
1743 
1744 int
1745 udf_readlink(void *v)
1746 {
1747 	struct vop_readlink_args /* {
1748 		struct vnode *a_vp;
1749 		struct uio *a_uio;
1750 		kauth_cred_t a_cred;
1751 	} */ *ap = v;
1752 	struct vnode *vp = ap->a_vp;
1753 	struct uio *uio = ap->a_uio;
1754 	kauth_cred_t cred = ap->a_cred;
1755 	struct udf_node *udf_node;
1756 	struct pathcomp pathcomp;
1757 	struct vattr vattr;
1758 	uint8_t *pathbuf, *targetbuf, *tmpname;
1759 	uint8_t *pathpos, *targetpos;
1760 	char *mntonname;
1761 	int pathlen, targetlen, namelen, mntonnamelen, len, l_ci;
1762 	int first, error;
1763 
1764 	DPRINTF(CALL, ("udf_readlink called\n"));
1765 
1766 	udf_node = VTOI(vp);
1767 	error = VOP_GETATTR(vp, &vattr, cred);
1768 	if (error)
1769 		return error;
1770 
1771 	/* claim temporary buffers for translation */
1772 	pathbuf   = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK);
1773 	targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK);
1774 	tmpname   = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK);
1775 	memset(pathbuf, 0, UDF_SYMLINKBUFLEN);
1776 	memset(targetbuf, 0, PATH_MAX);
1777 
1778 	/* read contents of file in our temporary buffer */
1779 	error = vn_rdwr(UIO_READ, udf_node->vnode,
1780 		pathbuf, vattr.va_size, 0,
1781 		UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS,
1782 		FSCRED, NULL, NULL);
1783 	if (error) {
1784 		/* failed to read in symlink contents */
1785 		free(pathbuf, M_UDFTEMP);
1786 		free(targetbuf, M_UDFTEMP);
1787 		free(tmpname, M_UDFTEMP);
1788 		return error;
1789 	}
1790 
1791 	/* convert to a unix path */
1792 	pathpos   = pathbuf;
1793 	pathlen   = 0;
1794 	targetpos = targetbuf;
1795 	targetlen = PATH_MAX;
1796 	mntonname    = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1797 	mntonnamelen = strlen(mntonname);
1798 
1799 	error = 0;
1800 	first = 1;
1801 	while (vattr.va_size - pathlen >= UDF_PATH_COMP_SIZE) {
1802 		len = UDF_PATH_COMP_SIZE;
1803 		memcpy(&pathcomp, pathpos, len);
1804 		l_ci = pathcomp.l_ci;
1805 		switch (pathcomp.type) {
1806 		case UDF_PATH_COMP_ROOT :
1807 			/* XXX should check for l_ci; bugcompatible now */
1808 			if ((targetlen < 1) || !first) {
1809 				error = EINVAL;
1810 				break;
1811 			}
1812 			*targetpos++ = '/'; targetlen--;
1813 			break;
1814 		case UDF_PATH_COMP_MOUNTROOT :
1815 			/* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */
1816 			if (l_ci || (targetlen < mntonnamelen+1) || !first) {
1817 				error = EINVAL;
1818 				break;
1819 			}
1820 			memcpy(targetpos, mntonname, mntonnamelen);
1821 			targetpos += mntonnamelen; targetlen -= mntonnamelen;
1822 			if (vattr.va_size-pathlen > UDF_PATH_COMP_SIZE+l_ci) {
1823 				/* more follows, so must be directory */
1824 				*targetpos++ = '/'; targetlen--;
1825 			}
1826 			break;
1827 		case UDF_PATH_COMP_PARENTDIR :
1828 			/* XXX should check for l_ci; bugcompatible now */
1829 			if (targetlen < 3) {
1830 				error = EINVAL;
1831 				break;
1832 			}
1833 			*targetpos++ = '.'; targetlen--;
1834 			*targetpos++ = '.'; targetlen--;
1835 			*targetpos++ = '/'; targetlen--;
1836 			break;
1837 		case UDF_PATH_COMP_CURDIR :
1838 			/* XXX should check for l_ci; bugcompatible now */
1839 			if (targetlen < 2) {
1840 				error = EINVAL;
1841 				break;
1842 			}
1843 			*targetpos++ = '.'; targetlen--;
1844 			*targetpos++ = '/'; targetlen--;
1845 			break;
1846 		case UDF_PATH_COMP_NAME :
1847 			if (l_ci == 0) {
1848 				error = EINVAL;
1849 				break;
1850 			}
1851 			memset(tmpname, 0, PATH_MAX);
1852 			memcpy(&pathcomp, pathpos, len + l_ci);
1853 			udf_to_unix_name(tmpname, MAXPATHLEN,
1854 				pathcomp.ident, l_ci,
1855 				&udf_node->ump->logical_vol->desc_charset);
1856 			namelen = strlen(tmpname);
1857 			if (targetlen < namelen + 1) {
1858 				error = EINVAL;
1859 				break;
1860 			}
1861 			memcpy(targetpos, tmpname, namelen);
1862 			targetpos += namelen; targetlen -= namelen;
1863 			if (vattr.va_size-pathlen > UDF_PATH_COMP_SIZE+l_ci) {
1864 				/* more follows, so must be directory */
1865 				*targetpos++ = '/'; targetlen--;
1866 			}
1867 			break;
1868 		default :
1869 			error = EINVAL;
1870 			break;
1871 		}
1872 		first = 0;
1873 		if (error)
1874 			break;
1875 		pathpos += UDF_PATH_COMP_SIZE + l_ci;
1876 		pathlen += UDF_PATH_COMP_SIZE + l_ci;
1877 
1878 	}
1879 	/* all processed? */
1880 	if (vattr.va_size - pathlen > 0)
1881 		error = EINVAL;
1882 
1883 	/* uiomove() to destination */
1884 	if (!error)
1885 		uiomove(targetbuf, PATH_MAX - targetlen, uio);
1886 
1887 	free(pathbuf, M_UDFTEMP);
1888 	free(targetbuf, M_UDFTEMP);
1889 	free(tmpname, M_UDFTEMP);
1890 
1891 	return error;
1892 }
1893 
1894 /* --------------------------------------------------------------------- */
1895 
1896 /*
1897  * udf_rename() moved to udf_rename.c
1898  */
1899 
1900 /* --------------------------------------------------------------------- */
1901 
1902 int
1903 udf_remove(void *v)
1904 {
1905 	struct vop_remove_args /* {
1906 		struct vnode *a_dvp;
1907 		struct vnode *a_vp;
1908 		struct componentname *a_cnp;
1909 	} */ *ap = v;
1910 	struct vnode *dvp = ap->a_dvp;
1911 	struct vnode *vp  = ap->a_vp;
1912 	struct componentname *cnp = ap->a_cnp;
1913 	struct udf_node *dir_node = VTOI(dvp);
1914 	struct udf_node *udf_node = VTOI(vp);
1915 	struct udf_mount *ump = dir_node->ump;
1916 	int error;
1917 
1918 	DPRINTF(CALL, ("udf_remove called\n"));
1919 	if (vp->v_type != VDIR) {
1920 		error = udf_dir_detach(ump, dir_node, udf_node, cnp);
1921 		DPRINTFIF(NODE, error, ("\tgot error removing file\n"));
1922 	} else {
1923 		DPRINTF(NODE, ("\tis a directory: perm. denied\n"));
1924 		error = EPERM;
1925 	}
1926 
1927 	if (error == 0) {
1928 		VN_KNOTE(vp, NOTE_DELETE);
1929 		VN_KNOTE(dvp, NOTE_WRITE);
1930 	}
1931 
1932 	if (dvp == vp)
1933 		vrele(vp);
1934 	else
1935 		vput(vp);
1936 	vput(dvp);
1937 
1938 	return error;
1939 }
1940 
1941 /* --------------------------------------------------------------------- */
1942 
1943 int
1944 udf_rmdir(void *v)
1945 {
1946 	struct vop_rmdir_args /* {
1947 		struct vnode *a_dvp;
1948 		struct vnode *a_vp;
1949 		struct componentname *a_cnp;
1950 	} */ *ap = v;
1951 	struct vnode *vp = ap->a_vp;
1952 	struct vnode *dvp = ap->a_dvp;
1953 	struct componentname *cnp = ap->a_cnp;
1954 	struct udf_node *dir_node = VTOI(dvp);
1955 	struct udf_node *udf_node = VTOI(vp);
1956 	struct udf_mount *ump = dir_node->ump;
1957 	int error, isempty;
1958 
1959 	DPRINTF(NOTIMPL, ("udf_rmdir '%s' called\n", cnp->cn_nameptr));
1960 
1961 	/* don't allow '.' to be deleted */
1962 	if (dir_node == udf_node) {
1963 		vrele(dvp);
1964 		vput(vp);
1965 		return EINVAL;
1966 	}
1967 
1968 	/* make sure our `leaf' node's hash is populated */
1969 	dirhash_get(&udf_node->dir_hash);
1970 	error = udf_dirhash_fill(udf_node);
1971 	if (error) {
1972 		dirhash_put(udf_node->dir_hash);
1973 		return error;
1974 	}
1975 
1976 	/* check to see if the directory is empty */
1977 	isempty = dirhash_dir_isempty(udf_node->dir_hash);
1978 	dirhash_put(udf_node->dir_hash);
1979 
1980 	if (!isempty) {
1981 		vput(dvp);
1982 		vput(vp);
1983 		return ENOTEMPTY;
1984 	}
1985 
1986 	/* detach the node from the directory, udf_node is an empty dir here */
1987 	error = udf_dir_detach(ump, dir_node, udf_node, cnp);
1988 	if (error == 0) {
1989 		cache_purge(vp);
1990 //		cache_purge(dvp);	/* XXX from msdosfs, why? */
1991 		/*
1992 		 * Bug alert: we need to remove '..' from the detaching
1993 		 * udf_node so further lookups of this are not possible. This
1994 		 * prevents a process in a deleted directory from going to its
1995 		 * deleted parent. Since `udf_node' is garanteed to be empty
1996 		 * here, trunc it so no fids are there.
1997 		 */
1998 		dirhash_purge(&udf_node->dir_hash);
1999 		udf_shrink_node(udf_node, 0);
2000 		VN_KNOTE(vp, NOTE_DELETE);
2001 	}
2002 	DPRINTFIF(NODE, error, ("\tgot error removing dir\n"));
2003 
2004 	/* unput the nodes and exit */
2005 	vput(dvp);
2006 	vput(vp);
2007 
2008 	return error;
2009 }
2010 
2011 /* --------------------------------------------------------------------- */
2012 
2013 int
2014 udf_fsync(void *v)
2015 {
2016 	struct vop_fsync_args /* {
2017 		struct vnode *a_vp;
2018 		kauth_cred_t a_cred;
2019 		int a_flags;
2020 		off_t offlo;
2021 		off_t offhi;
2022 		struct proc *a_p;
2023 	} */ *ap = v;
2024 	struct vnode *vp = ap->a_vp;
2025 	struct udf_node *udf_node = VTOI(vp);
2026 	int error, flags, wait;
2027 
2028 	DPRINTF(SYNC, ("udf_fsync called on %p : %s, %s\n",
2029 		udf_node,
2030 		(ap->a_flags & FSYNC_WAIT)     ? "wait":"no wait",
2031 		(ap->a_flags & FSYNC_DATAONLY) ? "data_only":"complete"));
2032 
2033 	/* flush data and wait for it when requested */
2034 	wait = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
2035 	error = vflushbuf(vp, ap->a_flags);
2036 	if (error)
2037 		return error;
2038 
2039 	if (udf_node == NULL) {
2040 		printf("udf_fsync() called on NULL udf_node!\n");
2041 		return 0;
2042 	}
2043 	if (vp->v_tag != VT_UDF) {
2044 		printf("udf_fsync() called on node not tagged as UDF node!\n");
2045 		return 0;
2046 	}
2047 
2048 	/* set our times */
2049 	udf_itimes(udf_node, NULL, NULL, NULL);
2050 
2051 	/* if called when mounted readonly, never write back */
2052 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
2053 		return 0;
2054 
2055 	/* if only data is requested, return */
2056 	if (ap->a_flags & FSYNC_DATAONLY)
2057 		return 0;
2058 
2059 	/* check if the node is dirty 'enough'*/
2060 	flags = udf_node->i_flags & (IN_MODIFIED | IN_ACCESSED);
2061 	if (flags == 0)
2062 		return 0;
2063 
2064 	/* if we don't have to wait, check for IO pending */
2065 	if (!wait) {
2066 		if (vp->v_numoutput > 0) {
2067 			DPRINTF(SYNC, ("udf_fsync %p, rejecting on v_numoutput\n", udf_node));
2068 			return 0;
2069 		}
2070 		if (udf_node->outstanding_bufs > 0) {
2071 			DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_bufs\n", udf_node));
2072 			return 0;
2073 		}
2074 		if (udf_node->outstanding_nodedscr > 0) {
2075 			DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_nodedscr\n", udf_node));
2076 			return 0;
2077 		}
2078 	}
2079 
2080 	/* wait until vp->v_numoutput reaches zero i.e. is finished */
2081 	if (wait) {
2082 		DPRINTF(SYNC, ("udf_fsync %p, waiting\n", udf_node));
2083 		mutex_enter(vp->v_interlock);
2084 		while (vp->v_numoutput) {
2085 			DPRINTF(SYNC, ("udf_fsync %p, v_numoutput %d\n", udf_node, vp->v_numoutput));
2086 			cv_timedwait(&vp->v_cv, vp->v_interlock, hz/8);
2087 		}
2088 		mutex_exit(vp->v_interlock);
2089 		DPRINTF(SYNC, ("udf_fsync %p, fin wait\n", udf_node));
2090 	}
2091 
2092 	/* write out node and wait for it if requested */
2093 	DPRINTF(SYNC, ("udf_fsync %p, writeout node\n", udf_node));
2094 	error = udf_writeout_node(udf_node, wait);
2095 	if (error)
2096 		return error;
2097 
2098 	/* TODO/XXX if ap->a_flags & FSYNC_CACHE, we ought to do a disc sync */
2099 
2100 	return 0;
2101 }
2102 
2103 /* --------------------------------------------------------------------- */
2104 
2105 int
2106 udf_advlock(void *v)
2107 {
2108 	struct vop_advlock_args /* {
2109 		struct vnode *a_vp;
2110 		void *a_id;
2111 		int a_op;
2112 		struct flock *a_fl;
2113 		int a_flags;
2114 	} */ *ap = v;
2115 	struct vnode *vp = ap->a_vp;
2116 	struct udf_node *udf_node = VTOI(vp);
2117 	struct file_entry    *fe;
2118 	struct extfile_entry *efe;
2119 	uint64_t file_size;
2120 
2121 	DPRINTF(LOCKING, ("udf_advlock called\n"));
2122 
2123 	/* get directory filesize */
2124 	if (udf_node->fe) {
2125 		fe = udf_node->fe;
2126 		file_size = udf_rw64(fe->inf_len);
2127 	} else {
2128 		assert(udf_node->efe);
2129 		efe = udf_node->efe;
2130 		file_size = udf_rw64(efe->inf_len);
2131 	}
2132 
2133 	return lf_advlock(ap, &udf_node->lockf, file_size);
2134 }
2135 
2136 /* --------------------------------------------------------------------- */
2137 
2138 /* Global vfs vnode data structures for udfs */
2139 int (**udf_vnodeop_p)(void *);
2140 
2141 const struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
2142 	{ &vop_default_desc, vn_default_error },
2143 	{ &vop_lookup_desc, udf_lookup },	/* lookup */
2144 	{ &vop_create_desc, udf_create },	/* create */
2145 	{ &vop_mknod_desc, udf_mknod },		/* mknod */	/* TODO */
2146 	{ &vop_open_desc, udf_open },		/* open */
2147 	{ &vop_close_desc, udf_close },		/* close */
2148 	{ &vop_access_desc, udf_access },	/* access */
2149 	{ &vop_getattr_desc, udf_getattr },	/* getattr */
2150 	{ &vop_setattr_desc, udf_setattr },	/* setattr */	/* TODO chflags */
2151 	{ &vop_read_desc, udf_read },		/* read */
2152 	{ &vop_write_desc, udf_write },		/* write */	/* WRITE */
2153 	{ &vop_fcntl_desc, genfs_fcntl },	/* fcntl */	/* TODO? */
2154 	{ &vop_ioctl_desc, genfs_enoioctl },	/* ioctl */	/* TODO? */
2155 	{ &vop_poll_desc, genfs_poll },		/* poll */	/* TODO/OK? */
2156 	{ &vop_kqfilter_desc, genfs_kqfilter },	/* kqfilter */	/* ? */
2157 	{ &vop_revoke_desc, genfs_revoke },	/* revoke */	/* TODO? */
2158 	{ &vop_mmap_desc, genfs_mmap },		/* mmap */	/* OK? */
2159 	{ &vop_fsync_desc, udf_fsync },		/* fsync */
2160 	{ &vop_seek_desc, genfs_seek },		/* seek */
2161 	{ &vop_remove_desc, udf_remove },	/* remove */
2162 	{ &vop_link_desc, udf_link },		/* link */	/* TODO */
2163 	{ &vop_rename_desc, udf_rename },	/* rename */ 	/* TODO */
2164 	{ &vop_mkdir_desc, udf_mkdir },		/* mkdir */
2165 	{ &vop_rmdir_desc, udf_rmdir },		/* rmdir */
2166 	{ &vop_symlink_desc, udf_symlink },	/* symlink */	/* TODO */
2167 	{ &vop_readdir_desc, udf_readdir },	/* readdir */
2168 	{ &vop_readlink_desc, udf_readlink },	/* readlink */	/* TEST ME */
2169 	{ &vop_abortop_desc, genfs_abortop },	/* abortop */	/* TODO/OK? */
2170 	{ &vop_inactive_desc, udf_inactive },	/* inactive */
2171 	{ &vop_reclaim_desc, udf_reclaim },	/* reclaim */
2172 	{ &vop_lock_desc, genfs_lock },		/* lock */
2173 	{ &vop_unlock_desc, genfs_unlock },	/* unlock */
2174 	{ &vop_bmap_desc, udf_trivial_bmap },	/* bmap */	/* 1:1 bmap */
2175 	{ &vop_strategy_desc, udf_vfsstrategy },/* strategy */
2176 /*	{ &vop_print_desc, udf_print },	*/	/* print */
2177 	{ &vop_islocked_desc, genfs_islocked },	/* islocked */
2178 	{ &vop_pathconf_desc, udf_pathconf },	/* pathconf */
2179 	{ &vop_advlock_desc, udf_advlock },	/* advlock */	/* TEST ME */
2180 	{ &vop_bwrite_desc, vn_bwrite },	/* bwrite */	/* ->strategy */
2181 	{ &vop_getpages_desc, genfs_getpages },	/* getpages */
2182 	{ &vop_putpages_desc, genfs_putpages },	/* putpages */
2183 	{ NULL, NULL }
2184 };
2185 
2186 
2187 const struct vnodeopv_desc udf_vnodeop_opv_desc = {
2188 	&udf_vnodeop_p, udf_vnodeop_entries
2189 };
2190