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