xref: /dflybsd-src/sys/vfs/udf/udf_vnops.c (revision fc36a10bce8c5678d103e0498db849506d9dac68)
103998195SJoerg Sonnenberger /*-
203998195SJoerg Sonnenberger  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
303998195SJoerg Sonnenberger  * All rights reserved.
403998195SJoerg Sonnenberger  *
503998195SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
603998195SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
703998195SJoerg Sonnenberger  * are met:
803998195SJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
903998195SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
1003998195SJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
1103998195SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
1203998195SJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
1303998195SJoerg Sonnenberger  *
1403998195SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1503998195SJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1603998195SJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1703998195SJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1803998195SJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1903998195SJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2003998195SJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2103998195SJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2203998195SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2303998195SJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2403998195SJoerg Sonnenberger  * SUCH DAMAGE.
2503998195SJoerg Sonnenberger  *
2603998195SJoerg Sonnenberger  * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.33 2003/12/07 05:04:49 scottl Exp $
2703998195SJoerg Sonnenberger  */
2803998195SJoerg Sonnenberger 
2903998195SJoerg Sonnenberger /* udf_vnops.c */
3003998195SJoerg Sonnenberger /* Take care of the vnode side of things */
3103998195SJoerg Sonnenberger 
3203998195SJoerg Sonnenberger #include <sys/param.h>
3303998195SJoerg Sonnenberger #include <sys/systm.h>
3413dd34d8Szrj #include <sys/uio.h>
3503998195SJoerg Sonnenberger #include <sys/namei.h>
3603998195SJoerg Sonnenberger #include <sys/kernel.h>
3703998195SJoerg Sonnenberger #include <sys/malloc.h>
3803998195SJoerg Sonnenberger #include <sys/stat.h>
3903998195SJoerg Sonnenberger #include <sys/module.h>
4023a64a69SMatthew Dillon #include <sys/buf.h>
4103998195SJoerg Sonnenberger #include <sys/iconv.h>
4203998195SJoerg Sonnenberger #include <sys/mount.h>
4303998195SJoerg Sonnenberger #include <sys/vnode.h>
4403998195SJoerg Sonnenberger #include <sys/dirent.h>
4503998195SJoerg Sonnenberger #include <sys/queue.h>
4603998195SJoerg Sonnenberger #include <sys/unistd.h>
4703998195SJoerg Sonnenberger 
48f91a71ddSJoerg Sonnenberger #include <machine/inttypes.h>
49f91a71ddSJoerg Sonnenberger 
5023a64a69SMatthew Dillon #include <sys/buf2.h>
5123a64a69SMatthew Dillon 
5203998195SJoerg Sonnenberger #include <vfs/udf/ecma167-udf.h>
5303998195SJoerg Sonnenberger #include <vfs/udf/osta.h>
5403998195SJoerg Sonnenberger #include <vfs/udf/udf.h>
5503998195SJoerg Sonnenberger #include <vfs/udf/udf_mount.h>
5603998195SJoerg Sonnenberger 
5703998195SJoerg Sonnenberger static int udf_access(struct vop_access_args *);
5803998195SJoerg Sonnenberger static int udf_getattr(struct vop_getattr_args *);
5903998195SJoerg Sonnenberger static int udf_ioctl(struct vop_ioctl_args *);
6003998195SJoerg Sonnenberger static int udf_pathconf(struct vop_pathconf_args *);
6103998195SJoerg Sonnenberger static int udf_read(struct vop_read_args *);
6203998195SJoerg Sonnenberger static int udf_readdir(struct vop_readdir_args *);
6303998195SJoerg Sonnenberger static int udf_readlink(struct vop_readlink_args *ap);
6403998195SJoerg Sonnenberger static int udf_strategy(struct vop_strategy_args *);
6503998195SJoerg Sonnenberger static int udf_bmap(struct vop_bmap_args *);
66e62afb5fSMatthew Dillon static int udf_lookup(struct vop_old_lookup_args *);
6703998195SJoerg Sonnenberger static int udf_reclaim(struct vop_reclaim_args *);
6803998195SJoerg Sonnenberger static int udf_readatoffset(struct udf_node *, int *, int, struct buf **, uint8_t **);
6903998195SJoerg Sonnenberger static int udf_bmap_internal(struct udf_node *, uint32_t, daddr_t *, uint32_t *);
7003998195SJoerg Sonnenberger 
7166a1ddf5SMatthew Dillon struct vop_ops udf_vnode_vops = {
7266a1ddf5SMatthew Dillon 	.vop_default =		vop_defaultop,
7366a1ddf5SMatthew Dillon 	.vop_access =		udf_access,
7466a1ddf5SMatthew Dillon 	.vop_bmap =		udf_bmap,
7566a1ddf5SMatthew Dillon 	.vop_old_lookup =	udf_lookup,
7666a1ddf5SMatthew Dillon 	.vop_getattr =		udf_getattr,
7766a1ddf5SMatthew Dillon 	.vop_ioctl =		udf_ioctl,
7866a1ddf5SMatthew Dillon 	.vop_pathconf =		udf_pathconf,
7966a1ddf5SMatthew Dillon 	.vop_read =		udf_read,
8066a1ddf5SMatthew Dillon 	.vop_readdir =		udf_readdir,
8166a1ddf5SMatthew Dillon 	.vop_readlink =		udf_readlink,
8266a1ddf5SMatthew Dillon 	.vop_reclaim =		udf_reclaim,
8366a1ddf5SMatthew Dillon 	.vop_strategy =		udf_strategy
8403998195SJoerg Sonnenberger };
8503998195SJoerg Sonnenberger 
8603998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
8703998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
8803998195SJoerg Sonnenberger 
8903998195SJoerg Sonnenberger #define UDF_INVALID_BMAP	-1
9003998195SJoerg Sonnenberger 
9103998195SJoerg Sonnenberger /* Look up a udf_node based on the ino_t passed in and return it's vnode */
9203998195SJoerg Sonnenberger int
udf_hashlookup(struct udf_mnt * udfmp,ino_t id,struct vnode ** vpp)9303998195SJoerg Sonnenberger udf_hashlookup(struct udf_mnt *udfmp, ino_t id, struct vnode **vpp)
9403998195SJoerg Sonnenberger {
9503998195SJoerg Sonnenberger 	struct udf_node *node;
9603998195SJoerg Sonnenberger 	struct udf_hash_lh *lh;
975fd012e0SMatthew Dillon 	struct vnode *vp;
9803998195SJoerg Sonnenberger 
9903998195SJoerg Sonnenberger 	*vpp = NULL;
10003998195SJoerg Sonnenberger 
1013b998fa9SMatthew Dillon 	lwkt_gettoken(&udfmp->hash_token);
10203998195SJoerg Sonnenberger loop:
10303998195SJoerg Sonnenberger 	lh = &udfmp->hashtbl[id % udfmp->hashsz];
1045fd012e0SMatthew Dillon 	if (lh == NULL) {
1053b998fa9SMatthew Dillon 		lwkt_reltoken(&udfmp->hash_token);
10603998195SJoerg Sonnenberger 		return(ENOENT);
1075fd012e0SMatthew Dillon 	}
10803998195SJoerg Sonnenberger 	LIST_FOREACH(node, lh, le) {
10903998195SJoerg Sonnenberger 		if (node->hash_id != id)
11003998195SJoerg Sonnenberger 			continue;
1115fd012e0SMatthew Dillon 		vp = node->i_vnode;
11287de5057SMatthew Dillon 		if (vget(vp, LK_EXCLUSIVE))
1135fd012e0SMatthew Dillon 			goto loop;
11403998195SJoerg Sonnenberger 		/*
11503998195SJoerg Sonnenberger 		 * We must check to see if the inode has been ripped
11603998195SJoerg Sonnenberger 		 * out from under us after blocking.
11703998195SJoerg Sonnenberger 		 */
11803998195SJoerg Sonnenberger 		lh = &udfmp->hashtbl[id % udfmp->hashsz];
1193446c007SMatthew Dillon 		LIST_FOREACH(node, lh, le) {
12003998195SJoerg Sonnenberger 			if (node->hash_id == id)
12103998195SJoerg Sonnenberger 				break;
1223446c007SMatthew Dillon 		}
1235fd012e0SMatthew Dillon 		if (node == NULL || vp != node->i_vnode) {
1245fd012e0SMatthew Dillon 			vput(vp);
12503998195SJoerg Sonnenberger 			goto loop;
12603998195SJoerg Sonnenberger 		}
1273b998fa9SMatthew Dillon 		lwkt_reltoken(&udfmp->hash_token);
1285fd012e0SMatthew Dillon 		*vpp = vp;
12903998195SJoerg Sonnenberger 		return(0);
13003998195SJoerg Sonnenberger 	}
13103998195SJoerg Sonnenberger 
1323b998fa9SMatthew Dillon 	lwkt_reltoken(&udfmp->hash_token);
13303998195SJoerg Sonnenberger 	return(0);
13403998195SJoerg Sonnenberger }
13503998195SJoerg Sonnenberger 
13603998195SJoerg Sonnenberger int
udf_hashins(struct udf_node * node)13703998195SJoerg Sonnenberger udf_hashins(struct udf_node *node)
13803998195SJoerg Sonnenberger {
13903998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
14003998195SJoerg Sonnenberger 	struct udf_hash_lh *lh;
14103998195SJoerg Sonnenberger 
14203998195SJoerg Sonnenberger 	udfmp = node->udfmp;
14303998195SJoerg Sonnenberger 
1443b998fa9SMatthew Dillon 	lwkt_gettoken(&udfmp->hash_token);
14503998195SJoerg Sonnenberger 	lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz];
14603998195SJoerg Sonnenberger 	LIST_INSERT_HEAD(lh, node, le);
1473b998fa9SMatthew Dillon 	lwkt_reltoken(&udfmp->hash_token);
14803998195SJoerg Sonnenberger 
14903998195SJoerg Sonnenberger 	return(0);
15003998195SJoerg Sonnenberger }
15103998195SJoerg Sonnenberger 
15203998195SJoerg Sonnenberger int
udf_hashrem(struct udf_node * node)15303998195SJoerg Sonnenberger udf_hashrem(struct udf_node *node)
15403998195SJoerg Sonnenberger {
15503998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
15603998195SJoerg Sonnenberger 	struct udf_hash_lh *lh;
15703998195SJoerg Sonnenberger 
15803998195SJoerg Sonnenberger 	udfmp = node->udfmp;
15903998195SJoerg Sonnenberger 
1603b998fa9SMatthew Dillon 	lwkt_gettoken(&udfmp->hash_token);
16103998195SJoerg Sonnenberger 	lh = &udfmp->hashtbl[node->hash_id % udfmp->hashsz];
16203998195SJoerg Sonnenberger 	if (lh == NULL)
163ed20d0e3SSascha Wildner 		panic("hash entry is NULL, node->hash_id= %"PRId64, node->hash_id);
16403998195SJoerg Sonnenberger 	LIST_REMOVE(node, le);
1653b998fa9SMatthew Dillon 	lwkt_reltoken(&udfmp->hash_token);
16603998195SJoerg Sonnenberger 
16703998195SJoerg Sonnenberger 	return(0);
16803998195SJoerg Sonnenberger }
16903998195SJoerg Sonnenberger 
17003998195SJoerg Sonnenberger int
udf_allocv(struct mount * mp,struct vnode ** vpp)17103998195SJoerg Sonnenberger udf_allocv(struct mount *mp, struct vnode **vpp)
17203998195SJoerg Sonnenberger {
17303998195SJoerg Sonnenberger 	int error;
17403998195SJoerg Sonnenberger 	struct vnode *vp;
17503998195SJoerg Sonnenberger 
1766ddb7618SMatthew Dillon 	error = getnewvnode(VT_UDF, mp, &vp, 0, 0);
17703998195SJoerg Sonnenberger 	if (error) {
178086c1d7eSSascha Wildner 		kprintf("udf_allocv: failed to allocate new vnode\n");
17903998195SJoerg Sonnenberger 		return(error);
18003998195SJoerg Sonnenberger 	}
181*fc36a10bSMatthew Dillon 	vx_downgrade(vp);
18203998195SJoerg Sonnenberger 	*vpp = vp;
18303998195SJoerg Sonnenberger 	return(0);
18403998195SJoerg Sonnenberger }
18503998195SJoerg Sonnenberger 
18603998195SJoerg Sonnenberger /* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
18703998195SJoerg Sonnenberger static mode_t
udf_permtomode(struct udf_node * node)18803998195SJoerg Sonnenberger udf_permtomode(struct udf_node *node)
18903998195SJoerg Sonnenberger {
19003998195SJoerg Sonnenberger 	uint32_t perm;
19103998195SJoerg Sonnenberger 	uint32_t flags;
19203998195SJoerg Sonnenberger 	mode_t mode;
19303998195SJoerg Sonnenberger 
19403998195SJoerg Sonnenberger 	perm = node->fentry->perm;
19503998195SJoerg Sonnenberger 	flags = node->fentry->icbtag.flags;
19603998195SJoerg Sonnenberger 
19703998195SJoerg Sonnenberger 	mode = perm & UDF_FENTRY_PERM_USER_MASK;
19803998195SJoerg Sonnenberger 	mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
19903998195SJoerg Sonnenberger 	mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
20003998195SJoerg Sonnenberger 	mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
20103998195SJoerg Sonnenberger 	mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
20203998195SJoerg Sonnenberger 	mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
20303998195SJoerg Sonnenberger 
20403998195SJoerg Sonnenberger 	return(mode);
20503998195SJoerg Sonnenberger }
20603998195SJoerg Sonnenberger 
20703998195SJoerg Sonnenberger static int
udf_access(struct vop_access_args * a)20803998195SJoerg Sonnenberger udf_access(struct vop_access_args *a)
20903998195SJoerg Sonnenberger {
21003998195SJoerg Sonnenberger 	struct vnode *vp;
21103998195SJoerg Sonnenberger 	struct udf_node *node;
21203998195SJoerg Sonnenberger 
21303998195SJoerg Sonnenberger 	vp = a->a_vp;
21403998195SJoerg Sonnenberger 	node = VTON(vp);
2157ca841ccSNicolas Thery 	KKASSERT(vp->v_mount->mnt_flag & MNT_RDONLY);
2167ca841ccSNicolas Thery 	return (vop_helper_access(a, node->fentry->uid, node->fentry->gid,
2177ca841ccSNicolas Thery 				  udf_permtomode(node), 0));
21803998195SJoerg Sonnenberger }
21903998195SJoerg Sonnenberger 
22003998195SJoerg Sonnenberger static int mon_lens[2][12] = {
22103998195SJoerg Sonnenberger 	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
22203998195SJoerg Sonnenberger 	{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
22303998195SJoerg Sonnenberger };
22403998195SJoerg Sonnenberger 
22503998195SJoerg Sonnenberger static int
udf_isaleapyear(int year)22603998195SJoerg Sonnenberger udf_isaleapyear(int year)
22703998195SJoerg Sonnenberger {
22803998195SJoerg Sonnenberger 	int i;
22903998195SJoerg Sonnenberger 
23003998195SJoerg Sonnenberger 	i = (year % 4) ? 0 : 1;
23103998195SJoerg Sonnenberger 	i &= (year % 100) ? 1 : 0;
23203998195SJoerg Sonnenberger 	i |= (year % 400) ? 0 : 1;
23303998195SJoerg Sonnenberger 
23403998195SJoerg Sonnenberger 	return(i);
23503998195SJoerg Sonnenberger }
23603998195SJoerg Sonnenberger 
23703998195SJoerg Sonnenberger /*
23803998195SJoerg Sonnenberger  * XXX This is just a rough hack.  Daylight savings isn't calculated and tv_nsec
23903998195SJoerg Sonnenberger  * is ignored.
24003998195SJoerg Sonnenberger  * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
24103998195SJoerg Sonnenberger  */
24203998195SJoerg Sonnenberger static void
udf_timetotimespec(struct timestamp * time,struct timespec * t)24303998195SJoerg Sonnenberger udf_timetotimespec(struct timestamp *time, struct timespec *t)
24403998195SJoerg Sonnenberger {
24503998195SJoerg Sonnenberger 	int i, lpyear, daysinyear;
24603998195SJoerg Sonnenberger 	union {
24703998195SJoerg Sonnenberger 		uint16_t	u_tz_offset;
24803998195SJoerg Sonnenberger 		int16_t		s_tz_offset;
24903998195SJoerg Sonnenberger 	} tz;
25003998195SJoerg Sonnenberger 
25103998195SJoerg Sonnenberger 	t->tv_nsec = 0;
25203998195SJoerg Sonnenberger 
25303998195SJoerg Sonnenberger 	/* DirectCD seems to like using bogus year values */
25403998195SJoerg Sonnenberger 	if (time->year < 1970) {
25503998195SJoerg Sonnenberger 		t->tv_sec = 0;
25603998195SJoerg Sonnenberger 		return;
25703998195SJoerg Sonnenberger 	}
25803998195SJoerg Sonnenberger 
25903998195SJoerg Sonnenberger 	/* Calculate the time and day */
26003998195SJoerg Sonnenberger 	t->tv_sec = time->second;
26103998195SJoerg Sonnenberger 	t->tv_sec += time->minute * 60;
26203998195SJoerg Sonnenberger 	t->tv_sec += time->hour * 3600;
26303998195SJoerg Sonnenberger 	t->tv_sec += time->day * 3600 * 24;
26403998195SJoerg Sonnenberger 
26503998195SJoerg Sonnenberger 	/* Calclulate the month */
26603998195SJoerg Sonnenberger 	lpyear = udf_isaleapyear(time->year);
26703998195SJoerg Sonnenberger 	for (i = 1; i < time->month; i++)
26803998195SJoerg Sonnenberger 		t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
26903998195SJoerg Sonnenberger 
27003998195SJoerg Sonnenberger 	/* Speed up the calculation */
27103998195SJoerg Sonnenberger 	if (time->year > 1979)
27203998195SJoerg Sonnenberger 		t->tv_sec += 315532800;
27303998195SJoerg Sonnenberger 	if (time->year > 1989)
27403998195SJoerg Sonnenberger 		t->tv_sec += 315619200;
27503998195SJoerg Sonnenberger 	if (time->year > 1999)
27603998195SJoerg Sonnenberger 		t->tv_sec += 315532800;
27703998195SJoerg Sonnenberger 	for (i = 2000; i < time->year; i++) {
27803998195SJoerg Sonnenberger 		daysinyear = udf_isaleapyear(i) + 365 ;
27903998195SJoerg Sonnenberger 		t->tv_sec += daysinyear * 3600 * 24;
28003998195SJoerg Sonnenberger 	}
28103998195SJoerg Sonnenberger 
28203998195SJoerg Sonnenberger 	/*
28303998195SJoerg Sonnenberger 	 * Calculate the time zone.  The timezone is 12 bit signed 2's
28403998195SJoerg Sonnenberger 	 * compliment, so we gotta do some extra magic to handle it right.
28503998195SJoerg Sonnenberger 	 */
28603998195SJoerg Sonnenberger 	tz.u_tz_offset = time->type_tz;
28703998195SJoerg Sonnenberger 	tz.u_tz_offset &= 0x0fff;
28803998195SJoerg Sonnenberger 	if (tz.u_tz_offset & 0x0800)
28903998195SJoerg Sonnenberger 		tz.u_tz_offset |= 0xf000;	/* extend the sign to 16 bits */
29003998195SJoerg Sonnenberger 	if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
29103998195SJoerg Sonnenberger 		t->tv_sec -= tz.s_tz_offset * 60;
29203998195SJoerg Sonnenberger 
29303998195SJoerg Sonnenberger 	return;
29403998195SJoerg Sonnenberger }
29503998195SJoerg Sonnenberger 
29603998195SJoerg Sonnenberger static int
udf_getattr(struct vop_getattr_args * a)29703998195SJoerg Sonnenberger udf_getattr(struct vop_getattr_args *a)
29803998195SJoerg Sonnenberger {
29903998195SJoerg Sonnenberger 	struct vnode *vp;
30003998195SJoerg Sonnenberger 	struct udf_node *node;
30103998195SJoerg Sonnenberger 	struct vattr *vap;
30203998195SJoerg Sonnenberger 	struct file_entry *fentry;
30303998195SJoerg Sonnenberger 
30403998195SJoerg Sonnenberger 	vp = a->a_vp;
30503998195SJoerg Sonnenberger 	vap = a->a_vap;
30603998195SJoerg Sonnenberger 	node = VTON(vp);
30703998195SJoerg Sonnenberger 	fentry = node->fentry;
30803998195SJoerg Sonnenberger 
3092ac7d105SSascha Wildner 	vap->va_fsid = devid_from_dev(node->i_dev);
31003998195SJoerg Sonnenberger 	vap->va_fileid = node->hash_id;
31103998195SJoerg Sonnenberger 	vap->va_mode = udf_permtomode(node);
31203998195SJoerg Sonnenberger 	vap->va_nlink = fentry->link_cnt;
31303998195SJoerg Sonnenberger 	/*
31403998195SJoerg Sonnenberger 	 * XXX The spec says that -1 is valid for uid/gid and indicates an
31503998195SJoerg Sonnenberger 	 * invalid uid/gid.  How should this be represented?
31603998195SJoerg Sonnenberger 	 */
31703998195SJoerg Sonnenberger 	vap->va_uid = (fentry->uid == 0xffffffff) ? 0 : fentry->uid;
31803998195SJoerg Sonnenberger 	vap->va_gid = (fentry->gid == 0xffffffff) ? 0 : fentry->gid;
31903998195SJoerg Sonnenberger 	udf_timetotimespec(&fentry->atime, &vap->va_atime);
32003998195SJoerg Sonnenberger 	udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
32103998195SJoerg Sonnenberger 	vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
3220e9b9130SMatthew Dillon 	vap->va_rmajor = VNOVAL;
3230e9b9130SMatthew Dillon 	vap->va_rminor = VNOVAL;
32403998195SJoerg Sonnenberger 	if (vp->v_type & VDIR) {
32503998195SJoerg Sonnenberger 		/*
32603998195SJoerg Sonnenberger 		 * Directories that are recorded within their ICB will show
32703998195SJoerg Sonnenberger 		 * as having 0 blocks recorded.  Since tradition dictates
32803998195SJoerg Sonnenberger 		 * that directories consume at least one logical block,
32903998195SJoerg Sonnenberger 		 * make it appear so.
33003998195SJoerg Sonnenberger 		 */
33103998195SJoerg Sonnenberger 		if (fentry->logblks_rec != 0)
33203998195SJoerg Sonnenberger 			vap->va_size = fentry->logblks_rec * node->udfmp->bsize;
33303998195SJoerg Sonnenberger 		else
33403998195SJoerg Sonnenberger 			vap->va_size = node->udfmp->bsize;
33503998195SJoerg Sonnenberger 	} else
33603998195SJoerg Sonnenberger 		vap->va_size = fentry->inf_len;
33703998195SJoerg Sonnenberger 	vap->va_flags = 0;
33803998195SJoerg Sonnenberger 	vap->va_gen = 1;
33903998195SJoerg Sonnenberger 	vap->va_blocksize = node->udfmp->bsize;
34003998195SJoerg Sonnenberger 	vap->va_bytes = fentry->inf_len;
34103998195SJoerg Sonnenberger 	vap->va_type = vp->v_type;
34203998195SJoerg Sonnenberger 	vap->va_filerev = 0; /* XXX */
34303998195SJoerg Sonnenberger 	return(0);
34403998195SJoerg Sonnenberger }
34503998195SJoerg Sonnenberger 
34603998195SJoerg Sonnenberger /*
34703998195SJoerg Sonnenberger  * File specific ioctls.  DeCSS candidate?
34803998195SJoerg Sonnenberger  */
34903998195SJoerg Sonnenberger static int
udf_ioctl(struct vop_ioctl_args * a)35003998195SJoerg Sonnenberger udf_ioctl(struct vop_ioctl_args *a)
35103998195SJoerg Sonnenberger {
352086c1d7eSSascha Wildner 	kprintf("%s called\n", __func__);
35303998195SJoerg Sonnenberger 	return(ENOTTY);
35403998195SJoerg Sonnenberger }
35503998195SJoerg Sonnenberger 
35603998195SJoerg Sonnenberger /*
35703998195SJoerg Sonnenberger  * I'm not sure that this has much value in a read-only filesystem, but
35803998195SJoerg Sonnenberger  * cd9660 has it too.
35903998195SJoerg Sonnenberger  */
36003998195SJoerg Sonnenberger static int
udf_pathconf(struct vop_pathconf_args * a)36103998195SJoerg Sonnenberger udf_pathconf(struct vop_pathconf_args *a)
36203998195SJoerg Sonnenberger {
36303998195SJoerg Sonnenberger 
36403998195SJoerg Sonnenberger 	switch (a->a_name) {
36503998195SJoerg Sonnenberger 	case _PC_LINK_MAX:
36603998195SJoerg Sonnenberger 		*a->a_retval = 65535;
36703998195SJoerg Sonnenberger 		return(0);
36803998195SJoerg Sonnenberger 	case _PC_NAME_MAX:
36903998195SJoerg Sonnenberger 		*a->a_retval = NAME_MAX;
37003998195SJoerg Sonnenberger 		return(0);
37103998195SJoerg Sonnenberger 	case _PC_PATH_MAX:
37203998195SJoerg Sonnenberger 		*a->a_retval = PATH_MAX;
37303998195SJoerg Sonnenberger 		return(0);
37403998195SJoerg Sonnenberger 	case _PC_NO_TRUNC:
37503998195SJoerg Sonnenberger 		*a->a_retval = 1;
37603998195SJoerg Sonnenberger 		return(0);
37703998195SJoerg Sonnenberger 	default:
37803998195SJoerg Sonnenberger 		return(EINVAL);
37903998195SJoerg Sonnenberger 	}
38003998195SJoerg Sonnenberger }
38103998195SJoerg Sonnenberger 
38203998195SJoerg Sonnenberger static int
udf_read(struct vop_read_args * a)38303998195SJoerg Sonnenberger udf_read(struct vop_read_args *a)
38403998195SJoerg Sonnenberger {
38503998195SJoerg Sonnenberger 	struct vnode *vp = a->a_vp;
38603998195SJoerg Sonnenberger 	struct uio *uio = a->a_uio;
38703998195SJoerg Sonnenberger 	struct udf_node *node = VTON(vp);
38803998195SJoerg Sonnenberger 	struct buf *bp;
38903998195SJoerg Sonnenberger 	uint8_t *data;
39003998195SJoerg Sonnenberger 	int error = 0;
39103998195SJoerg Sonnenberger 	int size, fsize, offset;
39203998195SJoerg Sonnenberger 
39303998195SJoerg Sonnenberger 	if (uio->uio_offset < 0)
39403998195SJoerg Sonnenberger 		return(EINVAL);
39503998195SJoerg Sonnenberger 
39603998195SJoerg Sonnenberger 	fsize = node->fentry->inf_len;
39703998195SJoerg Sonnenberger 
39803998195SJoerg Sonnenberger 	while (uio->uio_offset < fsize && uio->uio_resid > 0) {
39903998195SJoerg Sonnenberger 		offset = uio->uio_offset;
40003998195SJoerg Sonnenberger 		size = uio->uio_resid;
40103998195SJoerg Sonnenberger 		error = udf_readatoffset(node, &size, offset, &bp, &data);
402ffaa7d78SMatthew Dillon 		if (error == 0)
40303998195SJoerg Sonnenberger 			error = uiomove(data, size, uio);
40403998195SJoerg Sonnenberger 		if (bp != NULL)
40503998195SJoerg Sonnenberger 			brelse(bp);
40603998195SJoerg Sonnenberger 		if (error)
40703998195SJoerg Sonnenberger 			break;
4084a77c3abSDavid Rhodus 	}
40903998195SJoerg Sonnenberger 
41003998195SJoerg Sonnenberger 	return(error);
41103998195SJoerg Sonnenberger }
41203998195SJoerg Sonnenberger 
41303998195SJoerg Sonnenberger /*
41403998195SJoerg Sonnenberger  * Call the OSTA routines to translate the name from a CS0 dstring to a
41503998195SJoerg Sonnenberger  * 16-bit Unicode String.  Hooks need to be placed in here to translate from
41603998195SJoerg Sonnenberger  * Unicode to the encoding that the kernel/user expects.  Return the length
41703998195SJoerg Sonnenberger  * of the translated string.
41803998195SJoerg Sonnenberger  */
41903998195SJoerg Sonnenberger static int
udf_transname(char * cs0string,char * destname,int len,struct udf_mnt * udfmp)42003998195SJoerg Sonnenberger udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
42103998195SJoerg Sonnenberger {
42203998195SJoerg Sonnenberger 	unicode_t *transname;
42303998195SJoerg Sonnenberger 	int i, unilen = 0, destlen;
42403998195SJoerg Sonnenberger 
42503998195SJoerg Sonnenberger 	/* Convert 16-bit Unicode to destname */
42603998195SJoerg Sonnenberger 	/* allocate a buffer big enough to hold an 8->16 bit expansion */
427efda3bd0SMatthew Dillon 	transname = kmalloc(NAME_MAX * sizeof(unicode_t), M_TEMP, M_WAITOK | M_ZERO);
42803998195SJoerg Sonnenberger 
42903998195SJoerg Sonnenberger 	if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) {
430086c1d7eSSascha Wildner 		kprintf("udf: Unicode translation failed\n");
431efda3bd0SMatthew Dillon 		kfree(transname, M_TEMP);
43203998195SJoerg Sonnenberger 		return(0);
43303998195SJoerg Sonnenberger 	}
43403998195SJoerg Sonnenberger 
43503998195SJoerg Sonnenberger 	for (i = 0; i < unilen ; i++)
43603998195SJoerg Sonnenberger 		if (transname[i] & 0xff00)
43703998195SJoerg Sonnenberger 			destname[i] = '.';	/* Fudge the 16bit chars */
43803998195SJoerg Sonnenberger 		else
43903998195SJoerg Sonnenberger 			destname[i] = transname[i] & 0xff;
440efda3bd0SMatthew Dillon 	kfree(transname, M_TEMP);
44103998195SJoerg Sonnenberger 	destname[unilen] = 0;
44203998195SJoerg Sonnenberger 	destlen = unilen;
44303998195SJoerg Sonnenberger 
44403998195SJoerg Sonnenberger 	return(destlen);
44503998195SJoerg Sonnenberger }
44603998195SJoerg Sonnenberger 
44703998195SJoerg Sonnenberger /*
44803998195SJoerg Sonnenberger  * Compare a CS0 dstring with a name passed in from the VFS layer.  Return
44903998195SJoerg Sonnenberger  * 0 on a successful match, nonzero therwise.  Unicode work may need to be done
45003998195SJoerg Sonnenberger  * here also.
45103998195SJoerg Sonnenberger  */
45203998195SJoerg Sonnenberger static int
udf_cmpname(char * cs0string,char * cmpname,int cs0len,int cmplen,struct udf_mnt * udfmp)45303998195SJoerg Sonnenberger udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
45403998195SJoerg Sonnenberger {
45503998195SJoerg Sonnenberger 	char *transname;
45603998195SJoerg Sonnenberger 	int error = 0;
45703998195SJoerg Sonnenberger 
45803998195SJoerg Sonnenberger 	/* This is overkill, but not worth creating a new zone */
45903998195SJoerg Sonnenberger 
460efda3bd0SMatthew Dillon 	transname = kmalloc(NAME_MAX * sizeof(unicode_t), M_TEMP,
46103998195SJoerg Sonnenberger 			   M_WAITOK | M_ZERO);
46203998195SJoerg Sonnenberger 
46303998195SJoerg Sonnenberger 	cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
46403998195SJoerg Sonnenberger 
46503998195SJoerg Sonnenberger 	/* Easy check.  If they aren't the same length, they aren't equal */
46603998195SJoerg Sonnenberger 	if ((cs0len == 0) || (cs0len != cmplen))
46703998195SJoerg Sonnenberger 		error = -1;
46803998195SJoerg Sonnenberger 	else
46903998195SJoerg Sonnenberger 		error = bcmp(transname, cmpname, cmplen);
47003998195SJoerg Sonnenberger 
471efda3bd0SMatthew Dillon 	kfree(transname, M_TEMP);
47203998195SJoerg Sonnenberger 	return(error);
47303998195SJoerg Sonnenberger }
47403998195SJoerg Sonnenberger 
47503998195SJoerg Sonnenberger struct udf_uiodir {
47603998195SJoerg Sonnenberger 	struct dirent *dirent;
47784009d92SMatthew Dillon 	off_t *cookies;
47803998195SJoerg Sonnenberger 	int ncookies;
47903998195SJoerg Sonnenberger 	int acookies;
48003998195SJoerg Sonnenberger 	int eofflag;
48103998195SJoerg Sonnenberger };
48203998195SJoerg Sonnenberger 
48303998195SJoerg Sonnenberger static struct udf_dirstream *
udf_opendir(struct udf_node * node,int offset,int fsize,struct udf_mnt * udfmp)48403998195SJoerg Sonnenberger udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
48503998195SJoerg Sonnenberger {
48603998195SJoerg Sonnenberger 	struct udf_dirstream *ds;
48703998195SJoerg Sonnenberger 
488efda3bd0SMatthew Dillon 	ds = kmalloc(sizeof(*ds), M_UDFDS, M_WAITOK | M_ZERO);
48903998195SJoerg Sonnenberger 
49003998195SJoerg Sonnenberger 	ds->node = node;
49103998195SJoerg Sonnenberger 	ds->offset = offset;
49203998195SJoerg Sonnenberger 	ds->udfmp = udfmp;
49303998195SJoerg Sonnenberger 	ds->fsize = fsize;
49403998195SJoerg Sonnenberger 
49503998195SJoerg Sonnenberger 	return(ds);
49603998195SJoerg Sonnenberger }
49703998195SJoerg Sonnenberger 
49803998195SJoerg Sonnenberger static struct fileid_desc *
udf_getfid(struct udf_dirstream * ds)49903998195SJoerg Sonnenberger udf_getfid(struct udf_dirstream *ds)
50003998195SJoerg Sonnenberger {
50103998195SJoerg Sonnenberger 	struct fileid_desc *fid;
50203998195SJoerg Sonnenberger 	int error, frag_size = 0, total_fid_size;
50303998195SJoerg Sonnenberger 
50403998195SJoerg Sonnenberger 	/* End of directory? */
50503998195SJoerg Sonnenberger 	if (ds->offset + ds->off >= ds->fsize) {
50603998195SJoerg Sonnenberger 		ds->error = 0;
50703998195SJoerg Sonnenberger 		return(NULL);
50803998195SJoerg Sonnenberger 	}
50903998195SJoerg Sonnenberger 
51003998195SJoerg Sonnenberger 	/* Grab the first extent of the directory */
51103998195SJoerg Sonnenberger 	if (ds->off == 0) {
51203998195SJoerg Sonnenberger 		ds->size = 0;
513ffaa7d78SMatthew Dillon 		if (ds->bp != NULL)
514ffaa7d78SMatthew Dillon 			brelse(ds->bp);
51503998195SJoerg Sonnenberger 		error = udf_readatoffset(ds->node, &ds->size, ds->offset,
51603998195SJoerg Sonnenberger 		    &ds->bp, &ds->data);
51703998195SJoerg Sonnenberger 		if (error) {
51803998195SJoerg Sonnenberger 			ds->error = error;
51903998195SJoerg Sonnenberger 			return(NULL);
52003998195SJoerg Sonnenberger 		}
52103998195SJoerg Sonnenberger 	}
52203998195SJoerg Sonnenberger 
52303998195SJoerg Sonnenberger 	/*
52403998195SJoerg Sonnenberger 	 * Clean up from a previous fragmented FID.
52503998195SJoerg Sonnenberger 	 * XXX Is this the right place for this?
52603998195SJoerg Sonnenberger 	 */
52703998195SJoerg Sonnenberger 	if (ds->fid_fragment && ds->buf != NULL) {
52803998195SJoerg Sonnenberger 		ds->fid_fragment = 0;
529efda3bd0SMatthew Dillon 		kfree(ds->buf, M_UDFFID);
53003998195SJoerg Sonnenberger 	}
53103998195SJoerg Sonnenberger 
53203998195SJoerg Sonnenberger 	fid = (struct fileid_desc*)&ds->data[ds->off];
53303998195SJoerg Sonnenberger 
53403998195SJoerg Sonnenberger 	/*
53503998195SJoerg Sonnenberger 	 * Check to see if the fid is fragmented. The first test
53603998195SJoerg Sonnenberger 	 * ensures that we don't wander off the end of the buffer
53703998195SJoerg Sonnenberger 	 * looking for the l_iu and l_fi fields.
53803998195SJoerg Sonnenberger 	 */
53903998195SJoerg Sonnenberger 	if (ds->off + UDF_FID_SIZE > ds->size ||
54003998195SJoerg Sonnenberger 	    ds->off + fid->l_iu + fid->l_fi + UDF_FID_SIZE > ds->size) {
54103998195SJoerg Sonnenberger 
54203998195SJoerg Sonnenberger 		/* Copy what we have of the fid into a buffer */
54303998195SJoerg Sonnenberger 		frag_size = ds->size - ds->off;
54403998195SJoerg Sonnenberger 		if (frag_size >= ds->udfmp->bsize) {
545086c1d7eSSascha Wildner 			kprintf("udf: invalid FID fragment\n");
54603998195SJoerg Sonnenberger 			ds->error = EINVAL;
54703998195SJoerg Sonnenberger 			return(NULL);
54803998195SJoerg Sonnenberger 		}
54903998195SJoerg Sonnenberger 
55003998195SJoerg Sonnenberger 		/*
55103998195SJoerg Sonnenberger 		 * File ID descriptors can only be at most one
55203998195SJoerg Sonnenberger 		 * logical sector in size.
55303998195SJoerg Sonnenberger 		 */
554efda3bd0SMatthew Dillon 		ds->buf = kmalloc(ds->udfmp->bsize, M_UDFFID, M_WAITOK | M_ZERO);
55503998195SJoerg Sonnenberger 		bcopy(fid, ds->buf, frag_size);
55603998195SJoerg Sonnenberger 
55703998195SJoerg Sonnenberger 		/* Reduce all of the casting magic */
55803998195SJoerg Sonnenberger 		fid = (struct fileid_desc*)ds->buf;
55903998195SJoerg Sonnenberger 
56003998195SJoerg Sonnenberger 		if (ds->bp != NULL)
56103998195SJoerg Sonnenberger 			brelse(ds->bp);
56203998195SJoerg Sonnenberger 
56303998195SJoerg Sonnenberger 		/* Fetch the next allocation */
56403998195SJoerg Sonnenberger 		ds->offset += ds->size;
56503998195SJoerg Sonnenberger 		ds->size = 0;
56603998195SJoerg Sonnenberger 		error = udf_readatoffset(ds->node, &ds->size, ds->offset,
56703998195SJoerg Sonnenberger 		    &ds->bp, &ds->data);
56803998195SJoerg Sonnenberger 		if (error) {
56903998195SJoerg Sonnenberger 			ds->error = error;
57003998195SJoerg Sonnenberger 			return(NULL);
57103998195SJoerg Sonnenberger 		}
57203998195SJoerg Sonnenberger 
57303998195SJoerg Sonnenberger 		/*
57403998195SJoerg Sonnenberger 		 * If the fragment was so small that we didn't get
57503998195SJoerg Sonnenberger 		 * the l_iu and l_fi fields, copy those in.
57603998195SJoerg Sonnenberger 		 */
57703998195SJoerg Sonnenberger 		if (frag_size < UDF_FID_SIZE)
57803998195SJoerg Sonnenberger 			bcopy(ds->data, &ds->buf[frag_size],
57903998195SJoerg Sonnenberger 			    UDF_FID_SIZE - frag_size);
58003998195SJoerg Sonnenberger 
58103998195SJoerg Sonnenberger 		/*
58203998195SJoerg Sonnenberger 		 * Now that we have enough of the fid to work with,
58303998195SJoerg Sonnenberger 		 * copy in the rest of the fid from the new
58403998195SJoerg Sonnenberger 		 * allocation.
58503998195SJoerg Sonnenberger 		 */
58603998195SJoerg Sonnenberger 		total_fid_size = UDF_FID_SIZE + fid->l_iu + fid->l_fi;
58703998195SJoerg Sonnenberger 		if (total_fid_size > ds->udfmp->bsize) {
588086c1d7eSSascha Wildner 			kprintf("udf: invalid FID\n");
58903998195SJoerg Sonnenberger 			ds->error = EIO;
59003998195SJoerg Sonnenberger 			return(NULL);
59103998195SJoerg Sonnenberger 		}
59203998195SJoerg Sonnenberger 		bcopy(ds->data, &ds->buf[frag_size],
59303998195SJoerg Sonnenberger 		    total_fid_size - frag_size);
59403998195SJoerg Sonnenberger 
59503998195SJoerg Sonnenberger 		ds->fid_fragment = 1;
59603998195SJoerg Sonnenberger 	} else
59703998195SJoerg Sonnenberger 		total_fid_size = fid->l_iu + fid->l_fi + UDF_FID_SIZE;
59803998195SJoerg Sonnenberger 
59903998195SJoerg Sonnenberger 	/*
60003998195SJoerg Sonnenberger 	 * Update the offset. Align on a 4 byte boundary because the
60103998195SJoerg Sonnenberger 	 * UDF spec says so.
60203998195SJoerg Sonnenberger 	 */
60303998195SJoerg Sonnenberger 	ds->this_off = ds->off;
60403998195SJoerg Sonnenberger 	if (!ds->fid_fragment)
60503998195SJoerg Sonnenberger 		ds->off += (total_fid_size + 3) & ~0x03;
60603998195SJoerg Sonnenberger 	else
60703998195SJoerg Sonnenberger 		ds->off = (total_fid_size - frag_size + 3) & ~0x03;
60803998195SJoerg Sonnenberger 
60903998195SJoerg Sonnenberger 	return(fid);
61003998195SJoerg Sonnenberger }
61103998195SJoerg Sonnenberger 
61203998195SJoerg Sonnenberger static void
udf_closedir(struct udf_dirstream * ds)61303998195SJoerg Sonnenberger udf_closedir(struct udf_dirstream *ds)
61403998195SJoerg Sonnenberger {
61503998195SJoerg Sonnenberger 
61603998195SJoerg Sonnenberger 	if (ds->bp != NULL)
61703998195SJoerg Sonnenberger 		brelse(ds->bp);
61803998195SJoerg Sonnenberger 
61903998195SJoerg Sonnenberger 	if (ds->fid_fragment && ds->buf != NULL)
620efda3bd0SMatthew Dillon 		kfree(ds->buf, M_UDFFID);
62103998195SJoerg Sonnenberger 
622efda3bd0SMatthew Dillon 	kfree(ds, M_UDFDS);
62303998195SJoerg Sonnenberger }
62403998195SJoerg Sonnenberger 
62503998195SJoerg Sonnenberger static int
udf_readdir(struct vop_readdir_args * a)62603998195SJoerg Sonnenberger udf_readdir(struct vop_readdir_args *a)
62703998195SJoerg Sonnenberger {
62803998195SJoerg Sonnenberger 	struct vnode *vp;
62903998195SJoerg Sonnenberger 	struct uio *uio;
63003998195SJoerg Sonnenberger 	struct udf_node *node;
63103998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
63203998195SJoerg Sonnenberger 	struct fileid_desc *fid;
63303998195SJoerg Sonnenberger 	struct udf_uiodir uiodir;
63403998195SJoerg Sonnenberger 	struct udf_dirstream *ds;
63584009d92SMatthew Dillon 	off_t *cookies = NULL;
63603998195SJoerg Sonnenberger 	int ncookies;
63703998195SJoerg Sonnenberger 	int error = 0;
638d6427990SJoerg Sonnenberger 	char *name;
63903998195SJoerg Sonnenberger 
64003998195SJoerg Sonnenberger 	vp = a->a_vp;
641885ecb13SMatthew Dillon 
642b458d1abSMatthew Dillon 	error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_FAILRECLAIM);
643b458d1abSMatthew Dillon 	if (error)
644885ecb13SMatthew Dillon 		return (error);
645885ecb13SMatthew Dillon 
64603998195SJoerg Sonnenberger 	uio = a->a_uio;
64703998195SJoerg Sonnenberger 	node = VTON(vp);
64803998195SJoerg Sonnenberger 	udfmp = node->udfmp;
64903998195SJoerg Sonnenberger 	uiodir.eofflag = 1;
65003998195SJoerg Sonnenberger 
65103998195SJoerg Sonnenberger 	if (a->a_ncookies != NULL) {
65203998195SJoerg Sonnenberger 		/*
65303998195SJoerg Sonnenberger 		 * Guess how many entries are needed.  If we run out, this
65403998195SJoerg Sonnenberger 		 * function will be called again and thing will pick up were
65503998195SJoerg Sonnenberger 		 * it left off.
65603998195SJoerg Sonnenberger 		 */
657fb0466c9SMatthew Dillon 		ncookies = uio->uio_resid / 8 + 1;
658fb0466c9SMatthew Dillon 		if (ncookies > 1024)
659fb0466c9SMatthew Dillon 			ncookies = 1024;
66084009d92SMatthew Dillon 		cookies = kmalloc(sizeof(off_t) * ncookies, M_TEMP, M_WAITOK);
66103998195SJoerg Sonnenberger 		uiodir.ncookies = ncookies;
66203998195SJoerg Sonnenberger 		uiodir.cookies = cookies;
66303998195SJoerg Sonnenberger 		uiodir.acookies = 0;
664d557216fSMatthew Dillon 	} else {
66503998195SJoerg Sonnenberger 		uiodir.cookies = NULL;
666d557216fSMatthew Dillon 		uiodir.ncookies = 0;
667d557216fSMatthew Dillon 	}
66803998195SJoerg Sonnenberger 
66903998195SJoerg Sonnenberger 	/*
67003998195SJoerg Sonnenberger 	 * Iterate through the file id descriptors.  Give the parent dir
67103998195SJoerg Sonnenberger 	 * entry special attention.
67203998195SJoerg Sonnenberger 	 */
67303998195SJoerg Sonnenberger 	ds = udf_opendir(node, uio->uio_offset, node->fentry->inf_len,
67403998195SJoerg Sonnenberger 			 node->udfmp);
67503998195SJoerg Sonnenberger 
676efda3bd0SMatthew Dillon 	name = kmalloc(NAME_MAX, M_TEMP, M_WAITOK);
677d6427990SJoerg Sonnenberger 
67803998195SJoerg Sonnenberger 	while ((fid = udf_getfid(ds)) != NULL) {
67903998195SJoerg Sonnenberger 
68003998195SJoerg Sonnenberger 		/* XXX Should we return an error on a bad fid? */
68103998195SJoerg Sonnenberger 		if (udf_checktag(&fid->tag, TAGID_FID)) {
682086c1d7eSSascha Wildner 			kprintf("Invalid FID tag\n");
68303998195SJoerg Sonnenberger 			error = EIO;
68403998195SJoerg Sonnenberger 			break;
68503998195SJoerg Sonnenberger 		}
68603998195SJoerg Sonnenberger 
68703998195SJoerg Sonnenberger 		/* Is this a deleted file? */
68803998195SJoerg Sonnenberger 		if (fid->file_char & UDF_FILE_CHAR_DEL)
68903998195SJoerg Sonnenberger 			continue;
69003998195SJoerg Sonnenberger 
69103998195SJoerg Sonnenberger 		if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
69203998195SJoerg Sonnenberger 			/* Do up the '.' and '..' entries.  Dummy values are
69303998195SJoerg Sonnenberger 			 * used for the cookies since the offset here is
69403998195SJoerg Sonnenberger 			 * usually zero, and NFS doesn't like that value
69503998195SJoerg Sonnenberger 			 */
696d6427990SJoerg Sonnenberger 			if (uiodir.cookies != NULL) {
697d6427990SJoerg Sonnenberger 				if (++uiodir.acookies > uiodir.ncookies) {
698d6427990SJoerg Sonnenberger 					uiodir.eofflag = 0;
69903998195SJoerg Sonnenberger 					break;
700d6427990SJoerg Sonnenberger 				}
701d6427990SJoerg Sonnenberger 				*uiodir.cookies++ = 1;
702d6427990SJoerg Sonnenberger 			}
703d6427990SJoerg Sonnenberger 			if (vop_write_dirent(&error, uio, node->hash_id, DT_DIR,
704d6427990SJoerg Sonnenberger 					     1, ".")) {
705d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
706d6427990SJoerg Sonnenberger 				break;
707d6427990SJoerg Sonnenberger 			}
708d6427990SJoerg Sonnenberger 			if (error) {
709d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
710d6427990SJoerg Sonnenberger 				break;
711d6427990SJoerg Sonnenberger 			}
712d6427990SJoerg Sonnenberger 			if (uiodir.cookies != NULL) {
713d6427990SJoerg Sonnenberger 				if (++uiodir.acookies > uiodir.ncookies) {
714d6427990SJoerg Sonnenberger 					uiodir.eofflag = 0;
715d6427990SJoerg Sonnenberger 					break;
716d6427990SJoerg Sonnenberger 				}
717d6427990SJoerg Sonnenberger 				*uiodir.cookies++ = 2;
718d6427990SJoerg Sonnenberger 			}
719d6427990SJoerg Sonnenberger 			if (vop_write_dirent(&error, uio, udf_getid(&fid->icb),
720d6427990SJoerg Sonnenberger 					     DT_DIR, 2, "..")) {
721d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
722d6427990SJoerg Sonnenberger 				break;
723d6427990SJoerg Sonnenberger 			}
724d6427990SJoerg Sonnenberger 			if (error) {
725d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
726d6427990SJoerg Sonnenberger 				break;
727d6427990SJoerg Sonnenberger 			}
72803998195SJoerg Sonnenberger 		} else {
729d6427990SJoerg Sonnenberger 			uint8_t d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
73003998195SJoerg Sonnenberger 			    DT_DIR : DT_UNKNOWN;
731d6427990SJoerg Sonnenberger 			uint16_t namelen = udf_transname(&fid->data[fid->l_iu],
732d6427990SJoerg Sonnenberger 			    name, fid->l_fi, udfmp);
733d6427990SJoerg Sonnenberger 
734d6427990SJoerg Sonnenberger 			if (uiodir.cookies != NULL) {
735d6427990SJoerg Sonnenberger 				if (++uiodir.acookies > uiodir.ncookies) {
736d6427990SJoerg Sonnenberger 					uiodir.eofflag = 0;
737d6427990SJoerg Sonnenberger 					break;
738d6427990SJoerg Sonnenberger 				}
739d6427990SJoerg Sonnenberger 				*uiodir.cookies++ = ds->this_off;
740d6427990SJoerg Sonnenberger 			}
741d6427990SJoerg Sonnenberger 			if (vop_write_dirent(&error, uio, udf_getid(&fid->icb),
742d6427990SJoerg Sonnenberger 					 d_type, namelen, name)) {
743d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
744d6427990SJoerg Sonnenberger 				break;
745d6427990SJoerg Sonnenberger 			}
746d6427990SJoerg Sonnenberger 			if (error) {
747d6427990SJoerg Sonnenberger 				uiodir.eofflag = 0;
748d6427990SJoerg Sonnenberger 				break;
749d6427990SJoerg Sonnenberger 			}
75003998195SJoerg Sonnenberger 		}
75103998195SJoerg Sonnenberger 		if (error) {
752086c1d7eSSascha Wildner 			kprintf("uiomove returned %d\n", error);
75303998195SJoerg Sonnenberger 			break;
75403998195SJoerg Sonnenberger 		}
75503998195SJoerg Sonnenberger 
75603998195SJoerg Sonnenberger 	}
75703998195SJoerg Sonnenberger 
758efda3bd0SMatthew Dillon 	kfree(name, M_TEMP);
759d6427990SJoerg Sonnenberger 
76003998195SJoerg Sonnenberger 	/* tell the calling layer whether we need to be called again */
76103998195SJoerg Sonnenberger 	*a->a_eofflag = uiodir.eofflag;
76203998195SJoerg Sonnenberger 	uio->uio_offset = ds->offset + ds->off;
76303998195SJoerg Sonnenberger 
76403998195SJoerg Sonnenberger 	if (!error)
76503998195SJoerg Sonnenberger 		error = ds->error;
76603998195SJoerg Sonnenberger 
76703998195SJoerg Sonnenberger 	udf_closedir(ds);
76803998195SJoerg Sonnenberger 
76903998195SJoerg Sonnenberger 	if (a->a_ncookies != NULL) {
77003998195SJoerg Sonnenberger 		if (error)
771efda3bd0SMatthew Dillon 			kfree(cookies, M_TEMP);
77203998195SJoerg Sonnenberger 		else {
77303998195SJoerg Sonnenberger 			*a->a_ncookies = uiodir.acookies;
77403998195SJoerg Sonnenberger 			*a->a_cookies = cookies;
77503998195SJoerg Sonnenberger 		}
77603998195SJoerg Sonnenberger 	}
77703998195SJoerg Sonnenberger 
778885ecb13SMatthew Dillon 	vn_unlock(vp);
77903998195SJoerg Sonnenberger 	return(error);
78003998195SJoerg Sonnenberger }
78103998195SJoerg Sonnenberger 
78203998195SJoerg Sonnenberger /* Are there any implementations out there that do soft-links? */
78303998195SJoerg Sonnenberger static int
udf_readlink(struct vop_readlink_args * ap)78403998195SJoerg Sonnenberger udf_readlink(struct vop_readlink_args *ap)
78503998195SJoerg Sonnenberger {
786086c1d7eSSascha Wildner 	kprintf("%s called\n", __func__);
78703998195SJoerg Sonnenberger 	return(EOPNOTSUPP);
78803998195SJoerg Sonnenberger }
78903998195SJoerg Sonnenberger 
79003998195SJoerg Sonnenberger static int
udf_strategy(struct vop_strategy_args * ap)79181b5c339SMatthew Dillon udf_strategy(struct vop_strategy_args *ap)
79203998195SJoerg Sonnenberger {
79381b5c339SMatthew Dillon 	struct bio *bio;
79481b5c339SMatthew Dillon 	struct bio *nbio;
79503998195SJoerg Sonnenberger 	struct buf *bp;
79603998195SJoerg Sonnenberger 	struct vnode *vp;
79703998195SJoerg Sonnenberger 	struct udf_node *node;
79803998195SJoerg Sonnenberger 	int maxsize;
79954078292SMatthew Dillon 	daddr_t dblkno;
80003998195SJoerg Sonnenberger 
80181b5c339SMatthew Dillon 	bio = ap->a_bio;
80281b5c339SMatthew Dillon 	bp = bio->bio_buf;
80381b5c339SMatthew Dillon 	vp = ap->a_vp;
80403998195SJoerg Sonnenberger 	node = VTON(vp);
80503998195SJoerg Sonnenberger 
80681b5c339SMatthew Dillon 	nbio = push_bio(bio);
80754078292SMatthew Dillon 	if (nbio->bio_offset == NOOFFSET) {
80803998195SJoerg Sonnenberger 		/*
80903998195SJoerg Sonnenberger 		 * Files that are embedded in the fentry don't translate well
81003998195SJoerg Sonnenberger 		 * to a block number.  Reject.
81103998195SJoerg Sonnenberger 		 */
81281b5c339SMatthew Dillon 		if (udf_bmap_internal(node,
81354078292SMatthew Dillon 				     bio->bio_offset,
81454078292SMatthew Dillon 				     &dblkno, &maxsize)) {
81503998195SJoerg Sonnenberger 			clrbuf(bp);
81654078292SMatthew Dillon 			nbio->bio_offset = NOOFFSET;
81754078292SMatthew Dillon 		} else {
81854078292SMatthew Dillon 			nbio->bio_offset = dbtob(dblkno);
81903998195SJoerg Sonnenberger 		}
82003998195SJoerg Sonnenberger 	}
82154078292SMatthew Dillon 	if (nbio->bio_offset == NOOFFSET) {
82281b5c339SMatthew Dillon 		/* I/O was never started on nbio, must biodone(bio) */
82381b5c339SMatthew Dillon 		biodone(bio);
82403998195SJoerg Sonnenberger 		return(0);
82503998195SJoerg Sonnenberger 	}
82681b5c339SMatthew Dillon 	vn_strategy(node->i_devvp, nbio);
82703998195SJoerg Sonnenberger 	return(0);
82803998195SJoerg Sonnenberger }
82903998195SJoerg Sonnenberger 
83003998195SJoerg Sonnenberger static int
udf_bmap(struct vop_bmap_args * a)83103998195SJoerg Sonnenberger udf_bmap(struct vop_bmap_args *a)
83203998195SJoerg Sonnenberger {
83303998195SJoerg Sonnenberger 	struct udf_node *node;
83403998195SJoerg Sonnenberger 	uint32_t max_size;
83503998195SJoerg Sonnenberger 	daddr_t lsector;
83603998195SJoerg Sonnenberger 	int error;
83703998195SJoerg Sonnenberger 
83803998195SJoerg Sonnenberger 	node = VTON(a->a_vp);
83903998195SJoerg Sonnenberger 
84054078292SMatthew Dillon 	if (a->a_doffsetp == NULL)
84103998195SJoerg Sonnenberger 		return(0);
84203998195SJoerg Sonnenberger 
84354078292SMatthew Dillon 	KKASSERT(a->a_loffset % node->udfmp->bsize == 0);
84454078292SMatthew Dillon 
84554078292SMatthew Dillon 	error = udf_bmap_internal(node, a->a_loffset, &lsector, &max_size);
84603998195SJoerg Sonnenberger 	if (error)
84703998195SJoerg Sonnenberger 		return(error);
84803998195SJoerg Sonnenberger 
84903998195SJoerg Sonnenberger 	/* Translate logical to physical sector number */
85054078292SMatthew Dillon 	*a->a_doffsetp = (off_t)lsector << node->udfmp->bshift;
85103998195SJoerg Sonnenberger 
85203998195SJoerg Sonnenberger 	/* Punt on read-ahead for now */
85303998195SJoerg Sonnenberger 	if (a->a_runp)
85403998195SJoerg Sonnenberger 		*a->a_runp = 0;
85554078292SMatthew Dillon 	if (a->a_runb)
85654078292SMatthew Dillon 		*a->a_runb = 0;
85703998195SJoerg Sonnenberger 	return(0);
85803998195SJoerg Sonnenberger }
85903998195SJoerg Sonnenberger 
86003998195SJoerg Sonnenberger /*
86103998195SJoerg Sonnenberger  * The all powerful VOP_LOOKUP().
86203998195SJoerg Sonnenberger  */
86303998195SJoerg Sonnenberger static int
udf_lookup(struct vop_old_lookup_args * a)864e62afb5fSMatthew Dillon udf_lookup(struct vop_old_lookup_args *a)
86503998195SJoerg Sonnenberger {
86603998195SJoerg Sonnenberger 	struct vnode *dvp;
86703998195SJoerg Sonnenberger 	struct vnode *tdp = NULL;
86803998195SJoerg Sonnenberger 	struct vnode **vpp = a->a_vpp;
86903998195SJoerg Sonnenberger 	struct udf_node *node;
87003998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
87103998195SJoerg Sonnenberger 	struct fileid_desc *fid = NULL;
87203998195SJoerg Sonnenberger 	struct udf_dirstream *ds;
87303998195SJoerg Sonnenberger 	u_long nameiop;
87403998195SJoerg Sonnenberger 	u_long flags;
87503998195SJoerg Sonnenberger 	char *nameptr;
87603998195SJoerg Sonnenberger 	long namelen;
87703998195SJoerg Sonnenberger 	ino_t id = 0;
87803998195SJoerg Sonnenberger 	int offset, error = 0;
87903998195SJoerg Sonnenberger 	int numdirpasses, fsize;
88003998195SJoerg Sonnenberger 
88103998195SJoerg Sonnenberger 	dvp = a->a_dvp;
88203998195SJoerg Sonnenberger 	node = VTON(dvp);
88303998195SJoerg Sonnenberger 	udfmp = node->udfmp;
88403998195SJoerg Sonnenberger 	nameiop = a->a_cnp->cn_nameiop;
88503998195SJoerg Sonnenberger 	flags = a->a_cnp->cn_flags;
88603998195SJoerg Sonnenberger 	nameptr = a->a_cnp->cn_nameptr;
88703998195SJoerg Sonnenberger 	namelen = a->a_cnp->cn_namelen;
88803998195SJoerg Sonnenberger 	fsize = node->fentry->inf_len;
88903998195SJoerg Sonnenberger 
890880cdd2fSSascha Wildner 	*vpp = NULL;
891b808830cSSimon Schubert 
89203998195SJoerg Sonnenberger 	/*
89303998195SJoerg Sonnenberger 	 * If this is a LOOKUP and we've already partially searched through
89403998195SJoerg Sonnenberger 	 * the directory, pick up where we left off and flag that the
89503998195SJoerg Sonnenberger 	 * directory may need to be searched twice.  For a full description,
89603998195SJoerg Sonnenberger 	 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
89703998195SJoerg Sonnenberger 	 */
89803998195SJoerg Sonnenberger 	if (nameiop != NAMEI_LOOKUP || node->diroff == 0 ||
89903998195SJoerg Sonnenberger 	    node->diroff > fsize) {
90003998195SJoerg Sonnenberger 		offset = 0;
90103998195SJoerg Sonnenberger 		numdirpasses = 1;
90203998195SJoerg Sonnenberger 	} else {
90303998195SJoerg Sonnenberger 		offset = node->diroff;
90403998195SJoerg Sonnenberger 		numdirpasses = 2;
90503998195SJoerg Sonnenberger 	}
90603998195SJoerg Sonnenberger 
90703998195SJoerg Sonnenberger lookloop:
90803998195SJoerg Sonnenberger 	ds = udf_opendir(node, offset, fsize, udfmp);
90903998195SJoerg Sonnenberger 
91003998195SJoerg Sonnenberger 	while ((fid = udf_getfid(ds)) != NULL) {
91103998195SJoerg Sonnenberger 		/* XXX Should we return an error on a bad fid? */
91203998195SJoerg Sonnenberger 		if (udf_checktag(&fid->tag, TAGID_FID)) {
913086c1d7eSSascha Wildner 			kprintf("udf_lookup: Invalid tag\n");
91403998195SJoerg Sonnenberger 			error = EIO;
91503998195SJoerg Sonnenberger 			break;
91603998195SJoerg Sonnenberger 		}
91703998195SJoerg Sonnenberger 
91803998195SJoerg Sonnenberger 		/* Is this a deleted file? */
91903998195SJoerg Sonnenberger 		if (fid->file_char & UDF_FILE_CHAR_DEL)
92003998195SJoerg Sonnenberger 			continue;
92103998195SJoerg Sonnenberger 
92203998195SJoerg Sonnenberger 		if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
92303998195SJoerg Sonnenberger 			if (flags & CNP_ISDOTDOT) {
92403998195SJoerg Sonnenberger 				id = udf_getid(&fid->icb);
92503998195SJoerg Sonnenberger 				break;
92603998195SJoerg Sonnenberger 			}
92703998195SJoerg Sonnenberger 		} else {
92803998195SJoerg Sonnenberger 			if (!(udf_cmpname(&fid->data[fid->l_iu],
92903998195SJoerg Sonnenberger 					  nameptr, fid->l_fi, namelen, udfmp))) {
93003998195SJoerg Sonnenberger 				id = udf_getid(&fid->icb);
93103998195SJoerg Sonnenberger 				break;
93203998195SJoerg Sonnenberger 			}
93303998195SJoerg Sonnenberger 		}
93403998195SJoerg Sonnenberger 	}
93503998195SJoerg Sonnenberger 
93603998195SJoerg Sonnenberger 	if (!error)
93703998195SJoerg Sonnenberger 		error = ds->error;
93803998195SJoerg Sonnenberger 
93903998195SJoerg Sonnenberger 	/* XXX Bail out here? */
94003998195SJoerg Sonnenberger 	if (error) {
94103998195SJoerg Sonnenberger 		udf_closedir(ds);
94203998195SJoerg Sonnenberger 		return (error);
94303998195SJoerg Sonnenberger 	}
94403998195SJoerg Sonnenberger 
94503998195SJoerg Sonnenberger 	/* Did we have a match? */
94603998195SJoerg Sonnenberger 	if (id) {
947b9b0a6d0SMatthew Dillon 		error = udf_vget(udfmp->im_mountp, NULL, id, &tdp);
94803998195SJoerg Sonnenberger 		if (!error) {
94903998195SJoerg Sonnenberger 			/*
95003998195SJoerg Sonnenberger 			 * Remember where this entry was if it's the final
95103998195SJoerg Sonnenberger 			 * component.
95203998195SJoerg Sonnenberger 			 */
953fad57d0eSMatthew Dillon 			if (nameiop == NAMEI_LOOKUP)
95403998195SJoerg Sonnenberger 				node->diroff = ds->offset + ds->off;
955fad57d0eSMatthew Dillon 			if ((flags & CNP_LOCKPARENT) == 0) {
95603998195SJoerg Sonnenberger 				a->a_cnp->cn_flags |= CNP_PDIRUNLOCK;
957a11aaa81SMatthew Dillon 				vn_unlock(dvp);
95803998195SJoerg Sonnenberger 			}
95903998195SJoerg Sonnenberger 
96003998195SJoerg Sonnenberger 			*vpp = tdp;
96103998195SJoerg Sonnenberger 		}
96203998195SJoerg Sonnenberger 	} else {
96303998195SJoerg Sonnenberger 		/* Name wasn't found on this pass.  Do another pass? */
96403998195SJoerg Sonnenberger 		if (numdirpasses == 2) {
96503998195SJoerg Sonnenberger 			numdirpasses--;
96603998195SJoerg Sonnenberger 			offset = 0;
96703998195SJoerg Sonnenberger 			udf_closedir(ds);
96803998195SJoerg Sonnenberger 			goto lookloop;
96903998195SJoerg Sonnenberger 		}
970fad57d0eSMatthew Dillon 		if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) {
97103998195SJoerg Sonnenberger 			error = EROFS;
97203998195SJoerg Sonnenberger 		} else {
97303998195SJoerg Sonnenberger 			error = ENOENT;
97403998195SJoerg Sonnenberger 		}
97503998195SJoerg Sonnenberger 	}
97603998195SJoerg Sonnenberger 
97703998195SJoerg Sonnenberger 	udf_closedir(ds);
97803998195SJoerg Sonnenberger 	return(error);
97903998195SJoerg Sonnenberger }
98003998195SJoerg Sonnenberger 
98103998195SJoerg Sonnenberger static int
udf_reclaim(struct vop_reclaim_args * a)98203998195SJoerg Sonnenberger udf_reclaim(struct vop_reclaim_args *a)
98303998195SJoerg Sonnenberger {
98403998195SJoerg Sonnenberger 	struct vnode *vp;
98503998195SJoerg Sonnenberger 	struct udf_node *unode;
98603998195SJoerg Sonnenberger 
98703998195SJoerg Sonnenberger 	vp = a->a_vp;
98803998195SJoerg Sonnenberger 	unode = VTON(vp);
98903998195SJoerg Sonnenberger 
99003998195SJoerg Sonnenberger 	if (unode != NULL) {
99103998195SJoerg Sonnenberger 		udf_hashrem(unode);
99203998195SJoerg Sonnenberger 		if (unode->i_devvp) {
99303998195SJoerg Sonnenberger 			vrele(unode->i_devvp);
99403998195SJoerg Sonnenberger 			unode->i_devvp = 0;
99503998195SJoerg Sonnenberger 		}
99603998195SJoerg Sonnenberger 
99703998195SJoerg Sonnenberger 		if (unode->fentry != NULL)
998efda3bd0SMatthew Dillon 			kfree(unode->fentry, M_UDFFENTRY);
999efda3bd0SMatthew Dillon 		kfree(unode, M_UDFNODE);
100003998195SJoerg Sonnenberger 		vp->v_data = NULL;
100103998195SJoerg Sonnenberger 	}
100203998195SJoerg Sonnenberger 
100303998195SJoerg Sonnenberger 	return(0);
100403998195SJoerg Sonnenberger }
100503998195SJoerg Sonnenberger 
100603998195SJoerg Sonnenberger /*
100703998195SJoerg Sonnenberger  * Read the block and then set the data pointer to correspond with the
100803998195SJoerg Sonnenberger  * offset passed in.  Only read in at most 'size' bytes, and then set 'size'
100903998195SJoerg Sonnenberger  * to the number of bytes pointed to.  If 'size' is zero, try to read in a
101003998195SJoerg Sonnenberger  * whole extent.
1011ffaa7d78SMatthew Dillon  *
1012ffaa7d78SMatthew Dillon  * Note that *bp may be assigned error or not.
1013ffaa7d78SMatthew Dillon  *
101403998195SJoerg Sonnenberger  * XXX 'size' is limited to the logical block size for now due to problems
101503998195SJoerg Sonnenberger  * with udf_read()
101603998195SJoerg Sonnenberger  */
101703998195SJoerg Sonnenberger static int
udf_readatoffset(struct udf_node * node,int * size,int offset,struct buf ** bp,uint8_t ** data)101803998195SJoerg Sonnenberger udf_readatoffset(struct udf_node *node, int *size, int offset, struct buf **bp,
101903998195SJoerg Sonnenberger 		 uint8_t **data)
102003998195SJoerg Sonnenberger {
102103998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
102203998195SJoerg Sonnenberger 	struct file_entry *fentry = NULL;
102303998195SJoerg Sonnenberger 	struct buf *bp1;
102403998195SJoerg Sonnenberger 	uint32_t max_size;
102503998195SJoerg Sonnenberger 	daddr_t sector;
102603998195SJoerg Sonnenberger 	int error;
102703998195SJoerg Sonnenberger 
102803998195SJoerg Sonnenberger 	udfmp = node->udfmp;
102903998195SJoerg Sonnenberger 
1030ffaa7d78SMatthew Dillon 	*bp = NULL;
103103998195SJoerg Sonnenberger 	error = udf_bmap_internal(node, offset, &sector, &max_size);
103203998195SJoerg Sonnenberger 	if (error == UDF_INVALID_BMAP) {
103303998195SJoerg Sonnenberger 		/*
103403998195SJoerg Sonnenberger 		 * This error means that the file *data* is stored in the
103503998195SJoerg Sonnenberger 		 * allocation descriptor field of the file entry.
103603998195SJoerg Sonnenberger 		 */
103703998195SJoerg Sonnenberger 		fentry = node->fentry;
103803998195SJoerg Sonnenberger 		*data = &fentry->data[fentry->l_ea];
103903998195SJoerg Sonnenberger 		*size = fentry->l_ad;
104003998195SJoerg Sonnenberger 		return(0);
1041ffaa7d78SMatthew Dillon 	} else if (error != 0) {
104203998195SJoerg Sonnenberger 		return(error);
1043ffaa7d78SMatthew Dillon 	}
104403998195SJoerg Sonnenberger 
104503998195SJoerg Sonnenberger 	/* Adjust the size so that it is within range */
104603998195SJoerg Sonnenberger 	if (*size == 0 || *size > max_size)
104703998195SJoerg Sonnenberger 		*size = max_size;
104803998195SJoerg Sonnenberger 	*size = min(*size, MAXBSIZE);
104903998195SJoerg Sonnenberger 
105003998195SJoerg Sonnenberger 	if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
1051086c1d7eSSascha Wildner 		kprintf("warning: udf_readlblks returned error %d\n", error);
1052ffaa7d78SMatthew Dillon 		/* note: *bp may be non-NULL */
105303998195SJoerg Sonnenberger 		return(error);
105403998195SJoerg Sonnenberger 	}
105503998195SJoerg Sonnenberger 
105603998195SJoerg Sonnenberger 	bp1 = *bp;
105703998195SJoerg Sonnenberger 	*data = (uint8_t *)&bp1->b_data[offset % udfmp->bsize];
105803998195SJoerg Sonnenberger 	return(0);
105903998195SJoerg Sonnenberger }
106003998195SJoerg Sonnenberger 
106103998195SJoerg Sonnenberger /*
106203998195SJoerg Sonnenberger  * Translate a file offset into a logical block and then into a physical
106303998195SJoerg Sonnenberger  * block.
106403998195SJoerg Sonnenberger  */
106503998195SJoerg Sonnenberger static int
udf_bmap_internal(struct udf_node * node,uint32_t offset,daddr_t * sector,uint32_t * max_size)106603998195SJoerg Sonnenberger udf_bmap_internal(struct udf_node *node, uint32_t offset, daddr_t *sector, uint32_t *max_size)
106703998195SJoerg Sonnenberger {
106803998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
106903998195SJoerg Sonnenberger 	struct file_entry *fentry;
107003998195SJoerg Sonnenberger 	void *icb;
107103998195SJoerg Sonnenberger 	struct icb_tag *tag;
107203998195SJoerg Sonnenberger 	uint32_t icblen = 0;
107303998195SJoerg Sonnenberger 	daddr_t lsector;
107403998195SJoerg Sonnenberger 	int ad_offset, ad_num = 0;
107503998195SJoerg Sonnenberger 	int i, p_offset;
107603998195SJoerg Sonnenberger 
107703998195SJoerg Sonnenberger 	udfmp = node->udfmp;
107803998195SJoerg Sonnenberger 	fentry = node->fentry;
107903998195SJoerg Sonnenberger 	tag = &fentry->icbtag;
108003998195SJoerg Sonnenberger 
108103998195SJoerg Sonnenberger 	switch (tag->strat_type) {
108203998195SJoerg Sonnenberger 	case 4:
108303998195SJoerg Sonnenberger 		break;
108403998195SJoerg Sonnenberger 
108503998195SJoerg Sonnenberger 	case 4096:
1086086c1d7eSSascha Wildner 		kprintf("Cannot deal with strategy4096 yet!\n");
108703998195SJoerg Sonnenberger 		return(ENODEV);
108803998195SJoerg Sonnenberger 
108903998195SJoerg Sonnenberger 	default:
1090086c1d7eSSascha Wildner 		kprintf("Unknown strategy type %d\n", tag->strat_type);
109103998195SJoerg Sonnenberger 		return(ENODEV);
109203998195SJoerg Sonnenberger 	}
109303998195SJoerg Sonnenberger 
109403998195SJoerg Sonnenberger 	switch (tag->flags & 0x7) {
109503998195SJoerg Sonnenberger 	case 0:
109603998195SJoerg Sonnenberger 		/*
109703998195SJoerg Sonnenberger 		 * The allocation descriptor field is filled with short_ad's.
109803998195SJoerg Sonnenberger 		 * If the offset is beyond the current extent, look for the
109903998195SJoerg Sonnenberger 		 * next extent.
110003998195SJoerg Sonnenberger 		 */
110103998195SJoerg Sonnenberger 		do {
110203998195SJoerg Sonnenberger 			offset -= icblen;
110303998195SJoerg Sonnenberger 			ad_offset = sizeof(struct short_ad) * ad_num;
110403998195SJoerg Sonnenberger 			if (ad_offset > fentry->l_ad) {
1105086c1d7eSSascha Wildner 				kprintf("File offset out of bounds\n");
110603998195SJoerg Sonnenberger 				return(EINVAL);
110703998195SJoerg Sonnenberger 			}
110803998195SJoerg Sonnenberger 			icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
110903998195SJoerg Sonnenberger 			icblen = GETICBLEN(short_ad, icb);
111003998195SJoerg Sonnenberger 			ad_num++;
111103998195SJoerg Sonnenberger 		} while(offset >= icblen);
111203998195SJoerg Sonnenberger 
111303998195SJoerg Sonnenberger 		lsector = (offset  >> udfmp->bshift) +
111403998195SJoerg Sonnenberger 		    ((struct short_ad *)(icb))->pos;
111503998195SJoerg Sonnenberger 
111603998195SJoerg Sonnenberger 		*max_size = GETICBLEN(short_ad, icb);
111703998195SJoerg Sonnenberger 
111803998195SJoerg Sonnenberger 		break;
111903998195SJoerg Sonnenberger 	case 1:
112003998195SJoerg Sonnenberger 		/*
112103998195SJoerg Sonnenberger 		 * The allocation descriptor field is filled with long_ad's
112203998195SJoerg Sonnenberger 		 * If the offset is beyond the current extent, look for the
112303998195SJoerg Sonnenberger 		 * next extent.
112403998195SJoerg Sonnenberger 		 */
112503998195SJoerg Sonnenberger 		do {
112603998195SJoerg Sonnenberger 			offset -= icblen;
112703998195SJoerg Sonnenberger 			ad_offset = sizeof(struct long_ad) * ad_num;
112803998195SJoerg Sonnenberger 			if (ad_offset > fentry->l_ad) {
1129086c1d7eSSascha Wildner 				kprintf("File offset out of bounds\n");
113003998195SJoerg Sonnenberger 				return(EINVAL);
113103998195SJoerg Sonnenberger 			}
113203998195SJoerg Sonnenberger 			icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
113303998195SJoerg Sonnenberger 			icblen = GETICBLEN(long_ad, icb);
113403998195SJoerg Sonnenberger 			ad_num++;
113503998195SJoerg Sonnenberger 		} while(offset >= icblen);
113603998195SJoerg Sonnenberger 
113703998195SJoerg Sonnenberger 		lsector = (offset >> udfmp->bshift) +
113803998195SJoerg Sonnenberger 		    ((struct long_ad *)(icb))->loc.lb_num;
113903998195SJoerg Sonnenberger 
114003998195SJoerg Sonnenberger 		*max_size = GETICBLEN(long_ad, icb);
114103998195SJoerg Sonnenberger 
114203998195SJoerg Sonnenberger 		break;
114303998195SJoerg Sonnenberger 	case 3:
114403998195SJoerg Sonnenberger 		/*
114503998195SJoerg Sonnenberger 		 * This type means that the file *data* is stored in the
114603998195SJoerg Sonnenberger 		 * allocation descriptor field of the file entry.
114703998195SJoerg Sonnenberger 		 */
114803998195SJoerg Sonnenberger 		*max_size = 0;
114903998195SJoerg Sonnenberger 		*sector = node->hash_id + udfmp->part_start;
115003998195SJoerg Sonnenberger 
115103998195SJoerg Sonnenberger 		return(UDF_INVALID_BMAP);
115203998195SJoerg Sonnenberger 	case 2:
115303998195SJoerg Sonnenberger 		/* DirectCD does not use extended_ad's */
115403998195SJoerg Sonnenberger 	default:
1155086c1d7eSSascha Wildner 		kprintf("Unsupported allocation descriptor %d\n",
115603998195SJoerg Sonnenberger 		       tag->flags & 0x7);
115703998195SJoerg Sonnenberger 		return(ENODEV);
115803998195SJoerg Sonnenberger 	}
115903998195SJoerg Sonnenberger 
116003998195SJoerg Sonnenberger 	*sector = lsector + udfmp->part_start;
116103998195SJoerg Sonnenberger 
116203998195SJoerg Sonnenberger 	/*
116303998195SJoerg Sonnenberger 	 * Check the sparing table.  Each entry represents the beginning of
116403998195SJoerg Sonnenberger 	 * a packet.
116503998195SJoerg Sonnenberger 	 */
116603998195SJoerg Sonnenberger 	if (udfmp->s_table != NULL) {
116703998195SJoerg Sonnenberger 		for (i = 0; i< udfmp->s_table_entries; i++) {
116803998195SJoerg Sonnenberger 			p_offset = lsector - udfmp->s_table->entries[i].org;
116903998195SJoerg Sonnenberger 			if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
117003998195SJoerg Sonnenberger 				*sector = udfmp->s_table->entries[i].map +
117103998195SJoerg Sonnenberger 				    p_offset;
117203998195SJoerg Sonnenberger 				break;
117303998195SJoerg Sonnenberger 			}
117403998195SJoerg Sonnenberger 		}
117503998195SJoerg Sonnenberger 	}
117603998195SJoerg Sonnenberger 
117703998195SJoerg Sonnenberger 	return(0);
117803998195SJoerg Sonnenberger }
1179