xref: /openbsd-src/sys/isofs/udf/udf_vnops.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: udf_vnops.c,v 1.55 2014/07/12 18:50:00 tedu Exp $	*/
2 
3 /*
4  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
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 AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, 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  * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.50 2005/01/28 14:42:16 phk Exp $
29  */
30 
31 /*
32  * Ported to OpenBSD by Pedro Martelletto in February 2005.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/namei.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/stat.h>
42 #include <sys/buf.h>
43 #include <sys/pool.h>
44 #include <sys/lock.h>
45 #include <sys/mount.h>
46 #include <sys/vnode.h>
47 #include <sys/dirent.h>
48 #include <sys/queue.h>
49 #include <sys/unistd.h>
50 #include <sys/endian.h>
51 #include <sys/specdev.h>
52 
53 #include <isofs/udf/ecma167-udf.h>
54 #include <isofs/udf/udf.h>
55 #include <isofs/udf/udf_extern.h>
56 
57 int udf_bmap_internal(struct unode *, off_t, daddr_t *, uint32_t *);
58 
59 struct vops udf_vops = {
60 	.vop_access	= udf_access,
61 	.vop_bmap	= udf_bmap,
62 	.vop_lookup	= udf_lookup,
63 	.vop_getattr	= udf_getattr,
64 	.vop_open	= udf_open,
65 	.vop_close	= udf_close,
66 	.vop_ioctl	= udf_ioctl,
67 	.vop_read	= udf_read,
68 	.vop_readdir	= udf_readdir,
69 	.vop_readlink	= udf_readlink,
70 	.vop_inactive	= udf_inactive,
71 	.vop_reclaim	= udf_reclaim,
72 	.vop_strategy	= udf_strategy,
73 	.vop_lock	= udf_lock,
74 	.vop_unlock	= udf_unlock,
75 	.vop_pathconf	= udf_pathconf,
76 	.vop_islocked	= udf_islocked,
77 	.vop_print	= udf_print
78 };
79 
80 #define UDF_INVALID_BMAP	-1
81 
82 /* Look up a unode based on the udfino_t passed in and return its vnode */
83 int
84 udf_hashlookup(struct umount *ump, udfino_t id, int flags, struct vnode **vpp)
85 {
86 	struct unode *up;
87 	struct udf_hash_lh *lh;
88 	struct proc *p = curproc;
89 	int error;
90 
91 	*vpp = NULL;
92 
93 loop:
94 	mtx_enter(&ump->um_hashmtx);
95 	lh = &ump->um_hashtbl[id & ump->um_hashsz];
96 	if (lh == NULL) {
97 		mtx_leave(&ump->um_hashmtx);
98 		return (ENOENT);
99 	}
100 
101 	LIST_FOREACH(up, lh, u_le) {
102 		if (up->u_ino == id) {
103 			mtx_leave(&ump->um_hashmtx);
104 			error = vget(up->u_vnode, flags, p);
105 			if (error == ENOENT)
106 				goto loop;
107 			if (error)
108 				return (error);
109 			*vpp = up->u_vnode;
110 			return (0);
111 		}
112 	}
113 
114 	mtx_leave(&ump->um_hashmtx);
115 
116 	return (0);
117 }
118 
119 int
120 udf_hashins(struct unode *up)
121 {
122 	struct umount *ump;
123 	struct udf_hash_lh *lh;
124 	struct proc *p = curproc;
125 
126 	ump = up->u_ump;
127 
128 	vn_lock(up->u_vnode, LK_EXCLUSIVE | LK_RETRY, p);
129 	mtx_enter(&ump->um_hashmtx);
130 	lh = &ump->um_hashtbl[up->u_ino & ump->um_hashsz];
131 	if (lh == NULL)
132 		panic("hash entry is NULL, up->u_ino = %d", up->u_ino);
133 	LIST_INSERT_HEAD(lh, up, u_le);
134 	mtx_leave(&ump->um_hashmtx);
135 
136 	return (0);
137 }
138 
139 int
140 udf_hashrem(struct unode *up)
141 {
142 	struct umount *ump;
143 	struct udf_hash_lh *lh;
144 
145 	ump = up->u_ump;
146 
147 	mtx_enter(&ump->um_hashmtx);
148 	lh = &ump->um_hashtbl[up->u_ino & ump->um_hashsz];
149 	if (lh == NULL)
150 		panic("hash entry is NULL, up->u_ino = %d", up->u_ino);
151 	LIST_REMOVE(up, u_le);
152 	mtx_leave(&ump->um_hashmtx);
153 
154 	return (0);
155 }
156 
157 int
158 udf_allocv(struct mount *mp, struct vnode **vpp, struct proc *p)
159 {
160 	int error;
161 	struct vnode *vp;
162 
163 	error = getnewvnode(VT_UDF, mp, &udf_vops, &vp);
164 	if (error) {
165 		printf("udf_allocv: failed to allocate new vnode\n");
166 		return (error);
167 	}
168 
169 	*vpp = vp;
170 	return (0);
171 }
172 
173 /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
174 static mode_t
175 udf_permtomode(struct unode *up)
176 {
177 	uint32_t perm;
178 	uint16_t flags;
179 	mode_t mode;
180 
181 	perm = letoh32(up->u_fentry->perm);
182 	flags = letoh16(up->u_fentry->icbtag.flags);
183 
184 	mode = perm & UDF_FENTRY_PERM_USER_MASK;
185 	mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
186 	mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
187 	mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
188 	mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
189 	mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
190 
191 	return (mode);
192 }
193 
194 int
195 udf_access(void *v)
196 {
197 	struct vop_access_args *ap = v;
198 	struct vnode *vp;
199 	struct unode *up;
200 	mode_t a_mode, mode;
201 
202 	vp = ap->a_vp;
203 	up = VTOU(vp);
204 	a_mode = ap->a_mode;
205 
206 	if (a_mode & VWRITE) {
207 		switch (vp->v_type) {
208 		case VDIR:
209 		case VLNK:
210 		case VREG:
211 			return (EROFS);
212 			/* NOTREACHED */
213 		default:
214 			break;
215 		}
216 	}
217 
218 	mode = udf_permtomode(up);
219 
220 	return (vaccess(vp->v_type, mode, up->u_fentry->uid, up->u_fentry->gid,
221 	    a_mode, ap->a_cred));
222 }
223 
224 static int mon_lens[2][12] = {
225 	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
226 	{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
227 };
228 
229 static int
230 udf_isaleapyear(int year)
231 {
232 	int i;
233 
234 	i = (year % 4) ? 0 : 1;
235 	i &= (year % 100) ? 1 : 0;
236 	i |= (year % 400) ? 0 : 1;
237 
238 	return (i);
239 }
240 
241 /*
242  * This is just a rough hack.  Daylight savings isn't calculated and tv_nsec
243  * is ignored.
244  * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
245  */
246 static void
247 udf_timetotimespec(struct timestamp *time, struct timespec *t)
248 {
249 	int i, lpyear, daysinyear, year;
250 	union {
251 		uint16_t	u_tz_offset;
252 		int16_t		s_tz_offset;
253 	} tz;
254 
255 	/* DirectCD seems to like using bogus year values */
256 	year = letoh16(time->year);
257 	if (year < 1970) {
258 		t->tv_sec = 0;
259 		t->tv_nsec = 0;
260 		return;
261 	}
262 
263 	/* Calculate the time and day */
264 	t->tv_nsec = 1000 * time->usec + 100000 * time->hund_usec
265 	    + 10000000 * time->centisec;
266 	t->tv_sec = time->second;
267 	t->tv_sec += time->minute * 60;
268 	t->tv_sec += time->hour * 3600;
269 	t->tv_sec += time->day * 3600 * 24;
270 
271 	/* Calculate the month */
272 	lpyear = udf_isaleapyear(year);
273 	for (i = 1; i < time->month; i++)
274 		t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
275 
276 	/* Speed up the calculation */
277 	if (year > 1979)
278 		t->tv_sec += 315532800;
279 	if (year > 1989)
280 		t->tv_sec += 315619200;
281 	if (year > 1999)
282 		t->tv_sec += 315532800;
283 	for (i = 2000; i < year; i++) {
284 		daysinyear = udf_isaleapyear(i) + 365 ;
285 		t->tv_sec += daysinyear * 3600 * 24;
286 	}
287 
288 	/*
289 	 * Calculate the time zone.  The timezone is 12 bit signed 2's
290 	 * compliment, so we gotta do some extra magic to handle it right.
291 	 */
292 	tz.u_tz_offset = letoh16(time->type_tz);
293 	tz.u_tz_offset &= 0x0fff;
294 	if (tz.u_tz_offset & 0x0800)
295 		tz.u_tz_offset |= 0xf000;	/* extend the sign to 16 bits */
296 	if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
297 		t->tv_sec -= tz.s_tz_offset * 60;
298 
299 	return;
300 }
301 
302 int
303 udf_getattr(void *v)
304 {
305 	struct vop_getattr_args *ap = v;
306 	struct vnode *vp;
307 	struct unode *up;
308 	struct vattr *vap;
309 	struct extfile_entry *xfentry;
310 	struct file_entry *fentry;
311 	struct timespec ts;
312 
313 	ts.tv_sec = 0;
314 
315 	vp = ap->a_vp;
316 	vap = ap->a_vap;
317 	up = VTOU(vp);
318 
319 	xfentry = up->u_fentry;
320 	fentry = (struct file_entry *)up->u_fentry;
321 
322 	vap->va_fsid = up->u_dev;
323 	vap->va_fileid = up->u_ino;
324 	vap->va_mode = udf_permtomode(up);
325 	vap->va_nlink = letoh16(fentry->link_cnt);
326 	/*
327 	 * The spec says that -1 is valid for uid/gid and indicates an
328 	 * invalid uid/gid.  How should this be represented?
329 	 */
330 	vap->va_uid = (letoh32(fentry->uid) == -1) ? 0 : letoh32(fentry->uid);
331 	vap->va_gid = (letoh32(fentry->gid) == -1) ? 0 : letoh32(fentry->gid);
332 	vap->va_rdev = 0;
333 	if (vp->v_type & VDIR) {
334 		vap->va_nlink++; /* Count a reference to ourselves */
335 		/*
336 		 * Directories that are recorded within their ICB will show
337 		 * as having 0 blocks recorded.  Since tradition dictates
338 		 * that directories consume at least one logical block,
339 		 * make it appear so.
340 		 */
341 		vap->va_size = up->u_ump->um_bsize;
342 	} else
343 		vap->va_size = letoh64(fentry->inf_len);
344 	if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) {
345 		udf_timetotimespec(&xfentry->atime, &vap->va_atime);
346 		udf_timetotimespec(&xfentry->mtime, &vap->va_mtime);
347 		if ((vp->v_type & VDIR) && xfentry->logblks_rec != 0)
348 			vap->va_size =
349 				    letoh64(xfentry->logblks_rec) * up->u_ump->um_bsize;
350 	} else {
351 		udf_timetotimespec(&fentry->atime, &vap->va_atime);
352 		udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
353 		if ((vp->v_type & VDIR) && fentry->logblks_rec != 0)
354 			vap->va_size =
355 				    letoh64(fentry->logblks_rec) * up->u_ump->um_bsize;
356 	}
357 	vap->va_ctime = vap->va_mtime; /* Stored as an Extended Attribute */
358 	vap->va_flags = 0;
359 	vap->va_gen = 1;
360 	vap->va_blocksize = up->u_ump->um_bsize;
361 	vap->va_bytes = letoh64(fentry->inf_len);
362 	vap->va_type = vp->v_type;
363 	vap->va_filerev = 0;
364 
365 	return (0);
366 }
367 
368 int
369 udf_open(void *v)
370 {
371 	return (0); /* Nothing to be done at this point */
372 }
373 
374 int
375 udf_close(void *v)
376 {
377 	return (0); /* Nothing to be done at this point */
378 }
379 
380 /*
381  * File specific ioctls.
382  */
383 int
384 udf_ioctl(void *v)
385 {
386 	return (ENOTTY);
387 }
388 
389 /*
390  * I'm not sure that this has much value in a read-only filesystem, but
391  * cd9660 has it too.
392  */
393 int
394 udf_pathconf(void *v)
395 {
396 	struct vop_pathconf_args *ap = v;
397 	int error = 0;
398 
399 	switch (ap->a_name) {
400 	case _PC_LINK_MAX:
401 		*ap->a_retval = 65535;
402 		break;
403 	case _PC_NAME_MAX:
404 		*ap->a_retval = NAME_MAX;
405 		break;
406 	case _PC_CHOWN_RESTRICTED:
407 		*ap->a_retval = 1;
408 		break;
409 	case _PC_NO_TRUNC:
410 		*ap->a_retval = 1;
411 		break;
412 	case _PC_TIMESTAMP_RESOLUTION:
413 		*ap->a_retval = 1000;		/* 1 microsecond */
414 		break;
415 	default:
416 		error = EINVAL;
417 		break;
418 	}
419 
420 	return (error);
421 }
422 
423 int
424 udf_read(void *v)
425 {
426 	struct vop_read_args *ap = v;
427 	struct vnode *vp = ap->a_vp;
428 	struct uio *uio = ap->a_uio;
429 	struct unode *up = VTOU(vp);
430 	struct buf *bp;
431 	uint8_t *data;
432 	off_t fsize, offset;
433 	int error = 0;
434 	int size;
435 
436 	if (uio->uio_offset < 0)
437 		return (EINVAL);
438 
439 	fsize = letoh64(up->u_fentry->inf_len);
440 
441 	while (uio->uio_offset < fsize && uio->uio_resid > 0) {
442 		offset = uio->uio_offset;
443 		if (uio->uio_resid + offset <= fsize)
444 			size = uio->uio_resid;
445 		else
446 			size = fsize - offset;
447 		error = udf_readatoffset(up, &size, offset, &bp, &data);
448 		if (error == 0)
449 			error = uiomove(data, size, uio);
450 		if (bp != NULL) {
451 			brelse(bp);
452 			bp = NULL;
453 		}
454 		if (error)
455 			break;
456 	};
457 
458 	return (error);
459 }
460 
461 /*
462  * Translate the name from a CS0 dstring to a 16-bit Unicode String.
463  * Hooks need to be placed in here to translate from Unicode to the encoding
464  * that the kernel/user expects.  Return the length of the translated string.
465  */
466 int
467 udf_transname(char *cs0string, char *destname, int len, struct umount *ump)
468 {
469 	unicode_t *transname;
470 	int i, unilen = 0, destlen;
471 
472 	if (len > MAXNAMLEN) {
473 #ifdef DIAGNOSTIC
474 		printf("udf_transname(): name too long\n");
475 #endif
476 		return (0);
477 	}
478 
479 	/* allocate a buffer big enough to hold an 8->16 bit expansion */
480 	transname = pool_get(&udf_trans_pool, PR_WAITOK);
481 
482 	if ((unilen = udf_rawnametounicode(len, cs0string, transname)) == -1) {
483 #ifdef DIAGNOSTIC
484 		printf("udf_transname(): Unicode translation failed\n");
485 #endif
486 		pool_put(&udf_trans_pool, transname);
487 		return (0);
488 	}
489 
490 	/* Pack it back to 8-bit Unicode. */
491 	for (i = 0; i < unilen ; i++)
492 		if (transname[i] & 0xff00)
493 			destname[i] = '?';	/* Fudge the 16bit chars */
494 		else
495 			destname[i] = transname[i] & 0xff;
496 
497 	pool_put(&udf_trans_pool, transname);
498 
499 	/* Don't forget to terminate the string. */
500 	destname[unilen] = 0;
501 	destlen = unilen;
502 
503 	return (destlen);
504 }
505 
506 /*
507  * Compare a CS0 dstring with a name passed in from the VFS layer.  Return
508  * 0 on a successful match, nonzero otherwise.  Unicode work may need to be
509  * done here also.
510  */
511 static int
512 udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct umount *ump)
513 {
514 	char *transname;
515 	int error = 0;
516 
517 	/* This is overkill, but not worth creating a new pool */
518 	transname = pool_get(&udf_trans_pool, PR_WAITOK);
519 
520 	cs0len = udf_transname(cs0string, transname, cs0len, ump);
521 
522 	/* Easy check.  If they aren't the same length, they aren't equal */
523 	if ((cs0len == 0) || (cs0len != cmplen))
524 		error = -1;
525 	else
526 		error = bcmp(transname, cmpname, cmplen);
527 
528 	pool_put(&udf_trans_pool, transname);
529 
530 	return (error);
531 }
532 
533 struct udf_uiodir {
534 	struct dirent *dirent;
535 	int eofflag;
536 };
537 
538 static int
539 udf_uiodir(struct udf_uiodir *uiodir, struct uio *uio, long off)
540 {
541 	int de_size = DIRENT_SIZE(uiodir->dirent);
542 
543 	if (uio->uio_resid < de_size) {
544 		uiodir->eofflag = 0;
545 		return (-1);
546 	}
547 	uiodir->dirent->d_off = off;
548 	uiodir->dirent->d_reclen = de_size;
549 
550 	return (uiomove(uiodir->dirent, de_size, uio));
551 }
552 
553 static struct udf_dirstream *
554 udf_opendir(struct unode *up, int offset, int fsize, struct umount *ump)
555 {
556 	struct udf_dirstream *ds;
557 
558 	ds = pool_get(&udf_ds_pool, PR_WAITOK | PR_ZERO);
559 
560 	ds->node = up;
561 	ds->offset = offset;
562 	ds->ump = ump;
563 	ds->fsize = fsize;
564 
565 	return (ds);
566 }
567 
568 static struct fileid_desc *
569 udf_getfid(struct udf_dirstream *ds)
570 {
571 	struct fileid_desc *fid;
572 	int error, frag_size = 0, total_fid_size;
573 
574 	/* End of directory? */
575 	if (ds->offset + ds->off >= ds->fsize) {
576 		ds->error = 0;
577 		return (NULL);
578 	}
579 
580 	/* Grab the first extent of the directory */
581 	if (ds->off == 0) {
582 		ds->size = 0;
583 		error = udf_readatoffset(ds->node, &ds->size, ds->offset,
584 		    &ds->bp, &ds->data);
585 		if (error) {
586 			ds->error = error;
587 			if (ds->bp != NULL) {
588 				brelse(ds->bp);
589 				ds->bp = NULL;
590 			}
591 			return (NULL);
592 		}
593 	}
594 
595 	/*
596 	 * Clean up from a previous fragmented FID.
597 	 * Is this the right place for this?
598 	 */
599 	if (ds->fid_fragment && ds->buf != NULL) {
600 		ds->fid_fragment = 0;
601 		free(ds->buf, M_UDFFID, 0);
602 	}
603 
604 	fid = (struct fileid_desc*)&ds->data[ds->off];
605 
606 	/*
607 	 * Check to see if the fid is fragmented. The first test
608 	 * ensures that we don't wander off the end of the buffer
609 	 * looking for the l_iu and l_fi fields.
610 	 */
611 	if (ds->off + UDF_FID_SIZE > ds->size ||
612 	    ds->off + letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
613 
614 		/* Copy what we have of the fid into a buffer */
615 		frag_size = ds->size - ds->off;
616 		if (frag_size >= ds->ump->um_bsize) {
617 			printf("udf: invalid FID fragment\n");
618 			ds->error = EINVAL;
619 			return (NULL);
620 		}
621 
622 		/*
623 		 * File ID descriptors can only be at most one
624 		 * logical sector in size.
625 		 */
626 		ds->buf = malloc(ds->ump->um_bsize, M_UDFFID, M_WAITOK|M_ZERO);
627 		bcopy(fid, ds->buf, frag_size);
628 
629 		/* Reduce all of the casting magic */
630 		fid = (struct fileid_desc*)ds->buf;
631 
632 		if (ds->bp != NULL) {
633 			brelse(ds->bp);
634 			ds->bp = NULL;
635 		}
636 
637 		/* Fetch the next allocation */
638 		ds->offset += ds->size;
639 		ds->size = 0;
640 		error = udf_readatoffset(ds->node, &ds->size, ds->offset,
641 		    &ds->bp, &ds->data);
642 		if (error) {
643 			ds->error = error;
644 			if (ds->bp != NULL) {
645 				brelse(ds->bp);
646 				ds->bp = NULL;
647 			}
648 			return (NULL);
649 		}
650 
651 		/*
652 		 * If the fragment was so small that we didn't get
653 		 * the l_iu and l_fi fields, copy those in.
654 		 */
655 		if (frag_size < UDF_FID_SIZE)
656 			bcopy(ds->data, &ds->buf[frag_size],
657 			    UDF_FID_SIZE - frag_size);
658 
659 		/*
660 		 * Now that we have enough of the fid to work with,
661 		 * copy in the rest of the fid from the new
662 		 * allocation.
663 		 */
664 		total_fid_size = UDF_FID_SIZE + letoh16(fid->l_iu) + fid->l_fi;
665 		if (total_fid_size > ds->ump->um_bsize) {
666 			printf("udf: invalid FID\n");
667 			ds->error = EIO;
668 			return (NULL);
669 		}
670 		bcopy(ds->data, &ds->buf[frag_size],
671 		    total_fid_size - frag_size);
672 
673 		ds->fid_fragment = 1;
674 	} else {
675 		total_fid_size = letoh16(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
676 	}
677 
678 	/*
679 	 * Update the offset. Align on a 4 byte boundary because the
680 	 * UDF spec says so.
681 	 */
682 	if (!ds->fid_fragment) {
683 		ds->off += (total_fid_size + 3) & ~0x03;
684 	} else {
685 		ds->off = (total_fid_size - frag_size + 3) & ~0x03;
686 	}
687 	ds->this_off = ds->offset + ds->off;
688 
689 	return (fid);
690 }
691 
692 static void
693 udf_closedir(struct udf_dirstream *ds)
694 {
695 
696 	if (ds->bp != NULL) {
697 		brelse(ds->bp);
698 		ds->bp = NULL;
699 	}
700 
701 	if (ds->fid_fragment && ds->buf != NULL)
702 		free(ds->buf, M_UDFFID, 0);
703 
704 	pool_put(&udf_ds_pool, ds);
705 }
706 
707 #define SELF_OFFSET	1
708 #define PARENT_OFFSET	2
709 
710 int
711 udf_readdir(void *v)
712 {
713 	struct vop_readdir_args *ap = v;
714 	struct vnode *vp;
715 	struct uio *uio;
716 	struct dirent dir;
717 	struct unode *up;
718 	struct umount *ump;
719 	struct fileid_desc *fid;
720 	struct udf_uiodir uiodir;
721 	struct udf_dirstream *ds;
722 	off_t last_off;
723 	enum { MODE_NORMAL, MODE_SELF, MODE_PARENT } mode;
724 	int error = 0;
725 
726 	vp = ap->a_vp;
727 	uio = ap->a_uio;
728 	up = VTOU(vp);
729 	ump = up->u_ump;
730 	uiodir.eofflag = 1;
731 	uiodir.dirent = &dir;
732 	memset(&dir, 0, sizeof(dir));
733 
734 	/*
735 	 * if asked to start at SELF_OFFSET or PARENT_OFFSET, search
736 	 * for the parent ref
737 	 */
738 	if (uio->uio_offset == SELF_OFFSET) {
739 		mode = MODE_SELF;
740 		uio->uio_offset = 0;
741 	} else if (uio->uio_offset == PARENT_OFFSET) {
742 		mode = MODE_PARENT;
743 		uio->uio_offset = 0;
744 	} else
745 		mode = MODE_NORMAL;
746 
747 	/*
748 	 * Iterate through the file id descriptors.  Give the parent dir
749 	 * entry special attention.
750 	 */
751 	if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
752 		up->u_ump->um_start += up->u_ump->um_meta_start;
753 		up->u_ump->um_len = up->u_ump->um_meta_len;
754 	}
755 	ds = udf_opendir(up, uio->uio_offset,
756 	    letoh64(up->u_fentry->inf_len), up->u_ump);
757 
758 	last_off = ds->offset + ds->off;
759 	while ((fid = udf_getfid(ds)) != NULL) {
760 
761 		/* Should we return an error on a bad fid? */
762 		if (udf_checktag(&fid->tag, TAGID_FID)) {
763 			printf("Invalid FID tag (%d)\n", fid->tag.id);
764 			error = EIO;
765 			break;
766 		}
767 
768 		/* Is this a deleted file? */
769 		if (fid->file_char & UDF_FILE_CHAR_DEL)
770 			continue;
771 
772 		if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
773 			/* Do up the '.' and '..' entries.  Dummy values are
774 			 * used for the offset since the offset here is
775 			 * usually zero, and NFS doesn't like that value
776 			 */
777 			if (mode == MODE_NORMAL) {
778 				dir.d_fileno = up->u_ino;
779 				dir.d_type = DT_DIR;
780 				dir.d_name[0] = '.';
781 				dir.d_name[1] = '\0';
782 				dir.d_namlen = 1;
783 				error = udf_uiodir(&uiodir, uio, SELF_OFFSET);
784 				if (error)
785 					break;
786 			}
787 			if (mode != MODE_PARENT) {
788 				dir.d_fileno = udf_getid(&fid->icb);
789 				dir.d_type = DT_DIR;
790 				dir.d_name[0] = '.';
791 				dir.d_name[1] = '.';
792 				dir.d_name[2] = '\0';
793 				dir.d_namlen = 2;
794 				error = udf_uiodir(&uiodir, uio, PARENT_OFFSET);
795 			}
796 			mode = MODE_NORMAL;
797 		} else if (mode != MODE_NORMAL) {
798 			continue;
799 		} else {
800 			dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
801 			    &dir.d_name[0], fid->l_fi, ump);
802 			dir.d_fileno = udf_getid(&fid->icb);
803 			dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
804 			    DT_DIR : DT_UNKNOWN;
805 			error = udf_uiodir(&uiodir, uio, ds->this_off);
806 		}
807 		if (error) {
808 			/*
809 			 * udf_uiodir() indicates there isn't space for
810 			 * another entry by returning -1
811 			 */
812 			if (error == -1)
813 				error = 0;
814 			break;
815 		}
816 		last_off = ds->this_off;
817 	}
818 
819 	/* tell the calling layer whether we need to be called again */
820 	*ap->a_eofflag = uiodir.eofflag;
821 	uio->uio_offset = last_off;
822 
823 	if (!error)
824 		error = ds->error;
825 
826 	udf_closedir(ds);
827 	if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
828 		up->u_ump->um_start = up->u_ump->um_realstart;
829 		up->u_ump->um_len = up->u_ump->um_reallen;
830 	}
831 
832 	return (error);
833 }
834 
835 /* Are there any implementations out there that do soft-links? */
836 int
837 udf_readlink(void *v)
838 {
839 	return (EOPNOTSUPP);
840 }
841 
842 int
843 udf_strategy(void *v)
844 {
845 	struct vop_strategy_args *ap = v;
846 	struct buf *bp;
847 	struct vnode *vp;
848 	struct unode *up;
849 	int maxsize, s, error;
850 
851 	bp = ap->a_bp;
852 	vp = bp->b_vp;
853 	up = VTOU(vp);
854 
855 	/* cd9660 has this test reversed, but it seems more logical this way */
856 	if (bp->b_blkno != bp->b_lblkno) {
857 		/*
858 		 * Files that are embedded in the fentry don't translate well
859 		 * to a block number.  Reject.
860 		 */
861 		if (udf_bmap_internal(up, bp->b_lblkno * up->u_ump->um_bsize,
862 		    &bp->b_lblkno, &maxsize)) {
863 			clrbuf(bp);
864 			bp->b_blkno = -1;
865 		}
866 	} else {
867 		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
868 		if (error) {
869 			bp->b_error = error;
870 			bp->b_flags |= B_ERROR;
871 			s = splbio();
872 			biodone(bp);
873 			splx(s);
874 			return (error);
875 		}
876 
877 		if ((long)bp->b_blkno == -1)
878 			clrbuf(bp);
879 	}
880 
881 	if ((long)bp->b_blkno == -1) {
882 		s = splbio();
883 		biodone(bp);
884 		splx(s);
885 	} else {
886 		bp->b_dev = vp->v_rdev;
887 		(up->u_devvp->v_op->vop_strategy)(ap);
888 	}
889 
890 	return (0);
891 }
892 
893 int
894 udf_lock(void *v)
895 {
896 	struct vop_lock_args *ap = v;
897 
898 	struct vnode *vp = ap->a_vp;
899 
900 	return (lockmgr(&VTOU(vp)->u_lock, ap->a_flags, NULL));
901 }
902 
903 int
904 udf_unlock(void *v)
905 {
906 	struct vop_unlock_args *ap = v;
907 
908 	struct vnode *vp = ap->a_vp;
909 
910 	return (lockmgr(&VTOU(vp)->u_lock, ap->a_flags | LK_RELEASE, NULL));
911 }
912 
913 int
914 udf_islocked(void *v)
915 {
916 	struct vop_islocked_args *ap = v;
917 
918 	return (lockstatus(&VTOU(ap->a_vp)->u_lock));
919 }
920 
921 int
922 udf_print(void *v)
923 {
924 	struct vop_print_args *ap = v;
925 	struct vnode *vp = ap->a_vp;
926 	struct unode *up = VTOU(vp);
927 
928 	/*
929 	 * Complete the information given by vprint().
930 	 */
931 	printf("tag VT_UDF, hash id %u\n", up->u_ino);
932 #ifdef DIAGNOSTIC
933 	lockmgr_printinfo(&up->u_lock);
934 	printf("\n");
935 #endif
936 	return (0);
937 }
938 
939 int
940 udf_bmap(void *v)
941 {
942 	struct vop_bmap_args *ap = v;
943 	struct unode *up;
944 	uint32_t max_size;
945 	daddr_t lsector;
946 	int error;
947 
948 	up = VTOU(ap->a_vp);
949 
950 	if (ap->a_vpp != NULL)
951 		*ap->a_vpp = up->u_devvp;
952 	if (ap->a_bnp == NULL)
953 		return (0);
954 
955 	error = udf_bmap_internal(up, ap->a_bn * up->u_ump->um_bsize,
956 	    &lsector, &max_size);
957 	if (error)
958 		return (error);
959 
960 	/* Translate logical to physical sector number */
961 	*ap->a_bnp = lsector << (up->u_ump->um_bshift - DEV_BSHIFT);
962 
963 	/* Punt on read-ahead for now */
964 	if (ap->a_runp)
965 		*ap->a_runp = 0;
966 
967 	return (0);
968 }
969 
970 /*
971  * The all powerful VOP_LOOKUP().
972  */
973 int
974 udf_lookup(void *v)
975 {
976 	struct vop_lookup_args *ap = v;
977 	struct vnode *dvp;
978 	struct vnode *tdp = NULL;
979 	struct vnode **vpp = ap->a_vpp;
980 	struct unode *up;
981 	struct umount *ump;
982 	struct fileid_desc *fid = NULL;
983 	struct udf_dirstream *ds;
984 	struct proc *p;
985 	u_long nameiop;
986 	u_long flags;
987 	char *nameptr;
988 	long namelen;
989 	udfino_t id = 0;
990 	int offset, error = 0;
991 	int numdirpasses, fsize;
992 
993 	extern struct nchstats nchstats;
994 
995 	dvp = ap->a_dvp;
996 	up = VTOU(dvp);
997 	ump = up->u_ump;
998 	nameiop = ap->a_cnp->cn_nameiop;
999 	flags = ap->a_cnp->cn_flags;
1000 	nameptr = ap->a_cnp->cn_nameptr;
1001 	namelen = ap->a_cnp->cn_namelen;
1002 	fsize = letoh64(up->u_fentry->inf_len);
1003 	p = ap->a_cnp->cn_proc;
1004 	*vpp = NULL;
1005 
1006 	/*
1007 	 * Make sure the process can scan the requested directory.
1008 	 */
1009 	error = VOP_ACCESS(dvp, VEXEC, ap->a_cnp->cn_cred, p);
1010 	if (error)
1011 		return (error);
1012 
1013 	/*
1014 	 * Check if the (directory, name) tuple has been already cached.
1015 	 */
1016 	error = cache_lookup(dvp, vpp, ap->a_cnp);
1017 	if (error >= 0)
1018 		return (error);
1019 	else
1020 		error = 0;
1021 
1022 	/*
1023 	 * If dvp is what's being looked up, then return it.
1024 	 */
1025 	if (ap->a_cnp->cn_namelen == 1 && ap->a_cnp->cn_nameptr[0] == '.') {
1026 		vref(dvp);
1027 		*vpp = dvp;
1028 		return (0);
1029 	}
1030 
1031 	/*
1032 	 * If this is a LOOKUP and we've already partially searched through
1033 	 * the directory, pick up where we left off and flag that the
1034 	 * directory may need to be searched twice.  For a full description,
1035 	 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
1036 	 */
1037 	if (nameiop != LOOKUP || up->u_diroff == 0 || up->u_diroff > fsize) {
1038 		offset = 0;
1039 		numdirpasses = 1;
1040 	} else {
1041 		offset = up->u_diroff;
1042 		numdirpasses = 2;
1043 		nchstats.ncs_2passes++;
1044 	}
1045 
1046 	if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1047 		up->u_ump->um_start += up->u_ump->um_meta_start;
1048 		up->u_ump->um_len = up->u_ump->um_meta_len;
1049 	}
1050 lookloop:
1051 	ds = udf_opendir(up, offset, fsize, ump);
1052 
1053 	while ((fid = udf_getfid(ds)) != NULL) {
1054 		/* Check for a valid FID tag. */
1055 		if (udf_checktag(&fid->tag, TAGID_FID)) {
1056 			printf("udf_lookup: Invalid tag\n");
1057 			error = EIO;
1058 			break;
1059 		}
1060 
1061 		/* Is this a deleted file? */
1062 		if (fid->file_char & UDF_FILE_CHAR_DEL)
1063 			continue;
1064 
1065 		if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
1066 			if (flags & ISDOTDOT) {
1067 				id = udf_getid(&fid->icb);
1068 				break;
1069 			}
1070 		} else {
1071 			if (!(udf_cmpname(&fid->data[fid->l_iu],
1072 			    nameptr, fid->l_fi, namelen, ump))) {
1073 				id = udf_getid(&fid->icb);
1074 				break;
1075 			}
1076 		}
1077 	}
1078 
1079 	if (!error)
1080 		error = ds->error;
1081 
1082 	if (error) {
1083 		udf_closedir(ds);
1084 		if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1085 			up->u_ump->um_start = up->u_ump->um_realstart;
1086 			up->u_ump->um_len = up->u_ump->um_reallen;
1087 		}
1088 		return (error);
1089 	}
1090 
1091 	/* Did we have a match? */
1092 	if (id) {
1093 		error = udf_vget(ump->um_mountp, id, &tdp);
1094 		if (!error) {
1095 			/*
1096 			 * Remember where this entry was if it's the final
1097 			 * component.
1098 			 */
1099 			if ((flags & ISLASTCN) && nameiop == LOOKUP)
1100 				up->u_diroff = ds->offset + ds->off;
1101 			if (numdirpasses == 2)
1102 				nchstats.ncs_pass2++;
1103 			if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
1104 				ap->a_cnp->cn_flags |= PDIRUNLOCK;
1105 				VOP_UNLOCK(dvp, 0, p);
1106 			}
1107 
1108 			*vpp = tdp;
1109 		}
1110 	} else {
1111 		/* Name wasn't found on this pass.  Do another pass? */
1112 		if (numdirpasses == 2) {
1113 			numdirpasses--;
1114 			offset = 0;
1115 			udf_closedir(ds);
1116 			goto lookloop;
1117 		}
1118 
1119 		if ((flags & ISLASTCN) &&
1120 		    (nameiop == CREATE || nameiop == RENAME)) {
1121 			error = EROFS;
1122 		} else {
1123 			error = ENOENT;
1124 		}
1125 	}
1126 
1127 	/*
1128 	 * Cache the result of this lookup.
1129 	 */
1130 	if (flags & MAKEENTRY)
1131 		cache_enter(dvp, *vpp, ap->a_cnp);
1132 
1133 	udf_closedir(ds);
1134 	if (ISSET(up->u_ump->um_flags, UDF_MNT_USES_META)) {
1135 		up->u_ump->um_start = up->u_ump->um_realstart;
1136 		up->u_ump->um_len = up->u_ump->um_reallen;
1137 	}
1138 
1139 	return (error);
1140 }
1141 
1142 int
1143 udf_inactive(void *v)
1144 {
1145 	struct vop_inactive_args *ap = v;
1146 	struct vnode *vp = ap->a_vp;
1147 	struct proc *p = ap->a_p;
1148 
1149 	/*
1150 	 * No need to sync anything, so just unlock the vnode and return.
1151 	 */
1152 	VOP_UNLOCK(vp, 0, p);
1153 
1154 	return (0);
1155 }
1156 
1157 int
1158 udf_reclaim(void *v)
1159 {
1160 	struct vop_reclaim_args *ap = v;
1161 	struct vnode *vp;
1162 	struct unode *up;
1163 
1164 	vp = ap->a_vp;
1165 	up = VTOU(vp);
1166 
1167 	if (up != NULL) {
1168 		udf_hashrem(up);
1169 		if (up->u_devvp) {
1170 			vrele(up->u_devvp);
1171 			up->u_devvp = 0;
1172 		}
1173 
1174 		if (up->u_fentry != NULL)
1175 			free(up->u_fentry, M_UDFFENTRY, 0);
1176 
1177 		pool_put(&unode_pool, up);
1178 		vp->v_data = NULL;
1179 	}
1180 
1181 	return (0);
1182 }
1183 
1184 /*
1185  * Read the block and then set the data pointer to correspond with the
1186  * offset passed in.  Only read in at most 'size' bytes, and then set 'size'
1187  * to the number of bytes pointed to.  If 'size' is zero, try to read in a
1188  * whole extent.
1189  *
1190  * Note that *bp may be assigned error or not.
1191  *
1192  */
1193 int
1194 udf_readatoffset(struct unode *up, int *size, off_t offset,
1195     struct buf **bp, uint8_t **data)
1196 {
1197 	struct umount *ump;
1198 	struct extfile_entry *xfentry = NULL;
1199 	struct file_entry *fentry = NULL;
1200 	struct buf *bp1;
1201 	uint32_t max_size;
1202 	daddr_t sector;
1203 	int error;
1204 
1205 	ump = up->u_ump;
1206 
1207 	*bp = NULL;
1208 	error = udf_bmap_internal(up, offset, &sector, &max_size);
1209 	if (error == UDF_INVALID_BMAP) {
1210 		/*
1211 		 * This error means that the file *data* is stored in the
1212 		 * allocation descriptor field of the file entry.
1213 		 */
1214 		if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0) {
1215 			xfentry = up->u_fentry;
1216 			*data = &xfentry->data[letoh32(xfentry->l_ea)];
1217 			*size = letoh32(xfentry->l_ad);
1218 		} else {
1219 			fentry = (struct file_entry *)up->u_fentry;
1220 			*data = &fentry->data[letoh32(fentry->l_ea)];
1221 			*size = letoh32(fentry->l_ad);
1222 		}
1223 		return (0);
1224 	} else if (error != 0) {
1225 		return (error);
1226 	}
1227 
1228 	/* Adjust the size so that it is within range */
1229 	if (*size == 0 || *size > max_size)
1230 		*size = max_size;
1231 	*size = min(*size, MAXBSIZE);
1232 
1233 	if ((error = udf_readlblks(ump, sector, *size, bp))) {
1234 		printf("warning: udf_readlblks returned error %d\n", error);
1235 		/* note: *bp may be non-NULL */
1236 		return (error);
1237 	}
1238 
1239 	bp1 = *bp;
1240 	*data = (uint8_t *)&bp1->b_data[offset % ump->um_bsize];
1241 	return (0);
1242 }
1243 
1244 /*
1245  * Translate a file offset into a logical block and then into a physical
1246  * block.
1247  */
1248 int
1249 udf_bmap_internal(struct unode *up, off_t offset, daddr_t *sector,
1250     uint32_t *max_size)
1251 {
1252 	struct umount *ump;
1253 	struct extfile_entry *xfentry;
1254 	struct file_entry *fentry;
1255 	void *icb;
1256 	struct icb_tag *tag;
1257 	uint32_t icblen = 0;
1258 	daddr_t lsector;
1259 	int ad_offset, ad_num = 0;
1260 	int i, p_offset, l_ea, l_ad;
1261 
1262 	ump = up->u_ump;
1263 	xfentry = up->u_fentry;
1264 	fentry = (struct file_entry *)up->u_fentry;
1265 	tag = &fentry->icbtag;
1266 	if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) {
1267 		l_ea = letoh32(xfentry->l_ea);
1268 		l_ad = letoh32(xfentry->l_ad);
1269 	} else {
1270 		l_ea = letoh32(fentry->l_ea);
1271 		l_ad = letoh32(fentry->l_ad);
1272 	}
1273 
1274 	switch (letoh16(tag->strat_type)) {
1275 	case 4:
1276 		break;
1277 
1278 	case 4096:
1279 		printf("Cannot deal with strategy4096 yet!\n");
1280 		return (ENODEV);
1281 
1282 	default:
1283 		printf("Unknown strategy type %d\n", tag->strat_type);
1284 		return (ENODEV);
1285 	}
1286 
1287 	switch (letoh16(tag->flags) & 0x7) {
1288 	case 0:
1289 		/*
1290 		 * The allocation descriptor field is filled with short_ad's.
1291 		 * If the offset is beyond the current extent, look for the
1292 		 * next extent.
1293 		 */
1294 		do {
1295 			offset -= icblen;
1296 			ad_offset = sizeof(struct short_ad) * ad_num;
1297 			if (ad_offset > l_ad) {
1298 				printf("SFile offset out of bounds (%d > %d)\n",
1299 				    ad_offset, l_ad);
1300 				return (EINVAL);
1301 			}
1302 
1303 			if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0)
1304 				icb = GETICB(short_ad, xfentry, l_ea + ad_offset);
1305 			else
1306 				icb = GETICB(short_ad, fentry, l_ea + ad_offset);
1307 
1308 			icblen = GETICBLEN(short_ad, icb);
1309 			ad_num++;
1310 		} while(offset >= icblen);
1311 
1312 		lsector = (offset  >> ump->um_bshift) +
1313 		    letoh32(((struct short_ad *)(icb))->lb_num);
1314 
1315 		*max_size = GETICBLEN(short_ad, icb);
1316 
1317 		break;
1318 	case 1:
1319 		/*
1320 		 * The allocation descriptor field is filled with long_ad's
1321 		 * If the offset is beyond the current extent, look for the
1322 		 * next extent.
1323 		 */
1324 		do {
1325 			offset -= icblen;
1326 			ad_offset = sizeof(struct long_ad) * ad_num;
1327 			if (ad_offset > l_ad) {
1328 				printf("LFile offset out of bounds (%d > %d)\n",
1329 				    ad_offset, l_ad);
1330 				return (EINVAL);
1331 			}
1332 			if (udf_checktag(&up->u_fentry->tag, TAGID_EXTFENTRY) == 0)
1333 				icb = GETICB(long_ad, xfentry, l_ea + ad_offset);
1334 			else
1335 				icb = GETICB(long_ad, fentry, l_ea + ad_offset);
1336 			icblen = GETICBLEN(long_ad, icb);
1337 			ad_num++;
1338 		} while(offset >= icblen);
1339 
1340 		lsector = (offset >> ump->um_bshift) +
1341 		    letoh32(((struct long_ad *)(icb))->loc.lb_num);
1342 
1343 		*max_size = GETICBLEN(long_ad, icb);
1344 
1345 		break;
1346 	case 3:
1347 		/*
1348 		 * This type means that the file *data* is stored in the
1349 		 * allocation descriptor field of the file entry.
1350 		 */
1351 		*max_size = 0;
1352 		*sector = up->u_ino + ump->um_start;
1353 
1354 		return (UDF_INVALID_BMAP);
1355 	case 2:
1356 		/* DirectCD does not use extended_ad's */
1357 	default:
1358 		printf("Unsupported allocation descriptor %d\n",
1359 		       tag->flags & 0x7);
1360 		return (ENODEV);
1361 	}
1362 
1363 	*sector = lsector + ump->um_start;
1364 
1365 	/*
1366 	 * Check the sparing table.  Each entry represents the beginning of
1367 	 * a packet.
1368 	 */
1369 	if (ump->um_stbl != NULL) {
1370 		for (i = 0; i< ump->um_stbl_len; i++) {
1371 			p_offset =
1372 			    lsector - letoh32(ump->um_stbl->entries[i].org);
1373 			if ((p_offset < ump->um_psecs) && (p_offset >= 0)) {
1374 				*sector =
1375 				   letoh32(ump->um_stbl->entries[i].map) +
1376 				    p_offset;
1377 				break;
1378 			}
1379 		}
1380 	}
1381 
1382 	return (0);
1383 }
1384