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