xref: /netbsd-src/sys/fs/hfs/hfs_vnops.c (revision 6478b40555af74e0026fe65da2becaaefc2c3b08)
1*6478b405Sandvar /*	$NetBSD: hfs_vnops.c,v 1.40 2022/08/06 18:26:42 andvar Exp $	*/
225e99827Sdillo 
325e99827Sdillo /*-
425e99827Sdillo  * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
525e99827Sdillo  * All rights reserved.
625e99827Sdillo  *
725e99827Sdillo  * This code is derived from software contributed to The NetBSD Foundation
825e99827Sdillo  * by Yevgeny Binder and Dieter Baron.
925e99827Sdillo  *
1025e99827Sdillo  * Redistribution and use in source and binary forms, with or without
1125e99827Sdillo  * modification, are permitted provided that the following conditions
1225e99827Sdillo  * are met:
1325e99827Sdillo  * 1. Redistributions of source code must retain the above copyright
1425e99827Sdillo  *    notice, this list of conditions and the following disclaimer.
1525e99827Sdillo  * 2. Redistributions in binary form must reproduce the above copyright
1625e99827Sdillo  *    notice, this list of conditions and the following disclaimer in the
1725e99827Sdillo  *    documentation and/or other materials provided with the distribution.
1825e99827Sdillo  *
1925e99827Sdillo  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2025e99827Sdillo  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2125e99827Sdillo  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2225e99827Sdillo  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2325e99827Sdillo  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2425e99827Sdillo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2525e99827Sdillo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2625e99827Sdillo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2725e99827Sdillo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2825e99827Sdillo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2925e99827Sdillo  * POSSIBILITY OF SUCH DAMAGE.
3025e99827Sdillo  */
3125e99827Sdillo 
3225e99827Sdillo /*
3325e99827Sdillo  * Copyright (c) 1992, 1993
3425e99827Sdillo  *	The Regents of the University of California.  All rights reserved.
3525e99827Sdillo  *
3625e99827Sdillo  * This code is derived from software donated to Berkeley by
3725e99827Sdillo  * Jan-Simon Pendry.
3825e99827Sdillo  *
3925e99827Sdillo  * Redistribution and use in source and binary forms, with or without
4025e99827Sdillo  * modification, are permitted provided that the following conditions
4125e99827Sdillo  * are met:
4225e99827Sdillo  * 1. Redistributions of source code must retain the above copyright
4325e99827Sdillo  *    notice, this list of conditions and the following disclaimer.
4425e99827Sdillo  * 2. Redistributions in binary form must reproduce the above copyright
4525e99827Sdillo  *    notice, this list of conditions and the following disclaimer in the
4625e99827Sdillo  *    documentation and/or other materials provided with the distribution.
4725e99827Sdillo  * 3. Neither the name of the University nor the names of its contributors
4825e99827Sdillo  *    may be used to endorse or promote products derived from this software
4925e99827Sdillo  *    without specific prior written permission.
5025e99827Sdillo  *
5125e99827Sdillo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5225e99827Sdillo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5325e99827Sdillo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5425e99827Sdillo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5525e99827Sdillo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5625e99827Sdillo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5725e99827Sdillo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5825e99827Sdillo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5925e99827Sdillo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6025e99827Sdillo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6125e99827Sdillo  * SUCH DAMAGE.
6225e99827Sdillo  */
6325e99827Sdillo 
6425e99827Sdillo /*
6525e99827Sdillo  * Copyright (c) 1982, 1986, 1989, 1993, 1995
6625e99827Sdillo  *	The Regents of the University of California.  All rights reserved.
6725e99827Sdillo  * (c) UNIX System Laboratories, Inc.
6825e99827Sdillo  * All or some portions of this file are derived from material licensed
6925e99827Sdillo  * to the University of California by American Telephone and Telegraph
7025e99827Sdillo  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
7125e99827Sdillo  * the permission of UNIX System Laboratories, Inc.
7225e99827Sdillo  *
7325e99827Sdillo  * Redistribution and use in source and binary forms, with or without
7425e99827Sdillo  * modification, are permitted provided that the following conditions
7525e99827Sdillo  * are met:
7625e99827Sdillo  * 1. Redistributions of source code must retain the above copyright
7725e99827Sdillo  *    notice, this list of conditions and the following disclaimer.
7825e99827Sdillo  * 2. Redistributions in binary form must reproduce the above copyright
7925e99827Sdillo  *    notice, this list of conditions and the following disclaimer in the
8025e99827Sdillo  *    documentation and/or other materials provided with the distribution.
8125e99827Sdillo  * 3. Neither the name of the University nor the names of its contributors
8225e99827Sdillo  *    may be used to endorse or promote products derived from this software
8325e99827Sdillo  *    without specific prior written permission.
8425e99827Sdillo  *
8525e99827Sdillo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
8625e99827Sdillo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8725e99827Sdillo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8825e99827Sdillo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
8925e99827Sdillo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9025e99827Sdillo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9125e99827Sdillo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9225e99827Sdillo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9325e99827Sdillo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9425e99827Sdillo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9525e99827Sdillo  * SUCH DAMAGE.
9625e99827Sdillo  */
9725e99827Sdillo 
9825e99827Sdillo 
9925e99827Sdillo /*
10025e99827Sdillo  * Apple HFS+ filesystem
10125e99827Sdillo  */
10225e99827Sdillo 
10325e99827Sdillo #include <sys/cdefs.h>
104*6478b405Sandvar __KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.40 2022/08/06 18:26:42 andvar Exp $");
10525e99827Sdillo 
10625e99827Sdillo #ifdef _KERNEL_OPT
10725e99827Sdillo #include "opt_ipsec.h"
10825e99827Sdillo #endif
10925e99827Sdillo 
11025e99827Sdillo #include <sys/param.h>
11125e99827Sdillo #include <sys/systm.h>
11225e99827Sdillo #include <sys/kernel.h>
11325e99827Sdillo #include <sys/vmmeter.h>
11425e99827Sdillo #include <sys/time.h>
11525e99827Sdillo #include <sys/proc.h>
11625e99827Sdillo #include <sys/vnode.h>
11725e99827Sdillo #include <sys/malloc.h>
118265f1d8cShannken #include <sys/pool.h>
11925e99827Sdillo #include <sys/file.h>
12025e99827Sdillo #include <sys/stat.h>
12125e99827Sdillo #include <sys/mount.h>
12225e99827Sdillo #include <sys/namei.h>
12325e99827Sdillo #include <sys/buf.h>
12425e99827Sdillo #include <sys/dirent.h>
12525e99827Sdillo #include <sys/msgbuf.h>
12625e99827Sdillo 
12725e99827Sdillo #include <miscfs/fifofs/fifo.h>
12825e99827Sdillo #include <miscfs/specfs/specdev.h>
12925e99827Sdillo 
13056c3e412Sdillo #include <fs/hfs/hfs.h>
13156c3e412Sdillo #include <fs/hfs/unicode.h>
13225e99827Sdillo 
13325e99827Sdillo #include <miscfs/genfs/genfs.h>
13425e99827Sdillo 
135b7b49fc5Sdholland int	hfs_vop_parsepath(void *);
13656c3e412Sdillo int	hfs_vop_lookup(void *);
13756c3e412Sdillo int	hfs_vop_open(void *);
13856c3e412Sdillo int	hfs_vop_close(void *);
13956c3e412Sdillo int	hfs_vop_access(void *);
14056c3e412Sdillo int	hfs_vop_getattr(void *);
14156c3e412Sdillo int	hfs_vop_setattr(void *);
14256c3e412Sdillo int	hfs_vop_bmap(void *);
14356c3e412Sdillo int	hfs_vop_read(void *);
14456c3e412Sdillo int	hfs_vop_readdir(void *);
14556c3e412Sdillo int	hfs_vop_readlink(void *);
14656c3e412Sdillo int	hfs_vop_reclaim(void *);
14756c3e412Sdillo int	hfs_vop_print(void *);
14825e99827Sdillo 
1497b5e4e85Schristos #ifdef HFS_DEBUG
1507b5e4e85Schristos #define DPRINTF(a) printf a
1517b5e4e85Schristos #else
1527b5e4e85Schristos #define DPRINTF(a)
1537b5e4e85Schristos #endif
1547b5e4e85Schristos 
15525e99827Sdillo 
15656c3e412Sdillo int (**hfs_vnodeop_p) (void *);
15756c3e412Sdillo const struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
15825e99827Sdillo 	{ &vop_default_desc, vn_default_error },
159c6c16cd0Sdholland 	{ &vop_parsepath_desc, genfs_parsepath },	/* parsepath */
16056c3e412Sdillo 	{ &vop_lookup_desc, hfs_vop_lookup },		/* lookup */
16125e99827Sdillo 	{ &vop_create_desc, genfs_eopnotsupp },		/* create */
16225e99827Sdillo 	{ &vop_whiteout_desc, genfs_eopnotsupp },	/* whiteout */
16325e99827Sdillo 	{ &vop_mknod_desc, genfs_eopnotsupp },		/* mknod */
16456c3e412Sdillo 	{ &vop_open_desc, hfs_vop_open },		/* open */
16556c3e412Sdillo 	{ &vop_close_desc, hfs_vop_close },		/* close */
16656c3e412Sdillo 	{ &vop_access_desc, hfs_vop_access },		/* access */
1679aa2a9c3Schristos 	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
16856c3e412Sdillo 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
16956c3e412Sdillo 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
17056c3e412Sdillo 	{ &vop_read_desc, hfs_vop_read },		/* read */
17125e99827Sdillo 	{ &vop_write_desc, genfs_eopnotsupp },		/* write */
17205d075b3Sdholland 	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
17305d075b3Sdholland 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
17425e99827Sdillo 	{ &vop_ioctl_desc, genfs_eopnotsupp },		/* ioctl */
17525e99827Sdillo 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
17625e99827Sdillo 	{ &vop_poll_desc, genfs_eopnotsupp },		/* poll */
17725e99827Sdillo 	{ &vop_kqfilter_desc, genfs_kqfilter },		/* kqfilter */
17825e99827Sdillo 	{ &vop_revoke_desc, genfs_eopnotsupp },		/* revoke */
17925e99827Sdillo 	{ &vop_mmap_desc, genfs_mmap },			/* mmap */
18025e99827Sdillo 	{ &vop_fsync_desc, genfs_nullop },		/* fsync */
18125e99827Sdillo 	{ &vop_seek_desc, genfs_seek },			/* seek */
18225e99827Sdillo 	{ &vop_remove_desc, genfs_eopnotsupp },		/* remove */
18325e99827Sdillo 	{ &vop_link_desc, genfs_eopnotsupp },		/* link */
18425e99827Sdillo 	{ &vop_rename_desc, genfs_eopnotsupp },		/* rename */
18525e99827Sdillo 	{ &vop_mkdir_desc, genfs_eopnotsupp },		/* mkdir */
18625e99827Sdillo 	{ &vop_rmdir_desc, genfs_eopnotsupp },		/* rmdir */
18725e99827Sdillo 	{ &vop_symlink_desc, genfs_eopnotsupp },	/* symlink */
18856c3e412Sdillo 	{ &vop_readdir_desc, hfs_vop_readdir },		/* readdir */
18956c3e412Sdillo 	{ &vop_readlink_desc, hfs_vop_readlink },	/* readlink */
19025e99827Sdillo 	{ &vop_abortop_desc, genfs_abortop },		/* abortop */
19125e99827Sdillo 	{ &vop_inactive_desc, genfs_eopnotsupp },	/* inactive */
19256c3e412Sdillo 	{ &vop_reclaim_desc, hfs_vop_reclaim },		/* reclaim */
19325e99827Sdillo 	{ &vop_lock_desc, genfs_lock },			/* lock */
19425e99827Sdillo 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
19556c3e412Sdillo 	{ &vop_bmap_desc, hfs_vop_bmap },		/* bmap */
19625e99827Sdillo 	{ &vop_strategy_desc, genfs_eopnotsupp },	/* strategy */
19756c3e412Sdillo 	{ &vop_print_desc, hfs_vop_print },		/* print */
19825e99827Sdillo 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
19925e99827Sdillo 	{ &vop_pathconf_desc, genfs_eopnotsupp },	/* pathconf */
20025e99827Sdillo 	{ &vop_advlock_desc, genfs_eopnotsupp },	/* advlock */
20125e99827Sdillo 	{ &vop_bwrite_desc, genfs_eopnotsupp },		/* bwrite */
20225e99827Sdillo 	{ &vop_getpages_desc, genfs_getpages },		/* getpages */
20325e99827Sdillo 	{ &vop_putpages_desc, genfs_putpages },		/* putpages */
20425e99827Sdillo 	{ &vop_openextattr_desc, genfs_eopnotsupp },	/* openextattr */
20525e99827Sdillo 	{ &vop_closeextattr_desc, genfs_eopnotsupp },	/* closeextattr */
20625e99827Sdillo 	{ &vop_getextattr_desc, genfs_eopnotsupp },	/* getextattr */
20725e99827Sdillo 	{ &vop_setextattr_desc, genfs_eopnotsupp },	/* setextattr */
20825e99827Sdillo 	{ &vop_listextattr_desc, genfs_eopnotsupp },	/* listextattr */
20925e99827Sdillo 	{ &vop_deleteextattr_desc, genfs_eopnotsupp },	/* deleteextattr */
21025e99827Sdillo 	{ NULL, NULL }
21125e99827Sdillo };
21256c3e412Sdillo const struct vnodeopv_desc hfs_vnodeop_opv_desc =
21356c3e412Sdillo 	{ &hfs_vnodeop_p, hfs_vnodeop_entries };
21425e99827Sdillo 
21556c3e412Sdillo int (**hfs_specop_p) (void *);
21656c3e412Sdillo const struct vnodeopv_entry_desc hfs_specop_entries[] = {
21725e99827Sdillo 	{ &vop_default_desc, vn_default_error },
218d819c361Sdholland 	GENFS_SPECOP_ENTRIES,
21925e99827Sdillo 	{ &vop_close_desc, spec_close },		/* close */
22056c3e412Sdillo 	{ &vop_access_desc, hfs_vop_access },		/* access */
2219aa2a9c3Schristos 	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
22256c3e412Sdillo 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
22356c3e412Sdillo 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
22425e99827Sdillo 	{ &vop_read_desc, spec_read },			/* read */
22525e99827Sdillo 	{ &vop_write_desc, spec_write },		/* write */
22625e99827Sdillo 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
227baa3395fSad 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
22825e99827Sdillo 	{ &vop_inactive_desc, genfs_eopnotsupp },	/* inactive */
22956c3e412Sdillo 	{ &vop_reclaim_desc, hfs_vop_reclaim },		/* reclaim */
23025e99827Sdillo 	{ &vop_lock_desc, genfs_lock },			/* lock */
23125e99827Sdillo 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
23256c3e412Sdillo 	{ &vop_print_desc, hfs_vop_print },		/* print */
23325e99827Sdillo 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
23425e99827Sdillo 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
23525e99827Sdillo #if 0
236d819c361Sdholland 	{ &vop_openextattr_desc, hfs_openextattr },	/* openextattr */
237d819c361Sdholland 	{ &vop_closeextattr_desc, hfs_closeextattr },	/* closeextattr */
238d819c361Sdholland 	{ &vop_getextattr_desc, hfs_getextattr },	/* getextattr */
239d819c361Sdholland 	{ &vop_setextattr_desc, hfs_setextattr },	/* setextattr */
240d819c361Sdholland 	{ &vop_listextattr_desc, hfs_listextattr },	/* listextattr */
241d819c361Sdholland 	{ &vop_deleteextattr_desc, hfs_deleteextattr },	/* deleteextattr */
24225e99827Sdillo #endif
24325e99827Sdillo 	{ NULL, NULL }
24425e99827Sdillo };
24556c3e412Sdillo const struct vnodeopv_desc hfs_specop_opv_desc =
24656c3e412Sdillo 	{ &hfs_specop_p, hfs_specop_entries };
24725e99827Sdillo 
24856c3e412Sdillo int (**hfs_fifoop_p) (void *);
24956c3e412Sdillo const struct vnodeopv_entry_desc hfs_fifoop_entries[] = {
25025e99827Sdillo 	{ &vop_default_desc, vn_default_error },
251d819c361Sdholland 	GENFS_FIFOOP_ENTRIES,
252242bf1c3Spooka 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
25356c3e412Sdillo 	{ &vop_access_desc, hfs_vop_access },		/* access */
2549aa2a9c3Schristos 	{ &vop_accessx_desc, genfs_accessx },		/* accessx */
25556c3e412Sdillo 	{ &vop_getattr_desc, hfs_vop_getattr },		/* getattr */
25656c3e412Sdillo 	{ &vop_setattr_desc, hfs_vop_setattr },		/* setattr */
257242bf1c3Spooka 	{ &vop_read_desc, vn_fifo_bypass },		/* read */
258242bf1c3Spooka 	{ &vop_write_desc, vn_fifo_bypass },		/* write */
25925e99827Sdillo 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
260242bf1c3Spooka 	{ &vop_fsync_desc, vn_fifo_bypass },		/* fsync */
26125e99827Sdillo 	{ &vop_inactive_desc, genfs_eopnotsupp },	/* inactive */
26256c3e412Sdillo 	{ &vop_reclaim_desc, hfs_vop_reclaim },		/* reclaim */
26325e99827Sdillo 	{ &vop_lock_desc, genfs_lock },			/* lock */
26425e99827Sdillo 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
265242bf1c3Spooka 	{ &vop_strategy_desc, vn_fifo_bypass },		/* strategy */
26656c3e412Sdillo 	{ &vop_print_desc, hfs_vop_print },		/* print */
26725e99827Sdillo 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
26825e99827Sdillo 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
26925e99827Sdillo #if 0
270d819c361Sdholland 	{ &vop_openextattr_desc, hfs_openextattr },	/* openextattr */
271d819c361Sdholland 	{ &vop_closeextattr_desc, hfs_closeextattr },	/* closeextattr */
272d819c361Sdholland 	{ &vop_getextattr_desc, hfs_getextattr },	/* getextattr */
273d819c361Sdholland 	{ &vop_setextattr_desc, hfs_setextattr },	/* setextattr */
274d819c361Sdholland 	{ &vop_listextattr_desc, hfs_listextattr },	/* listextattr */
275d819c361Sdholland 	{ &vop_deleteextattr_desc, hfs_deleteextattr },	/* deleteextattr */
27625e99827Sdillo #endif
27725e99827Sdillo 	{ NULL, NULL }
27825e99827Sdillo };
27956c3e412Sdillo const struct vnodeopv_desc hfs_fifoop_opv_desc =
28056c3e412Sdillo 	{ &hfs_fifoop_p, hfs_fifoop_entries };
28125e99827Sdillo 
28225e99827Sdillo int
hfs_vop_parsepath(void * v)283b7b49fc5Sdholland hfs_vop_parsepath(void *v)
284b7b49fc5Sdholland {
285b7b49fc5Sdholland 	struct vop_parsepath_args /* {
286b7b49fc5Sdholland 		struct vnode *a_dvp;
287b7b49fc5Sdholland 		const char *a_name;
288b7b49fc5Sdholland 		size_t *a_retval;
289b7b49fc5Sdholland 	} */ *ap = v;
290b7b49fc5Sdholland 	size_t len;
291b7b49fc5Sdholland 	int error;
292b7b49fc5Sdholland 
293b7b49fc5Sdholland 	error = genfs_parsepath(v);
294b7b49fc5Sdholland 	if (error) {
295b7b49fc5Sdholland 		return error;
296b7b49fc5Sdholland 	}
297b7b49fc5Sdholland 
298b7b49fc5Sdholland 	len = *ap->a_retval;
299b7b49fc5Sdholland 	if (!strcmp(ap->a_name + len, "/rsrc")) {
300b7b49fc5Sdholland 		*ap->a_retval += 5;
301b7b49fc5Sdholland 	}
302b7b49fc5Sdholland 	return 0;
303b7b49fc5Sdholland }
304b7b49fc5Sdholland 
305b7b49fc5Sdholland int
hfs_vop_lookup(void * v)30656c3e412Sdillo hfs_vop_lookup(void *v)
30725e99827Sdillo {
30897834f7bShannken 	struct vop_lookup_v2_args /* {
30925e99827Sdillo 		struct vnode * a_dvp;
31025e99827Sdillo 		struct vnode ** a_vpp;
31125e99827Sdillo 		struct componentname * a_cnp;
31225e99827Sdillo 	} */ *ap = v;
31325e99827Sdillo 	struct componentname *cnp;
31456c3e412Sdillo 	struct hfsnode *dp;	/* hfsnode for directory being searched */
31525e99827Sdillo 	kauth_cred_t cred;
31625e99827Sdillo 	struct vnode **vpp;		/* resultant vnode */
31725e99827Sdillo 	struct vnode *tdp;		/* returned by VFS_VGET */
31825e99827Sdillo 	struct vnode *vdp;		/* vnode for directory being searched */
31956c3e412Sdillo 	hfs_catalog_key_t key;	/* hfs+ catalog search key for requested child */
32056c3e412Sdillo 	hfs_catalog_keyed_record_t rec; /* catalog record of requested child */
321b7b49fc5Sdholland 	size_t namelen;
322b7b49fc5Sdholland 	int use_resource_fork = 0;
32325e99827Sdillo 	unichar_t* unicn;		/* name of component, in Unicode */
32425e99827Sdillo 	const char *pname;
32525e99827Sdillo 	int error;
32625e99827Sdillo 	int flags;
32756c3e412Sdillo 	int result;			/* result of libhfs operations */
32825e99827Sdillo 
3297b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_lookup()\n"));
33025e99827Sdillo 
33125e99827Sdillo 	cnp = ap->a_cnp;
33225e99827Sdillo 	cred = cnp->cn_cred;
33325e99827Sdillo 	vdp = ap->a_dvp;
33425e99827Sdillo 	dp = VTOH(vdp);
33525e99827Sdillo 	error = 0;
33625e99827Sdillo 	pname = cnp->cn_nameptr;
33725e99827Sdillo 	result = 0;
33825e99827Sdillo 	unicn = NULL;
33925e99827Sdillo 	vpp = ap->a_vpp;
34025e99827Sdillo 	*vpp = NULL;
34125e99827Sdillo 
34225e99827Sdillo 	flags = cnp->cn_flags;
34325e99827Sdillo 
34425e99827Sdillo 
34525e99827Sdillo 	/*
346*6478b405Sandvar 	 * Check accessibility of directory.
34725e99827Sdillo 	 */
34861e8303eSpooka 	if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0)
34925e99827Sdillo 		return error;
35025e99827Sdillo 
35125e99827Sdillo 	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
35225e99827Sdillo 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
35325e99827Sdillo 		return EROFS;
35425e99827Sdillo 
35525e99827Sdillo 	/*
35625e99827Sdillo 	 * We now have a segment name to search for, and a directory to search.
35725e99827Sdillo 	 *
35825e99827Sdillo 	 * Before tediously performing a linear scan of the directory,
35925e99827Sdillo 	 * check the name cache to see if the directory/name pair
36025e99827Sdillo 	 * we are looking for is known already.
36125e99827Sdillo 	 */
36225e99827Sdillo /* XXX Cache disabled until we can make sure it works. */
3637b5e4e85Schristos #if 0
3647b5e4e85Schristos 	if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
3657b5e4e85Schristos 		return error;
3667b5e4e85Schristos #endif
36725e99827Sdillo 
36825e99827Sdillo 
3697b5e4e85Schristos #if 0
3707b5e4e85Schristos 	if (cnp->cn_namelen == 1 && *pname == '.') {
37125e99827Sdillo 		*vpp = vdp;
372c3183f32Spooka 		vref(vdp);
3737b5e4e85Schristos 		return 0;
3747b5e4e85Schristos 	}
3757b5e4e85Schristos #endif
37625e99827Sdillo 
37725e99827Sdillo 	if (flags & ISDOTDOT) {
3787b5e4e85Schristos 		DPRINTF(("DOTDOT "));
379265f1d8cShannken 		error = hfs_vget_internal(vdp->v_mount, dp->h_parent,
380265f1d8cShannken 		    HFS_RSRCFORK, &tdp);
3811b189c72Spooka 		if (error != 0)
38225e99827Sdillo 			goto error;
38325e99827Sdillo 		*vpp = tdp;
3847b5e4e85Schristos #if 0
3857b5e4e85Schristos 	} else if (dp->h_rec.u.cnid == rec.file.u.cnid) {
3867b5e4e85Schristos #endif
38725e99827Sdillo 	} else if (cnp->cn_namelen == 1 && pname[0] == '.') {
3887b5e4e85Schristos 		DPRINTF(("DOT "));
389c3183f32Spooka 		vref(vdp);	/* we want ourself, ie "." */
39025e99827Sdillo 		*vpp = vdp;
39125e99827Sdillo 	} else {
39256c3e412Sdillo 		hfs_callback_args cbargs;
39302c89a86Schristos 		uint8_t len, ni;
39425e99827Sdillo 
39556c3e412Sdillo 		hfslib_init_cbargs(&cbargs);
39625e99827Sdillo 
397b7b49fc5Sdholland 		namelen = cnp->cn_namelen;
398b7b49fc5Sdholland 		if (namelen > 5 &&
399b7b49fc5Sdholland 		    !strcmp(cnp->cn_nameptr + namelen - 5, "/rsrc")) {
400b7b49fc5Sdholland 			namelen -= 5;
401b7b49fc5Sdholland 			use_resource_fork = 1;
402b7b49fc5Sdholland 		}
403b7b49fc5Sdholland 
40425e99827Sdillo 		/* XXX: when decomposing, string could grow
40525e99827Sdillo 		   and we have to handle overflow */
406b7b49fc5Sdholland 		unicn = malloc(namelen * sizeof(unicn[0]), M_TEMP, M_WAITOK);
407b7b49fc5Sdholland 		len = utf8_to_utf16(unicn, namelen,
408b7b49fc5Sdholland 		    cnp->cn_nameptr, namelen, 0, NULL);
40902c89a86Schristos 		for (ni = 0; ni < len; ni++)
41088453bd9Schristos 			if (unicn[ni] == (unichar_t)':')
41188453bd9Schristos 				unicn[ni] = (unichar_t)'/';
41225e99827Sdillo 		/* XXX: check conversion errors? */
41336a81a3bSgmcgarry 		if (hfslib_make_catalog_key(VTOH(vdp)->h_rec.u.cnid, len, unicn,
41425e99827Sdillo 		    &key) == 0) {
4157b5e4e85Schristos 			DPRINTF(("ERROR in hfslib_make_catalog_key\n"));
41625e99827Sdillo 			error = EINVAL;
41725e99827Sdillo 			goto error;
41825e99827Sdillo 		}
41925e99827Sdillo 
4207b5e4e85Schristos 		result = hfslib_find_catalog_record_with_key(&dp->h_hmp->hm_vol,
4217b5e4e85Schristos 		    &key, &rec, &cbargs);
42225e99827Sdillo 		if (result > 0) {
42325e99827Sdillo 			error = EINVAL;
42425e99827Sdillo 			goto error;
42525e99827Sdillo 		}
42625e99827Sdillo 		if (result < 0) {
42725e99827Sdillo 			if (cnp->cn_nameiop == CREATE)
42825e99827Sdillo 				error = EROFS;
42925e99827Sdillo 			else
43025e99827Sdillo 				error = ENOENT;
43125e99827Sdillo 			goto error;
43225e99827Sdillo 		}
43325e99827Sdillo 
43456c3e412Sdillo 		if (rec.file.user_info.file_type == HFS_HARD_LINK_FILE_TYPE
4357b5e4e85Schristos 		    && rec.file.user_info.file_creator == HFS_HFSLUS_CREATOR) {
43656c3e412Sdillo 			if (hfslib_get_hardlink(&dp->h_hmp->hm_vol,
43725e99827Sdillo 			    rec.file.bsd.special.inode_num,
43825e99827Sdillo 			    &rec, &cbargs) != 0) {
43925e99827Sdillo 				error = EINVAL;
44025e99827Sdillo 				goto error;
44125e99827Sdillo 			}
44225e99827Sdillo 		}
44325e99827Sdillo 
44456c3e412Sdillo 		if (rec.type == HFS_REC_FILE
445b7b49fc5Sdholland 		    && use_resource_fork
44625e99827Sdillo 		    && rec.file.rsrc_fork.logical_size > 0) {
447b7b49fc5Sdholland 		    /* advance namei next pointer to end of string */
44856c3e412Sdillo 			error = hfs_vget_internal(vdp->v_mount, rec.file.cnid,
44956c3e412Sdillo 			    HFS_RSRCFORK, &tdp);
450d4367314Smaxv 		} else
451265f1d8cShannken 			error = hfs_vget_internal(vdp->v_mount, rec.file.cnid,
452265f1d8cShannken 			    HFS_DATAFORK, &tdp);
45325e99827Sdillo 		if (error != 0)
45425e99827Sdillo 			goto error;
45525e99827Sdillo 		*vpp = tdp;
45625e99827Sdillo 	}
4577b5e4e85Schristos 	DPRINTF(("\n"));
45825e99827Sdillo 	/*
45925e99827Sdillo 	 * Insert name into cache if appropriate.
46025e99827Sdillo 	 */
46125e99827Sdillo /* XXX Cache disabled until we can make sure it works. */
4627b5e4e85Schristos #if 0
4637b5e4e85Schristos 	cache_enter(vdp, *vpp, cnp);
4647b5e4e85Schristos #endif
46525e99827Sdillo 
46625e99827Sdillo 	error = 0;
46725e99827Sdillo 
46825e99827Sdillo 	/* FALLTHROUGH */
46925e99827Sdillo error:
47025e99827Sdillo 	if (unicn != NULL)
47125e99827Sdillo 		free(unicn, M_TEMP);
47225e99827Sdillo 
47325e99827Sdillo 	return error;
47425e99827Sdillo }
47525e99827Sdillo 
47625e99827Sdillo int
hfs_vop_open(void * v)47756c3e412Sdillo hfs_vop_open(void *v)
47825e99827Sdillo {
47925e99827Sdillo #if 0
48025e99827Sdillo 	struct vop_open_args /* {
48125e99827Sdillo 		struct vnode *a_vp;
48225e99827Sdillo 		int a_mode;
48325e99827Sdillo 		kauth_cred_t a_cred;
48425e99827Sdillo 	} */ *ap = v;
48556c3e412Sdillo 	struct hfsnode *hn = VTOH(ap->a_vp);
48625e99827Sdillo #endif
4877b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_open()\n"));
48825e99827Sdillo 
48925e99827Sdillo 	/*
4907b5e4e85Schristos 	 * XXX This is a good place to read and cache the file's extents to
4917b5e4e85Schristos 	 * XXX avoid doing it upon every read/write. Must however keep the
4927b5e4e85Schristos 	 * XXX cache in sync when the file grows/shrinks. (So would that go
4937b5e4e85Schristos 	 * XXX in vop_truncate?)
49425e99827Sdillo 	 */
49525e99827Sdillo 
49625e99827Sdillo 	return 0;
49725e99827Sdillo }
49825e99827Sdillo 
49925e99827Sdillo int
hfs_vop_close(void * v)50056c3e412Sdillo hfs_vop_close(void *v)
50125e99827Sdillo {
50225e99827Sdillo #if 0
50325e99827Sdillo 	struct vop_close_args /* {
50425e99827Sdillo 		struct vnode *a_vp;
50525e99827Sdillo 		int a_fflag;
50625e99827Sdillo 		kauth_cred_t a_cred;
50725e99827Sdillo 	} */ *ap = v;
50856c3e412Sdillo 	struct hfsnode *hn = VTOH(ap->a_vp);
50925e99827Sdillo #endif
5107b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_close()\n"));
51125e99827Sdillo 
51225e99827Sdillo 	/* Release extents cache here. */
51325e99827Sdillo 
51425e99827Sdillo 	return 0;
51525e99827Sdillo }
51625e99827Sdillo 
517009f5d2fSelad static int
hfs_check_possible(struct vnode * vp,accmode_t accmode)5189aa2a9c3Schristos hfs_check_possible(struct vnode *vp, accmode_t accmode)
519009f5d2fSelad {
520009f5d2fSelad 
521009f5d2fSelad 	/*
522009f5d2fSelad 	 * Disallow writes on files, directories, and symlinks
523009f5d2fSelad 	 * since we have no write support yet.
524009f5d2fSelad 	 */
525009f5d2fSelad 
5269aa2a9c3Schristos 	if (accmode & VWRITE) {
527009f5d2fSelad 		switch (vp->v_type) {
528009f5d2fSelad 		case VDIR:
529009f5d2fSelad 		case VLNK:
530009f5d2fSelad 		case VREG:
531009f5d2fSelad 			return EROFS;
532009f5d2fSelad 		default:
533009f5d2fSelad 			break;
534009f5d2fSelad 		}
535009f5d2fSelad 	}
536009f5d2fSelad 
537009f5d2fSelad 	return 0;
538009f5d2fSelad }
539009f5d2fSelad 
540009f5d2fSelad static int
hfs_check_permitted(vnode_t * vp,struct vattr * va,accmode_t accmode,kauth_cred_t cred)5419aa2a9c3Schristos hfs_check_permitted(vnode_t *vp, struct vattr *va, accmode_t accmode,
5420c9d8d15Selad     kauth_cred_t cred)
543009f5d2fSelad {
544009f5d2fSelad 
5459aa2a9c3Schristos 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
5469aa2a9c3Schristos 	    va->va_type, va->va_mode), vp, NULL,  genfs_can_access(vp, cred,
5479aa2a9c3Schristos 	    va->va_uid, va->va_gid, va->va_mode, NULL, accmode));
548009f5d2fSelad }
549009f5d2fSelad 
55025e99827Sdillo int
hfs_vop_access(void * v)55156c3e412Sdillo hfs_vop_access(void *v)
55225e99827Sdillo {
55325e99827Sdillo 	struct vop_access_args /* {
55425e99827Sdillo 		struct vnode *a_vp;
5559aa2a9c3Schristos 		int a_accmode;
55625e99827Sdillo 		kauth_cred_t a_cred;
55725e99827Sdillo 	} */ *ap = v;
55825e99827Sdillo 	struct vattr va;
55925e99827Sdillo 	int error;
56025e99827Sdillo 
5617b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_access()\n"));
56225e99827Sdillo 
5639aa2a9c3Schristos 	error = hfs_check_possible(ap->a_vp, ap->a_accmode);
564009f5d2fSelad 	if (error)
565009f5d2fSelad 		return error;
56625e99827Sdillo 
56761e8303eSpooka 	if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0)
56825e99827Sdillo 		return error;
56925e99827Sdillo 
5709aa2a9c3Schristos 	error = hfs_check_permitted(ap->a_vp, &va, ap->a_accmode, ap->a_cred);
571009f5d2fSelad 
572009f5d2fSelad 	return error;
57325e99827Sdillo }
57425e99827Sdillo 
57525e99827Sdillo int
hfs_vop_getattr(void * v)57656c3e412Sdillo hfs_vop_getattr(void *v)
57725e99827Sdillo {
57825e99827Sdillo 	struct vop_getattr_args /* {
57925e99827Sdillo 		struct vnode	*a_vp;
58025e99827Sdillo 		struct vattr	*a_vap;
58125e99827Sdillo 		struct ucred	*a_cred;
58225e99827Sdillo 	} */ *ap = v;
58325e99827Sdillo 	struct vnode	*vp;
58456c3e412Sdillo 	struct hfsnode	*hp;
58525e99827Sdillo 	struct vattr	*vap;
58656c3e412Sdillo 	hfs_bsd_data_t *bsd;
58756c3e412Sdillo 	hfs_fork_t     *fork;
58825e99827Sdillo 
5897b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_getattr()\n"));
59025e99827Sdillo 
59125e99827Sdillo 	vp = ap->a_vp;
59225e99827Sdillo 	hp = VTOH(vp);
59325e99827Sdillo 	vap = ap->a_vap;
59425e99827Sdillo 
59525e99827Sdillo 	vattr_null(vap);
59625e99827Sdillo 
59725e99827Sdillo 	/*
5987b5e4e85Schristos 	 * XXX Cannot trust permissions/modes/flags stored in an HFS+ catalog
59925e99827Sdillo 	 * XXX record those values are not set on files created under Mac OS 9.
60025e99827Sdillo 	 */
60125e99827Sdillo 	vap->va_type = ap->a_vp->v_type;
60236a81a3bSgmcgarry 	if (hp->h_rec.u.rec_type == HFS_REC_FILE) {
6037b5e4e85Schristos 		hfs_file_record_t *f = &hp->h_rec.file;
60456c3e412Sdillo 		if (hp->h_fork == HFS_RSRCFORK)
6057b5e4e85Schristos 			fork = &f->rsrc_fork;
60625e99827Sdillo 		else
6077b5e4e85Schristos 			fork = &f->data_fork;
6087b5e4e85Schristos 		vap->va_fileid = f->cnid;
6097b5e4e85Schristos 		bsd = &f->bsd;
61056c3e412Sdillo 		vap->va_bytes = fork->total_blocks * HFS_BLOCKSIZE(vp);
61125e99827Sdillo 		vap->va_size = fork->logical_size;
6127b5e4e85Schristos 		hfs_time_to_timespec(f->date_created, &vap->va_ctime);
6137b5e4e85Schristos 		hfs_time_to_timespec(f->date_content_mod, &vap->va_mtime);
6147b5e4e85Schristos 		hfs_time_to_timespec(f->date_accessed, &vap->va_atime);
61525e99827Sdillo 		vap->va_nlink = 1;
616d4367314Smaxv 	} else if (hp->h_rec.u.rec_type == HFS_REC_FLDR) {
6177b5e4e85Schristos 		hfs_folder_record_t *f = &hp->h_rec.folder;
61825e99827Sdillo 		vap->va_fileid = hp->h_rec.folder.cnid;
6197b5e4e85Schristos 		bsd = &f->bsd;
62025e99827Sdillo 		vap->va_size = 512; /* XXX Temporary */
62125e99827Sdillo 		vap->va_bytes = 512; /* XXX Temporary */
6227b5e4e85Schristos 		hfs_time_to_timespec(f->date_created, &vap->va_ctime);
6237b5e4e85Schristos 		hfs_time_to_timespec(f->date_content_mod,&vap->va_mtime);
6247b5e4e85Schristos 		hfs_time_to_timespec(f->date_accessed, &vap->va_atime);
62525e99827Sdillo 		vap->va_nlink = 2; /* XXX */
626d4367314Smaxv 	} else {
6277b5e4e85Schristos 		DPRINTF(("hfs+: hfs_vop_getattr(): invalid record type %i",
6287b5e4e85Schristos 		    hp->h_rec.u.rec_type));
62925e99827Sdillo 		return EINVAL;
63025e99827Sdillo 	}
63125e99827Sdillo 
63225e99827Sdillo 	if ((bsd->file_mode & S_IFMT) == 0) {
63325e99827Sdillo 		/* no bsd permissions recorded, use default values */
63436a81a3bSgmcgarry 		if (hp->h_rec.u.rec_type == HFS_REC_FILE)
63556c3e412Sdillo 			vap->va_mode = (S_IFREG | HFS_DEFAULT_FILE_MODE);
63625e99827Sdillo 		else
63756c3e412Sdillo 			vap->va_mode = (S_IFDIR | HFS_DEFAULT_DIR_MODE);
63856c3e412Sdillo 		vap->va_uid = HFS_DEFAULT_UID;
63956c3e412Sdillo 		vap->va_gid = HFS_DEFAULT_GID;
640d4367314Smaxv 	} else {
64125e99827Sdillo 		vap->va_mode = bsd->file_mode;
64225e99827Sdillo 		vap->va_uid = bsd->owner_id;
64325e99827Sdillo 		vap->va_gid = bsd->group_id;
64425e99827Sdillo 		if ((vap->va_mode & S_IFMT) == S_IFCHR
64525e99827Sdillo 		    || (vap->va_mode & S_IFMT) == S_IFBLK) {
64625e99827Sdillo 			vap->va_rdev
64756c3e412Sdillo 			    = HFS_CONVERT_RDEV(bsd->special.raw_device);
64825e99827Sdillo 		}
64925e99827Sdillo 		else if (bsd->special.link_count != 0) {
65025e99827Sdillo 		    /* XXX: only if in metadata directory */
65125e99827Sdillo 		    vap->va_nlink = bsd->special.link_count;
65225e99827Sdillo 		}
65325e99827Sdillo 	}
65425e99827Sdillo 
65525e99827Sdillo 	vap->va_fsid = hp->h_dev;
65625e99827Sdillo 	vap->va_blocksize = hp->h_hmp->hm_vol.vh.block_size;
65725e99827Sdillo 	vap->va_gen = 1;
65825e99827Sdillo 	vap->va_flags = 0;
65925e99827Sdillo 
66025e99827Sdillo 	return 0;
66125e99827Sdillo }
66225e99827Sdillo 
66325e99827Sdillo int
hfs_vop_setattr(void * v)66456c3e412Sdillo hfs_vop_setattr(void *v)
66525e99827Sdillo {
66625e99827Sdillo 	struct vop_setattr_args /* {
66725e99827Sdillo 		struct vnode	*a_vp;
66825e99827Sdillo 		struct vattr	*a_vap;
66925e99827Sdillo 		kauth_cred_t	a_cred;
67025e99827Sdillo 	} */ *ap = v;
67125e99827Sdillo 	struct vattr	*vap;
67225e99827Sdillo 	struct vnode	*vp;
67325e99827Sdillo 
67425e99827Sdillo 	vap = ap->a_vap;
67525e99827Sdillo 	vp = ap->a_vp;
67625e99827Sdillo 
67725e99827Sdillo 	/*
67825e99827Sdillo 	 * Check for unsettable attributes.
67925e99827Sdillo 	 */
68025e99827Sdillo 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
68125e99827Sdillo 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
68225e99827Sdillo 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
68325e99827Sdillo 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
68425e99827Sdillo 		return EINVAL;
68525e99827Sdillo 	}
68625e99827Sdillo 
68725e99827Sdillo 	/* XXX: needs revisiting for write support */
68825e99827Sdillo 	if (vap->va_flags != VNOVAL
68925e99827Sdillo 	    || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
69025e99827Sdillo 	    || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
69125e99827Sdillo 	    || vap->va_birthtime.tv_sec != VNOVAL) {
69225e99827Sdillo 		return EROFS;
69325e99827Sdillo 	}
69425e99827Sdillo 
69525e99827Sdillo 	if (vap->va_size != VNOVAL) {
69625e99827Sdillo 		/*
69725e99827Sdillo 		 * Disallow write attempts on read-only file systems;
69825e99827Sdillo 		 * unless the file is a socket, fifo, or a block or
69925e99827Sdillo 		 * character device resident on the file system.
70025e99827Sdillo 		 */
70125e99827Sdillo 		switch (vp->v_type) {
70225e99827Sdillo 		case VDIR:
70325e99827Sdillo 			return EISDIR;
70425e99827Sdillo 		case VCHR:
70525e99827Sdillo 		case VBLK:
70625e99827Sdillo 		case VFIFO:
70725e99827Sdillo 			break;
70825e99827Sdillo 		case VREG:
70925e99827Sdillo 			return EROFS;
71025e99827Sdillo 		default:
71125e99827Sdillo 			return EOPNOTSUPP;
71225e99827Sdillo 		}
71325e99827Sdillo 	}
71425e99827Sdillo 
71525e99827Sdillo 	return 0;
71625e99827Sdillo }
71725e99827Sdillo 
71825e99827Sdillo int
hfs_vop_bmap(void * v)71956c3e412Sdillo hfs_vop_bmap(void *v)
72025e99827Sdillo {
72125e99827Sdillo 	struct vop_bmap_args /* {
72225e99827Sdillo 		struct vnode *a_vp;
72325e99827Sdillo 		daddr_t  a_bn;
72425e99827Sdillo 		struct vnode **a_vpp;
72525e99827Sdillo 		daddr_t *a_bnp;
72625e99827Sdillo 		int *a_runp;
72725e99827Sdillo 	} */ *ap = v;
72825e99827Sdillo 	struct vnode *vp;
72956c3e412Sdillo 	struct hfsnode *hp;
73025e99827Sdillo 	daddr_t lblkno;
73156c3e412Sdillo 	hfs_callback_args cbargs;
73256c3e412Sdillo 	hfs_libcb_argsread argsread;
73356c3e412Sdillo 	hfs_extent_descriptor_t *extents;
73425e99827Sdillo 	uint16_t numextents, i;
73525e99827Sdillo 	int bshift;
73625e99827Sdillo 
73725e99827Sdillo 	vp = ap->a_vp;
73825e99827Sdillo 	hp = VTOH(vp);
73925e99827Sdillo 	lblkno = ap->a_bn;
74025e99827Sdillo 	bshift = vp->v_mount->mnt_fs_bshift;
74125e99827Sdillo 
74225e99827Sdillo 	/*
74325e99827Sdillo 	 * Check for underlying vnode requests and ensure that logical
74425e99827Sdillo 	 * to physical mapping is requested.
74525e99827Sdillo 	 */
74625e99827Sdillo 	if (ap->a_vpp != NULL)
74725e99827Sdillo 		*ap->a_vpp = hp->h_devvp;
74825e99827Sdillo 	if (ap->a_bnp == NULL)
7497b5e4e85Schristos 		return 0;
75025e99827Sdillo 
75156c3e412Sdillo 	hfslib_init_cbargs(&cbargs);
75225e99827Sdillo 	argsread.cred = NULL;
75325e99827Sdillo 	argsread.l = NULL;
75425e99827Sdillo 	cbargs.read = &argsread;
75525e99827Sdillo 
75656c3e412Sdillo 	numextents = hfslib_get_file_extents(&hp->h_hmp->hm_vol,
75736a81a3bSgmcgarry 	    hp->h_rec.u.cnid, hp->h_fork, &extents, &cbargs);
75825e99827Sdillo 
75925e99827Sdillo 	/* XXX: is this correct for 0-length files? */
76025e99827Sdillo 	if (numextents == 0)
76125e99827Sdillo 		return EBADF;
76225e99827Sdillo 
76325e99827Sdillo 	for (i = 0; i < numextents; i++) {
76425e99827Sdillo 		if (lblkno < extents[i].block_count)
76525e99827Sdillo 			break;
76625e99827Sdillo 		lblkno -= extents[i].block_count;
76725e99827Sdillo 	}
76825e99827Sdillo 
76925e99827Sdillo 	if (i == numextents) {
77025e99827Sdillo 		/* XXX: block number past EOF */
77125e99827Sdillo 		i--;
77225e99827Sdillo 		lblkno += extents[i].block_count;
77325e99827Sdillo 	}
77425e99827Sdillo 
7757b5e4e85Schristos 	*ap->a_bnp = ((extents[i].start_block + lblkno) << (bshift-DEV_BSHIFT))
77641627b2cSdillo 	    + (hp->h_hmp->hm_vol.offset >> DEV_BSHIFT);
77725e99827Sdillo 
77825e99827Sdillo 	if (ap->a_runp) {
77925e99827Sdillo 		int nblk;
78025e99827Sdillo 
78125e99827Sdillo 		nblk = extents[i].block_count - lblkno - 1;
78225e99827Sdillo 		if (nblk <= 0)
78325e99827Sdillo 			*ap->a_runp = 0;
78425e99827Sdillo 		else if (nblk > MAXBSIZE >> bshift)
78525e99827Sdillo 			*ap->a_runp = (MAXBSIZE >> bshift) - 1;
78625e99827Sdillo 		else
78725e99827Sdillo 			*ap->a_runp = nblk;
78825e99827Sdillo 	}
78925e99827Sdillo 
7907b5e4e85Schristos 	free(extents, M_TEMP);
79125e99827Sdillo 
79225e99827Sdillo 	return 0;
79325e99827Sdillo }
79425e99827Sdillo 
79525e99827Sdillo int
hfs_vop_read(void * v)79656c3e412Sdillo hfs_vop_read(void *v)
79725e99827Sdillo {
79825e99827Sdillo 	struct vop_read_args /* {
79925e99827Sdillo 		struct vnode *a_vp;
80025e99827Sdillo 		struct uio *a_uio;
80125e99827Sdillo 		int a_ioflag;
80225e99827Sdillo 		kauth_cred_t a_cred;
80325e99827Sdillo 	} */ *ap = v;
80425e99827Sdillo 	struct vnode *vp;
80556c3e412Sdillo 	struct hfsnode *hp;
80625e99827Sdillo 	struct uio *uio;
80725e99827Sdillo 	uint64_t fsize; /* logical size of file */
80825e99827Sdillo 	int advice;
80925e99827Sdillo 	int error;
81025e99827Sdillo 
81125e99827Sdillo 	vp = ap->a_vp;
81225e99827Sdillo 	hp = VTOH(vp);
81325e99827Sdillo 	uio = ap->a_uio;
81456c3e412Sdillo 	if (hp->h_fork == HFS_RSRCFORK)
81525e99827Sdillo 		fsize = hp->h_rec.file.rsrc_fork.logical_size;
81625e99827Sdillo 	else
81725e99827Sdillo 		fsize = hp->h_rec.file.data_fork.logical_size;
81825e99827Sdillo 	error = 0;
81925e99827Sdillo 	advice = IO_ADV_DECODE(ap->a_ioflag);
82025e99827Sdillo 
82125e99827Sdillo 	if (uio->uio_offset < 0)
82225e99827Sdillo 		return EINVAL;
82325e99827Sdillo 
82425e99827Sdillo 	if (uio->uio_resid == 0 || uio->uio_offset >= fsize)
82525e99827Sdillo 		return 0;
82625e99827Sdillo 
82725e99827Sdillo 	if (vp->v_type != VREG && vp->v_type != VLNK)
82825e99827Sdillo 		return EINVAL;
82925e99827Sdillo 
83025e99827Sdillo 	error = 0;
83125e99827Sdillo 	while (uio->uio_resid > 0 && error == 0) {
83225e99827Sdillo 		vsize_t len;
83325e99827Sdillo 
83425e99827Sdillo 		len = MIN(uio->uio_resid, fsize - uio->uio_offset);
83525e99827Sdillo 		if (len == 0)
83625e99827Sdillo 			break;
83725e99827Sdillo 
838b4099c3eSpooka 		error = ubc_uiomove(&vp->v_uobj, uio, len, advice,
839f5ad84fdSad 		    UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
84025e99827Sdillo 	}
84125e99827Sdillo 
84225e99827Sdillo 	return error;
84325e99827Sdillo }
84425e99827Sdillo 
84525e99827Sdillo int
hfs_vop_readdir(void * v)84656c3e412Sdillo hfs_vop_readdir(void *v)
84725e99827Sdillo {
84825e99827Sdillo 	struct vop_readdir_args /* {
84925e99827Sdillo 		struct vnode *a_vp;
85025e99827Sdillo 		struct uio *a_uio;
85125e99827Sdillo 		kauth_cred_t a_cred;
85225e99827Sdillo 		int *a_eofflag;
85325e99827Sdillo 		off_t **a_cookies;
85425e99827Sdillo 		int a_*ncookies;
85525e99827Sdillo 	} */ *ap = v;
85625e99827Sdillo 
8577b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_readdir()\n"));
85825e99827Sdillo 
8597b5e4e85Schristos 	struct dirent curent; /* the dirent entry we are constructing */
86056c3e412Sdillo 	struct hfsnode *hp;
86156c3e412Sdillo 	hfs_catalog_keyed_record_t *children;
86256c3e412Sdillo 	hfs_unistr255_t *childnames;
86356c3e412Sdillo 	hfs_callback_args cbargs;
86456c3e412Sdillo 	hfs_libcb_argsread argsread;
86525e99827Sdillo 	struct uio *uio;
8667b5e4e85Schristos 	off_t bufoff; /* offset in buffer relative to start of dirents */
86725e99827Sdillo 	uint32_t numchildren;
8687b5e4e85Schristos 	uint32_t curchild; /* index of child we are stuffing into dirent */
86902c89a86Schristos 	size_t namlen, ni;
87025e99827Sdillo 	int error;
87125e99827Sdillo 	int i; /* dummy variable */
87225e99827Sdillo 
87325e99827Sdillo 	bufoff = 0;
87425e99827Sdillo 	children = NULL;
87525e99827Sdillo 	error = 0;
87625e99827Sdillo 	numchildren = 0;
87725e99827Sdillo 	hp = VTOH(ap->a_vp);
87825e99827Sdillo 	uio = ap->a_uio;
87925e99827Sdillo 
88025e99827Sdillo 	if (uio->uio_offset < 0)
88125e99827Sdillo 		return EINVAL;
88225e99827Sdillo 	if (ap->a_eofflag != NULL)
88325e99827Sdillo 		*ap->a_eofflag = 0;
88425e99827Sdillo 
88525e99827Sdillo /* XXX Inform that we don't support NFS, for now. */
8867b5e4e85Schristos #if 0
8877b5e4e85Schristos 	if(ap->a_eofflag != NULL || ap->a_cookies != NULL ||
8887b5e4e85Schristos 	    ap->a_ncookies != NULL)
8897b5e4e85Schristos 		return EOPNOTSUPP;
8907b5e4e85Schristos #endif
8917b5e4e85Schristos 	DPRINTF(("READDIR uio: offset=%td, resid=%zu\n",
8927b5e4e85Schristos 	    uio->uio_offset, uio->uio_resid));
89356c3e412Sdillo 	hfslib_init_cbargs(&cbargs);
89425e99827Sdillo 	argsread.cred = ap->a_cred;
89525e99827Sdillo 	argsread.l = NULL;
89625e99827Sdillo 	cbargs.read = &argsread;
89725e99827Sdillo 
89825e99827Sdillo 	/* XXX Should we cache this? */
89936a81a3bSgmcgarry 	if (hfslib_get_directory_contents(&hp->h_hmp->hm_vol, hp->h_rec.u.cnid,
90025e99827Sdillo 	    &children, &childnames, &numchildren, &cbargs) != 0) {
9017b5e4e85Schristos 		DPRINTF(("ENOENT\n"));
90225e99827Sdillo 		error = ENOENT;
90325e99827Sdillo 		goto error;
90425e99827Sdillo 	}
90525e99827Sdillo 
9067b5e4e85Schristos 	DPRINTF(("numchildren = %u\n", numchildren));
9077b5e4e85Schristos 	for (curchild = 0; curchild < numchildren && uio->uio_resid > 0;
9087b5e4e85Schristos 	    curchild++) {
909d3002142Schristos 		namlen = utf16_to_utf8(curent.d_name, NAME_MAX,
9107b5e4e85Schristos 		    childnames[curchild].unicode, childnames[curchild].length,
91125e99827Sdillo 		    0, NULL);
91225e99827Sdillo 		/* XXX: check conversion errors? */
913d3002142Schristos 		if (namlen > NAME_MAX) {
91425e99827Sdillo 			/* XXX: how to handle name too long? */
91525e99827Sdillo 			continue;
91625e99827Sdillo 		}
91702c89a86Schristos 		for (ni = 0; ni < namlen; ni++)
91802c89a86Schristos 			if (curent.d_name[ni] == '/')
91902c89a86Schristos 				curent.d_name[ni] = ':';
92025e99827Sdillo 		curent.d_namlen = namlen;
92125e99827Sdillo 		curent.d_reclen = _DIRENT_SIZE(&curent);
92225e99827Sdillo 
92325e99827Sdillo 		/* Skip to desired dirent. */
9247b5e4e85Schristos 		bufoff += curent.d_reclen;
9257b5e4e85Schristos 		if (bufoff - curent.d_reclen < uio->uio_offset)
92625e99827Sdillo 			continue;
92725e99827Sdillo 
92825e99827Sdillo 		/* Make sure we don't return partial entries. */
92925e99827Sdillo 		if (uio->uio_resid < curent.d_reclen) {
9307b5e4e85Schristos 			DPRINTF(("PARTIAL ENTRY\n"));
93125e99827Sdillo 			if (ap->a_eofflag != NULL)
93225e99827Sdillo 				*ap->a_eofflag = 1;
93325e99827Sdillo 			break;
93425e99827Sdillo 		}
93525e99827Sdillo 
93625e99827Sdillo 		curent.d_fileno = children[curchild].file.cnid;
93756c3e412Sdillo 		switch (hfs_catalog_keyed_record_vtype(children+curchild)) {
93825e99827Sdillo 		case VREG:
93925e99827Sdillo 			curent.d_type = DT_REG;
94025e99827Sdillo 			break;
94125e99827Sdillo 		case VDIR:
94225e99827Sdillo 			curent.d_type = DT_DIR;
94325e99827Sdillo 			break;
94425e99827Sdillo 		case VBLK:
94525e99827Sdillo 			curent.d_type = DT_BLK;
94625e99827Sdillo 			break;
94725e99827Sdillo 		case VCHR:
94825e99827Sdillo 			curent.d_type = DT_CHR;
94925e99827Sdillo 			break;
95025e99827Sdillo 		case VLNK:
95125e99827Sdillo 			curent.d_type = DT_LNK;
95225e99827Sdillo 			break;
95325e99827Sdillo 		case VSOCK:
95425e99827Sdillo 			curent.d_type = DT_SOCK;
95525e99827Sdillo 			break;
95625e99827Sdillo 		case VFIFO:
95725e99827Sdillo 			curent.d_type = DT_FIFO;
95825e99827Sdillo 			break;
95925e99827Sdillo 		default:
96025e99827Sdillo 			curent.d_type = DT_UNKNOWN;
96125e99827Sdillo 			break;
96225e99827Sdillo 		}
9637b5e4e85Schristos 		DPRINTF(("curchildname = %s\t\t", curchildname));
96425e99827Sdillo 		/* pad curent.d_name to aligned byte boundary */
96525e99827Sdillo 		for (i = curent.d_namlen;
96625e99827Sdillo 		    i < curent.d_reclen - _DIRENT_NAMEOFF(&curent); i++)
96725e99827Sdillo 			curent.d_name[i] = 0;
96825e99827Sdillo 
9697b5e4e85Schristos 		DPRINTF(("curent.d_name = %s\n", curent.d_name));
97025e99827Sdillo 
97125e99827Sdillo 		if ((error = uiomove(&curent, curent.d_reclen, uio)) != 0)
97225e99827Sdillo 			goto error;
97325e99827Sdillo 	}
97425e99827Sdillo 
97525e99827Sdillo 	/* FALLTHROUGH */
97625e99827Sdillo 
97725e99827Sdillo error:
97825e99827Sdillo 	if (numchildren > 0) {
97925e99827Sdillo 		if (children != NULL)
98025e99827Sdillo 			free(children, M_TEMP);
98125e99827Sdillo 		if (childnames != NULL)
98225e99827Sdillo 			free(childnames, M_TEMP);
98325e99827Sdillo 	}
98425e99827Sdillo 
985f9880b21Sjakllsch 	if (error) {
9867b5e4e85Schristos 		DPRINTF(("ERROR = %i\n", error));
987f9880b21Sjakllsch 	}
988f9880b21Sjakllsch 
98925e99827Sdillo 	return error;
99025e99827Sdillo }
99125e99827Sdillo 
99225e99827Sdillo int
hfs_vop_readlink(void * v)99356c3e412Sdillo hfs_vop_readlink(void *v) {
99425e99827Sdillo 	struct vop_readlink_args /* {
99525e99827Sdillo 		struct vnode *a_vp;
99625e99827Sdillo 		struct uio *a_uio;
99725e99827Sdillo 		kauth_cred_t a_cred;
99825e99827Sdillo 	} */ *ap = v;
99925e99827Sdillo 
100025e99827Sdillo 	return VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
100125e99827Sdillo }
100225e99827Sdillo 
100325e99827Sdillo int
hfs_vop_reclaim(void * v)100456c3e412Sdillo hfs_vop_reclaim(void *v)
100525e99827Sdillo {
10067f7aad09Sriastradh 	struct vop_reclaim_v2_args /* {
100725e99827Sdillo 		struct vnode *a_vp;
100825e99827Sdillo 	} */ *ap = v;
100925e99827Sdillo 	struct vnode *vp;
101056c3e412Sdillo 	struct hfsnode *hp;
101125e99827Sdillo 
10127f7aad09Sriastradh 	VOP_UNLOCK(ap->a_vp);
10137f7aad09Sriastradh 
10147b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_reclaim()\n"));
101525e99827Sdillo 
101625e99827Sdillo 	vp = ap->a_vp;
101725e99827Sdillo 	hp = VTOH(vp);
101825e99827Sdillo 
101925e99827Sdillo 	/* Decrement the reference count to the volume's device. */
102025e99827Sdillo 	if (hp->h_devvp) {
102125e99827Sdillo 		vrele(hp->h_devvp);
102225e99827Sdillo 		hp->h_devvp = 0;
102325e99827Sdillo 	}
102425e99827Sdillo 
102525e99827Sdillo 	genfs_node_destroy(vp);
1026265f1d8cShannken 	pool_put(&hfs_node_pool, hp);
10274a4e5251Srmind 	vp->v_data = NULL;
102825e99827Sdillo 
102925e99827Sdillo 	return 0;
103025e99827Sdillo }
103125e99827Sdillo 
103225e99827Sdillo int
hfs_vop_print(void * v)103356c3e412Sdillo hfs_vop_print(void *v)
103425e99827Sdillo {
103525e99827Sdillo 	struct vop_print_args /* {
103625e99827Sdillo 		struct vnode	*a_vp;
103725e99827Sdillo 	} */ *ap = v;
103825e99827Sdillo 	struct vnode	*vp;
103956c3e412Sdillo 	struct hfsnode	*hp;
104025e99827Sdillo 
10417b5e4e85Schristos 	DPRINTF(("VOP = hfs_vop_print()\n"));
104225e99827Sdillo 
104325e99827Sdillo 	vp = ap->a_vp;
104425e99827Sdillo 	hp = VTOH(vp);
104525e99827Sdillo 
104625e99827Sdillo 	printf("dummy = %X\n", (unsigned)hp->dummy);
104725e99827Sdillo 	printf("\n");
104825e99827Sdillo 
104925e99827Sdillo 	return 0;
105025e99827Sdillo }
1051