1 /* $NetBSD: hfs_vnops.c,v 1.24 2011/09/27 01:14:47 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Yevgeny Binder and Dieter Baron. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1992, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software donated to Berkeley by 37 * Jan-Simon Pendry. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 /* 65 * Copyright (c) 1982, 1986, 1989, 1993, 1995 66 * The Regents of the University of California. All rights reserved. 67 * (c) UNIX System Laboratories, Inc. 68 * All or some portions of this file are derived from material licensed 69 * to the University of California by American Telephone and Telegraph 70 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 71 * the permission of UNIX System Laboratories, Inc. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 1. Redistributions of source code must retain the above copyright 77 * notice, this list of conditions and the following disclaimer. 78 * 2. Redistributions in binary form must reproduce the above copyright 79 * notice, this list of conditions and the following disclaimer in the 80 * documentation and/or other materials provided with the distribution. 81 * 3. Neither the name of the University nor the names of its contributors 82 * may be used to endorse or promote products derived from this software 83 * without specific prior written permission. 84 * 85 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 86 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 87 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 88 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 89 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 90 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 91 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 92 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 93 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 94 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 95 * SUCH DAMAGE. 96 */ 97 98 99 /* 100 * Apple HFS+ filesystem 101 */ 102 103 #include <sys/cdefs.h> 104 __KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.24 2011/09/27 01:14:47 christos Exp $"); 105 106 #ifdef _KERNEL_OPT 107 #include "opt_ipsec.h" 108 #endif 109 110 #include <sys/param.h> 111 #include <sys/systm.h> 112 #include <sys/kernel.h> 113 #include <sys/vmmeter.h> 114 #include <sys/time.h> 115 #include <sys/proc.h> 116 #include <sys/vnode.h> 117 #include <sys/malloc.h> 118 #include <sys/file.h> 119 #include <sys/stat.h> 120 #include <sys/mount.h> 121 #include <sys/namei.h> 122 #include <sys/buf.h> 123 #include <sys/dirent.h> 124 #include <sys/msgbuf.h> 125 126 #include <miscfs/fifofs/fifo.h> 127 #include <miscfs/specfs/specdev.h> 128 129 #include <fs/hfs/hfs.h> 130 #include <fs/hfs/unicode.h> 131 132 #include <miscfs/genfs/genfs.h> 133 134 int hfs_vop_lookup(void *); 135 int hfs_vop_open(void *); 136 int hfs_vop_close(void *); 137 int hfs_vop_access(void *); 138 int hfs_vop_getattr(void *); 139 int hfs_vop_setattr(void *); 140 int hfs_vop_bmap(void *); 141 int hfs_vop_read(void *); 142 int hfs_vop_readdir(void *); 143 int hfs_vop_readlink(void *); 144 int hfs_vop_reclaim(void *); 145 int hfs_vop_print(void *); 146 147 #ifdef HFS_DEBUG 148 #define DPRINTF(a) printf a 149 #else 150 #define DPRINTF(a) 151 #endif 152 153 154 int (**hfs_vnodeop_p) (void *); 155 const struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { 156 { &vop_default_desc, vn_default_error }, 157 { &vop_lookup_desc, hfs_vop_lookup }, /* lookup */ 158 { &vop_create_desc, genfs_eopnotsupp }, /* create */ 159 { &vop_whiteout_desc, genfs_eopnotsupp }, /* whiteout */ 160 { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ 161 { &vop_open_desc, hfs_vop_open }, /* open */ 162 { &vop_close_desc, hfs_vop_close }, /* close */ 163 { &vop_access_desc, hfs_vop_access }, /* access */ 164 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 165 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 166 { &vop_read_desc, hfs_vop_read }, /* read */ 167 { &vop_write_desc, genfs_eopnotsupp }, /* write */ 168 { &vop_ioctl_desc, genfs_eopnotsupp }, /* ioctl */ 169 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 170 { &vop_poll_desc, genfs_eopnotsupp }, /* poll */ 171 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 172 { &vop_revoke_desc, genfs_eopnotsupp }, /* revoke */ 173 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 174 { &vop_fsync_desc, genfs_nullop }, /* fsync */ 175 { &vop_seek_desc, genfs_seek }, /* seek */ 176 { &vop_remove_desc, genfs_eopnotsupp }, /* remove */ 177 { &vop_link_desc, genfs_eopnotsupp }, /* link */ 178 { &vop_rename_desc, genfs_eopnotsupp }, /* rename */ 179 { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */ 180 { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */ 181 { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */ 182 { &vop_readdir_desc, hfs_vop_readdir }, /* readdir */ 183 { &vop_readlink_desc, hfs_vop_readlink }, /* readlink */ 184 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 185 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 186 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 187 { &vop_lock_desc, genfs_lock }, /* lock */ 188 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 189 { &vop_bmap_desc, hfs_vop_bmap }, /* bmap */ 190 { &vop_strategy_desc, genfs_eopnotsupp }, /* strategy */ 191 { &vop_print_desc, hfs_vop_print }, /* print */ 192 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 193 { &vop_pathconf_desc, genfs_eopnotsupp }, /* pathconf */ 194 { &vop_advlock_desc, genfs_eopnotsupp }, /* advlock */ 195 { &vop_bwrite_desc, genfs_eopnotsupp }, /* bwrite */ 196 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 197 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 198 { &vop_openextattr_desc, genfs_eopnotsupp }, /* openextattr */ 199 { &vop_closeextattr_desc, genfs_eopnotsupp }, /* closeextattr */ 200 { &vop_getextattr_desc, genfs_eopnotsupp }, /* getextattr */ 201 { &vop_setextattr_desc, genfs_eopnotsupp }, /* setextattr */ 202 { &vop_listextattr_desc, genfs_eopnotsupp }, /* listextattr */ 203 { &vop_deleteextattr_desc, genfs_eopnotsupp }, /* deleteextattr */ 204 { NULL, NULL } 205 }; 206 const struct vnodeopv_desc hfs_vnodeop_opv_desc = 207 { &hfs_vnodeop_p, hfs_vnodeop_entries }; 208 209 int (**hfs_specop_p) (void *); 210 const struct vnodeopv_entry_desc hfs_specop_entries[] = { 211 { &vop_default_desc, vn_default_error }, 212 { &vop_lookup_desc, spec_lookup }, /* lookup */ 213 { &vop_create_desc, spec_create }, /* create */ 214 { &vop_mknod_desc, spec_mknod }, /* mknod */ 215 { &vop_open_desc, spec_open }, /* open */ 216 { &vop_close_desc, spec_close }, /* close */ 217 { &vop_access_desc, hfs_vop_access }, /* access */ 218 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 219 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 220 { &vop_read_desc, spec_read }, /* read */ 221 { &vop_write_desc, spec_write }, /* write */ 222 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 223 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 224 { &vop_poll_desc, spec_poll }, /* poll */ 225 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 226 { &vop_revoke_desc, spec_revoke }, /* revoke */ 227 { &vop_mmap_desc, spec_mmap }, /* mmap */ 228 { &vop_fsync_desc, spec_fsync }, /* fsync */ 229 { &vop_seek_desc, spec_seek }, /* seek */ 230 { &vop_remove_desc, spec_remove }, /* remove */ 231 { &vop_link_desc, spec_link }, /* link */ 232 { &vop_rename_desc, spec_rename }, /* rename */ 233 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 234 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 235 { &vop_symlink_desc, spec_symlink }, /* symlink */ 236 { &vop_readdir_desc, spec_readdir }, /* readdir */ 237 { &vop_readlink_desc, spec_readlink }, /* readlink */ 238 { &vop_abortop_desc, spec_abortop }, /* abortop */ 239 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 240 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 241 { &vop_lock_desc, genfs_lock }, /* lock */ 242 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 243 { &vop_bmap_desc, spec_bmap }, /* bmap */ 244 { &vop_strategy_desc, spec_strategy }, /* strategy */ 245 { &vop_print_desc, hfs_vop_print }, /* print */ 246 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 247 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 248 { &vop_advlock_desc, spec_advlock }, /* advlock */ 249 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 250 { &vop_getpages_desc, spec_getpages }, /* getpages */ 251 { &vop_putpages_desc, spec_putpages }, /* putpages */ 252 #if 0 253 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 254 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 255 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 256 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 257 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 258 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 259 #endif 260 { NULL, NULL } 261 }; 262 const struct vnodeopv_desc hfs_specop_opv_desc = 263 { &hfs_specop_p, hfs_specop_entries }; 264 265 int (**hfs_fifoop_p) (void *); 266 const struct vnodeopv_entry_desc hfs_fifoop_entries[] = { 267 { &vop_default_desc, vn_default_error }, 268 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ 269 { &vop_create_desc, vn_fifo_bypass }, /* create */ 270 { &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ 271 { &vop_open_desc, vn_fifo_bypass }, /* open */ 272 { &vop_close_desc, vn_fifo_bypass }, /* close */ 273 { &vop_access_desc, hfs_vop_access }, /* access */ 274 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 275 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 276 { &vop_read_desc, vn_fifo_bypass }, /* read */ 277 { &vop_write_desc, vn_fifo_bypass }, /* write */ 278 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ 279 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 280 { &vop_poll_desc, vn_fifo_bypass }, /* poll */ 281 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ 282 { &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ 283 { &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ 284 { &vop_fsync_desc, vn_fifo_bypass }, /* fsync */ 285 { &vop_seek_desc, vn_fifo_bypass }, /* seek */ 286 { &vop_remove_desc, vn_fifo_bypass }, /* remove */ 287 { &vop_link_desc, vn_fifo_bypass }, /* link */ 288 { &vop_rename_desc, vn_fifo_bypass }, /* rename */ 289 { &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ 290 { &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ 291 { &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ 292 { &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ 293 { &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ 294 { &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ 295 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 296 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 297 { &vop_lock_desc, genfs_lock }, /* lock */ 298 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 299 { &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ 300 { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 301 { &vop_print_desc, hfs_vop_print }, /* print */ 302 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 303 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ 304 { &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ 305 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 306 { &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ 307 #if 0 308 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 309 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 310 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 311 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 312 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 313 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 314 #endif 315 { NULL, NULL } 316 }; 317 const struct vnodeopv_desc hfs_fifoop_opv_desc = 318 { &hfs_fifoop_p, hfs_fifoop_entries }; 319 320 int 321 hfs_vop_lookup(void *v) 322 { 323 struct vop_lookup_args /* { 324 struct vnode * a_dvp; 325 struct vnode ** a_vpp; 326 struct componentname * a_cnp; 327 } */ *ap = v; 328 struct buf *bp; /* a buffer of directory entries */ 329 struct componentname *cnp; 330 struct hfsnode *dp; /* hfsnode for directory being searched */ 331 kauth_cred_t cred; 332 struct vnode **vpp; /* resultant vnode */ 333 struct vnode *pdp; /* saved dp during symlink work */ 334 struct vnode *tdp; /* returned by VFS_VGET */ 335 struct vnode *vdp; /* vnode for directory being searched */ 336 hfs_catalog_key_t key; /* hfs+ catalog search key for requested child */ 337 hfs_catalog_keyed_record_t rec; /* catalog record of requested child */ 338 unichar_t* unicn; /* name of component, in Unicode */ 339 const char *pname; 340 int error; 341 int flags; 342 int result; /* result of libhfs operations */ 343 344 DPRINTF(("VOP = hfs_vop_lookup()\n")); 345 346 bp = NULL; 347 cnp = ap->a_cnp; 348 cred = cnp->cn_cred; 349 vdp = ap->a_dvp; 350 dp = VTOH(vdp); 351 error = 0; 352 pname = cnp->cn_nameptr; 353 result = 0; 354 unicn = NULL; 355 vpp = ap->a_vpp; 356 *vpp = NULL; 357 358 flags = cnp->cn_flags; 359 360 361 /* 362 * Check accessiblity of directory. 363 */ 364 if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0) 365 return error; 366 367 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 368 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 369 return EROFS; 370 371 /* 372 * We now have a segment name to search for, and a directory to search. 373 * 374 * Before tediously performing a linear scan of the directory, 375 * check the name cache to see if the directory/name pair 376 * we are looking for is known already. 377 */ 378 /* XXX Cache disabled until we can make sure it works. */ 379 #if 0 380 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) 381 return error; 382 #endif 383 384 385 #if 0 386 if (cnp->cn_namelen == 1 && *pname == '.') { 387 *vpp = vdp; 388 vref(vdp); 389 return 0; 390 } 391 #endif 392 393 pdp = vdp; 394 if (flags & ISDOTDOT) { 395 DPRINTF(("DOTDOT ")); 396 VOP_UNLOCK(pdp); /* race to get the inode */ 397 error = VFS_VGET(vdp->v_mount, dp->h_parent, &tdp); 398 vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 399 if (error != 0) 400 goto error; 401 *vpp = tdp; 402 #if 0 403 } else if (dp->h_rec.u.cnid == rec.file.u.cnid) { 404 #endif 405 } else if (cnp->cn_namelen == 1 && pname[0] == '.') { 406 DPRINTF(("DOT ")); 407 vref(vdp); /* we want ourself, ie "." */ 408 *vpp = vdp; 409 } else { 410 hfs_callback_args cbargs; 411 uint8_t len, ni; 412 413 hfslib_init_cbargs(&cbargs); 414 415 /* XXX: when decomposing, string could grow 416 and we have to handle overflow */ 417 unicn = malloc(cnp->cn_namelen * sizeof(unicn[0]), 418 M_TEMP, M_WAITOK); 419 len = utf8_to_utf16(unicn, cnp->cn_namelen, 420 cnp->cn_nameptr, cnp->cn_namelen, 0, NULL); 421 for (ni = 0; ni < len; ni++) 422 if (unicn[ni] == (unichar_t)':') 423 unicn[ni] = (unichar_t)'/'; 424 /* XXX: check conversion errors? */ 425 if (hfslib_make_catalog_key(VTOH(vdp)->h_rec.u.cnid, len, unicn, 426 &key) == 0) { 427 DPRINTF(("ERROR in hfslib_make_catalog_key\n")); 428 error = EINVAL; 429 goto error; 430 } 431 432 result = hfslib_find_catalog_record_with_key(&dp->h_hmp->hm_vol, 433 &key, &rec, &cbargs); 434 if (result > 0) { 435 error = EINVAL; 436 goto error; 437 } 438 if (result < 0) { 439 if (cnp->cn_nameiop == CREATE) 440 error = EROFS; 441 else 442 error = ENOENT; 443 goto error; 444 } 445 446 if (rec.file.user_info.file_type == HFS_HARD_LINK_FILE_TYPE 447 && rec.file.user_info.file_creator == HFS_HFSLUS_CREATOR) { 448 if (hfslib_get_hardlink(&dp->h_hmp->hm_vol, 449 rec.file.bsd.special.inode_num, 450 &rec, &cbargs) != 0) { 451 error = EINVAL; 452 goto error; 453 } 454 } 455 456 if (rec.type == HFS_REC_FILE 457 && strcmp(cnp->cn_nameptr+cnp->cn_namelen, "/rsrc") == 0 458 && rec.file.rsrc_fork.logical_size > 0) { 459 /* advance namei next pointer to end of stirng */ 460 cnp->cn_consume = 5; 461 cnp->cn_flags &= ~REQUIREDIR; /* XXX: needed? */ 462 error = hfs_vget_internal(vdp->v_mount, rec.file.cnid, 463 HFS_RSRCFORK, &tdp); 464 } 465 else 466 error = VFS_VGET(vdp->v_mount, rec.file.cnid, &tdp); 467 if (error != 0) 468 goto error; 469 *vpp = tdp; 470 } 471 DPRINTF(("\n")); 472 /* 473 * Insert name into cache if appropriate. 474 */ 475 /* XXX Cache disabled until we can make sure it works. */ 476 #if 0 477 if (cnp->cn_flags & MAKEENTRY) 478 cache_enter(vdp, *vpp, cnp); 479 #endif 480 481 error = 0; 482 483 /* FALLTHROUGH */ 484 error: 485 if (unicn != NULL) 486 free(unicn, M_TEMP); 487 488 return error; 489 } 490 491 int 492 hfs_vop_open(void *v) 493 { 494 #if 0 495 struct vop_open_args /* { 496 struct vnode *a_vp; 497 int a_mode; 498 kauth_cred_t a_cred; 499 } */ *ap = v; 500 struct hfsnode *hn = VTOH(ap->a_vp); 501 #endif 502 DPRINTF(("VOP = hfs_vop_open()\n")); 503 504 /* 505 * XXX This is a good place to read and cache the file's extents to 506 * XXX avoid doing it upon every read/write. Must however keep the 507 * XXX cache in sync when the file grows/shrinks. (So would that go 508 * XXX in vop_truncate?) 509 */ 510 511 return 0; 512 } 513 514 int 515 hfs_vop_close(void *v) 516 { 517 #if 0 518 struct vop_close_args /* { 519 struct vnode *a_vp; 520 int a_fflag; 521 kauth_cred_t a_cred; 522 } */ *ap = v; 523 struct hfsnode *hn = VTOH(ap->a_vp); 524 #endif 525 DPRINTF(("VOP = hfs_vop_close()\n")); 526 527 /* Release extents cache here. */ 528 529 return 0; 530 } 531 532 static int 533 hfs_check_possible(struct vnode *vp, mode_t mode) 534 { 535 536 /* 537 * Disallow writes on files, directories, and symlinks 538 * since we have no write support yet. 539 */ 540 541 if (mode & VWRITE) { 542 switch (vp->v_type) { 543 case VDIR: 544 case VLNK: 545 case VREG: 546 return EROFS; 547 default: 548 break; 549 } 550 } 551 552 return 0; 553 } 554 555 static int 556 hfs_check_permitted(struct vattr *va, mode_t mode, kauth_cred_t cred) 557 { 558 559 return genfs_can_access(va->va_type, va->va_mode, va->va_uid, 560 va->va_gid, mode, cred); 561 } 562 563 int 564 hfs_vop_access(void *v) 565 { 566 struct vop_access_args /* { 567 struct vnode *a_vp; 568 int a_mode; 569 kauth_cred_t a_cred; 570 } */ *ap = v; 571 struct vattr va; 572 int error; 573 574 DPRINTF(("VOP = hfs_vop_access()\n")); 575 576 error = hfs_check_possible(ap->a_vp, ap->a_mode); 577 if (error) 578 return error; 579 580 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0) 581 return error; 582 583 error = hfs_check_permitted(&va, ap->a_mode, ap->a_cred); 584 585 return error; 586 } 587 588 int 589 hfs_vop_getattr(void *v) 590 { 591 struct vop_getattr_args /* { 592 struct vnode *a_vp; 593 struct vattr *a_vap; 594 struct ucred *a_cred; 595 } */ *ap = v; 596 struct vnode *vp; 597 struct hfsnode *hp; 598 struct vattr *vap; 599 hfs_bsd_data_t *bsd; 600 hfs_fork_t *fork; 601 602 DPRINTF(("VOP = hfs_vop_getattr()\n")); 603 604 vp = ap->a_vp; 605 hp = VTOH(vp); 606 vap = ap->a_vap; 607 608 vattr_null(vap); 609 610 /* 611 * XXX Cannot trust permissions/modes/flags stored in an HFS+ catalog 612 * XXX record those values are not set on files created under Mac OS 9. 613 */ 614 vap->va_type = ap->a_vp->v_type; 615 if (hp->h_rec.u.rec_type == HFS_REC_FILE) { 616 hfs_file_record_t *f = &hp->h_rec.file; 617 if (hp->h_fork == HFS_RSRCFORK) 618 fork = &f->rsrc_fork; 619 else 620 fork = &f->data_fork; 621 vap->va_fileid = f->cnid; 622 bsd = &f->bsd; 623 vap->va_bytes = fork->total_blocks * HFS_BLOCKSIZE(vp); 624 vap->va_size = fork->logical_size; 625 hfs_time_to_timespec(f->date_created, &vap->va_ctime); 626 hfs_time_to_timespec(f->date_content_mod, &vap->va_mtime); 627 hfs_time_to_timespec(f->date_accessed, &vap->va_atime); 628 vap->va_nlink = 1; 629 } 630 else if (hp->h_rec.u.rec_type == HFS_REC_FLDR) { 631 hfs_folder_record_t *f = &hp->h_rec.folder; 632 vap->va_fileid = hp->h_rec.folder.cnid; 633 bsd = &f->bsd; 634 vap->va_size = 512; /* XXX Temporary */ 635 vap->va_bytes = 512; /* XXX Temporary */ 636 hfs_time_to_timespec(f->date_created, &vap->va_ctime); 637 hfs_time_to_timespec(f->date_content_mod,&vap->va_mtime); 638 hfs_time_to_timespec(f->date_accessed, &vap->va_atime); 639 vap->va_nlink = 2; /* XXX */ 640 } 641 else { 642 DPRINTF(("hfs+: hfs_vop_getattr(): invalid record type %i", 643 hp->h_rec.u.rec_type)); 644 return EINVAL; 645 } 646 647 if ((bsd->file_mode & S_IFMT) == 0) { 648 /* no bsd permissions recorded, use default values */ 649 if (hp->h_rec.u.rec_type == HFS_REC_FILE) 650 vap->va_mode = (S_IFREG | HFS_DEFAULT_FILE_MODE); 651 else 652 vap->va_mode = (S_IFDIR | HFS_DEFAULT_DIR_MODE); 653 vap->va_uid = HFS_DEFAULT_UID; 654 vap->va_gid = HFS_DEFAULT_GID; 655 } 656 else { 657 vap->va_mode = bsd->file_mode; 658 vap->va_uid = bsd->owner_id; 659 vap->va_gid = bsd->group_id; 660 if ((vap->va_mode & S_IFMT) == S_IFCHR 661 || (vap->va_mode & S_IFMT) == S_IFBLK) { 662 vap->va_rdev 663 = HFS_CONVERT_RDEV(bsd->special.raw_device); 664 } 665 else if (bsd->special.link_count != 0) { 666 /* XXX: only if in metadata directory */ 667 vap->va_nlink = bsd->special.link_count; 668 } 669 } 670 671 vap->va_fsid = hp->h_dev; 672 vap->va_blocksize = hp->h_hmp->hm_vol.vh.block_size; 673 vap->va_gen = 1; 674 vap->va_flags = 0; 675 676 return 0; 677 } 678 679 int 680 hfs_vop_setattr(void *v) 681 { 682 struct vop_setattr_args /* { 683 struct vnode *a_vp; 684 struct vattr *a_vap; 685 kauth_cred_t a_cred; 686 } */ *ap = v; 687 struct vattr *vap; 688 struct vnode *vp; 689 690 vap = ap->a_vap; 691 vp = ap->a_vp; 692 693 /* 694 * Check for unsettable attributes. 695 */ 696 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 697 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 698 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 699 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 700 return EINVAL; 701 } 702 703 /* XXX: needs revisiting for write support */ 704 if (vap->va_flags != VNOVAL 705 || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL 706 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL 707 || vap->va_birthtime.tv_sec != VNOVAL) { 708 return EROFS; 709 } 710 711 if (vap->va_size != VNOVAL) { 712 /* 713 * Disallow write attempts on read-only file systems; 714 * unless the file is a socket, fifo, or a block or 715 * character device resident on the file system. 716 */ 717 switch (vp->v_type) { 718 case VDIR: 719 return EISDIR; 720 case VCHR: 721 case VBLK: 722 case VFIFO: 723 break; 724 case VREG: 725 return EROFS; 726 default: 727 return EOPNOTSUPP; 728 } 729 } 730 731 return 0; 732 } 733 734 int 735 hfs_vop_bmap(void *v) 736 { 737 struct vop_bmap_args /* { 738 struct vnode *a_vp; 739 daddr_t a_bn; 740 struct vnode **a_vpp; 741 daddr_t *a_bnp; 742 int *a_runp; 743 } */ *ap = v; 744 struct vnode *vp; 745 struct hfsnode *hp; 746 daddr_t lblkno; 747 hfs_callback_args cbargs; 748 hfs_libcb_argsread argsread; 749 hfs_extent_descriptor_t *extents; 750 uint16_t numextents, i; 751 int bshift; 752 753 vp = ap->a_vp; 754 hp = VTOH(vp); 755 lblkno = ap->a_bn; 756 bshift = vp->v_mount->mnt_fs_bshift; 757 758 /* 759 * Check for underlying vnode requests and ensure that logical 760 * to physical mapping is requested. 761 */ 762 if (ap->a_vpp != NULL) 763 *ap->a_vpp = hp->h_devvp; 764 if (ap->a_bnp == NULL) 765 return 0; 766 767 hfslib_init_cbargs(&cbargs); 768 argsread.cred = NULL; 769 argsread.l = NULL; 770 cbargs.read = &argsread; 771 772 numextents = hfslib_get_file_extents(&hp->h_hmp->hm_vol, 773 hp->h_rec.u.cnid, hp->h_fork, &extents, &cbargs); 774 775 /* XXX: is this correct for 0-length files? */ 776 if (numextents == 0) 777 return EBADF; 778 779 for (i = 0; i < numextents; i++) { 780 if (lblkno < extents[i].block_count) 781 break; 782 lblkno -= extents[i].block_count; 783 } 784 785 if (i == numextents) { 786 /* XXX: block number past EOF */ 787 i--; 788 lblkno += extents[i].block_count; 789 } 790 791 *ap->a_bnp = ((extents[i].start_block + lblkno) << (bshift-DEV_BSHIFT)) 792 + (hp->h_hmp->hm_vol.offset >> DEV_BSHIFT); 793 794 if (ap->a_runp) { 795 int nblk; 796 797 nblk = extents[i].block_count - lblkno - 1; 798 if (nblk <= 0) 799 *ap->a_runp = 0; 800 else if (nblk > MAXBSIZE >> bshift) 801 *ap->a_runp = (MAXBSIZE >> bshift) - 1; 802 else 803 *ap->a_runp = nblk; 804 805 } 806 807 free(extents, M_TEMP); 808 809 return 0; 810 } 811 812 int 813 hfs_vop_read(void *v) 814 { 815 struct vop_read_args /* { 816 struct vnode *a_vp; 817 struct uio *a_uio; 818 int a_ioflag; 819 kauth_cred_t a_cred; 820 } */ *ap = v; 821 struct vnode *vp; 822 struct hfsnode *hp; 823 struct uio *uio; 824 uint64_t fsize; /* logical size of file */ 825 int advice; 826 int error; 827 828 vp = ap->a_vp; 829 hp = VTOH(vp); 830 uio = ap->a_uio; 831 if (hp->h_fork == HFS_RSRCFORK) 832 fsize = hp->h_rec.file.rsrc_fork.logical_size; 833 else 834 fsize = hp->h_rec.file.data_fork.logical_size; 835 error = 0; 836 advice = IO_ADV_DECODE(ap->a_ioflag); 837 838 if (uio->uio_offset < 0) 839 return EINVAL; 840 841 if (uio->uio_resid == 0 || uio->uio_offset >= fsize) 842 return 0; 843 844 if (vp->v_type != VREG && vp->v_type != VLNK) 845 return EINVAL; 846 847 error = 0; 848 while (uio->uio_resid > 0 && error == 0) { 849 vsize_t len; 850 851 len = MIN(uio->uio_resid, fsize - uio->uio_offset); 852 if (len == 0) 853 break; 854 855 error = ubc_uiomove(&vp->v_uobj, uio, len, advice, 856 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); 857 } 858 859 return error; 860 } 861 862 int 863 hfs_vop_readdir(void *v) 864 { 865 struct vop_readdir_args /* { 866 struct vnode *a_vp; 867 struct uio *a_uio; 868 kauth_cred_t a_cred; 869 int *a_eofflag; 870 off_t **a_cookies; 871 int a_*ncookies; 872 } */ *ap = v; 873 874 DPRINTF(("VOP = hfs_vop_readdir()\n")); 875 876 struct dirent curent; /* the dirent entry we are constructing */ 877 struct hfsnode *hp; 878 hfs_catalog_keyed_record_t *children; 879 hfs_unistr255_t *childnames; 880 hfs_callback_args cbargs; 881 hfs_libcb_argsread argsread; 882 struct uio *uio; 883 off_t bufoff; /* offset in buffer relative to start of dirents */ 884 uint32_t numchildren; 885 uint32_t curchild; /* index of child we are stuffing into dirent */ 886 size_t namlen, ni; 887 int error; 888 int i; /* dummy variable */ 889 890 bufoff = 0; 891 children = NULL; 892 error = 0; 893 numchildren = 0; 894 hp = VTOH(ap->a_vp); 895 uio = ap->a_uio; 896 897 if (uio->uio_offset < 0) 898 return EINVAL; 899 if (ap->a_eofflag != NULL) 900 *ap->a_eofflag = 0; 901 902 /* XXX Inform that we don't support NFS, for now. */ 903 #if 0 904 if(ap->a_eofflag != NULL || ap->a_cookies != NULL || 905 ap->a_ncookies != NULL) 906 return EOPNOTSUPP; 907 #endif 908 DPRINTF(("READDIR uio: offset=%td, resid=%zu\n", 909 uio->uio_offset, uio->uio_resid)); 910 hfslib_init_cbargs(&cbargs); 911 argsread.cred = ap->a_cred; 912 argsread.l = NULL; 913 cbargs.read = &argsread; 914 915 /* XXX Should we cache this? */ 916 if (hfslib_get_directory_contents(&hp->h_hmp->hm_vol, hp->h_rec.u.cnid, 917 &children, &childnames, &numchildren, &cbargs) != 0) { 918 DPRINTF(("ENOENT\n")); 919 error = ENOENT; 920 goto error; 921 } 922 923 DPRINTF(("numchildren = %u\n", numchildren)); 924 for (curchild = 0; curchild < numchildren && uio->uio_resid > 0; 925 curchild++) { 926 namlen = utf16_to_utf8(curent.d_name, NAME_MAX, 927 childnames[curchild].unicode, childnames[curchild].length, 928 0, NULL); 929 /* XXX: check conversion errors? */ 930 if (namlen > NAME_MAX) { 931 /* XXX: how to handle name too long? */ 932 continue; 933 } 934 for (ni = 0; ni < namlen; ni++) 935 if (curent.d_name[ni] == '/') 936 curent.d_name[ni] = ':'; 937 curent.d_namlen = namlen; 938 curent.d_reclen = _DIRENT_SIZE(&curent); 939 940 /* Skip to desired dirent. */ 941 bufoff += curent.d_reclen; 942 if (bufoff - curent.d_reclen < uio->uio_offset) 943 continue; 944 945 /* Make sure we don't return partial entries. */ 946 if (uio->uio_resid < curent.d_reclen) { 947 DPRINTF(("PARTIAL ENTRY\n")); 948 if (ap->a_eofflag != NULL) 949 *ap->a_eofflag = 1; 950 break; 951 } 952 953 curent.d_fileno = children[curchild].file.cnid; 954 switch (hfs_catalog_keyed_record_vtype(children+curchild)) { 955 case VREG: 956 curent.d_type = DT_REG; 957 break; 958 case VDIR: 959 curent.d_type = DT_DIR; 960 break; 961 case VBLK: 962 curent.d_type = DT_BLK; 963 break; 964 case VCHR: 965 curent.d_type = DT_CHR; 966 break; 967 case VLNK: 968 curent.d_type = DT_LNK; 969 break; 970 case VSOCK: 971 curent.d_type = DT_SOCK; 972 break; 973 case VFIFO: 974 curent.d_type = DT_FIFO; 975 break; 976 default: 977 curent.d_type = DT_UNKNOWN; 978 break; 979 } 980 DPRINTF(("curchildname = %s\t\t", curchildname)); 981 /* pad curent.d_name to aligned byte boundary */ 982 for (i = curent.d_namlen; 983 i < curent.d_reclen - _DIRENT_NAMEOFF(&curent); i++) 984 curent.d_name[i] = 0; 985 986 DPRINTF(("curent.d_name = %s\n", curent.d_name)); 987 988 if ((error = uiomove(&curent, curent.d_reclen, uio)) != 0) 989 goto error; 990 } 991 992 993 /* FALLTHROUGH */ 994 995 error: 996 if (numchildren > 0) { 997 if (children != NULL) 998 free(children, M_TEMP); 999 if (childnames != NULL) 1000 free(childnames, M_TEMP); 1001 } 1002 1003 if (error) { 1004 DPRINTF(("ERROR = %i\n", error)); 1005 } 1006 1007 return error; 1008 } 1009 1010 int 1011 hfs_vop_readlink(void *v) { 1012 struct vop_readlink_args /* { 1013 struct vnode *a_vp; 1014 struct uio *a_uio; 1015 kauth_cred_t a_cred; 1016 } */ *ap = v; 1017 1018 return VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred); 1019 } 1020 1021 int 1022 hfs_vop_reclaim(void *v) 1023 { 1024 struct vop_reclaim_args /* { 1025 struct vnode *a_vp; 1026 } */ *ap = v; 1027 struct vnode *vp; 1028 struct hfsnode *hp; 1029 struct hfsmount *hmp; 1030 1031 DPRINTF(("VOP = hfs_vop_reclaim()\n")); 1032 1033 vp = ap->a_vp; 1034 hp = VTOH(vp); 1035 hmp = hp->h_hmp; 1036 1037 /* Remove the hfsnode from its hash chain. */ 1038 hfs_nhashremove(hp); 1039 1040 /* Decrement the reference count to the volume's device. */ 1041 if (hp->h_devvp) { 1042 vrele(hp->h_devvp); 1043 hp->h_devvp = 0; 1044 } 1045 1046 genfs_node_destroy(vp); 1047 free(vp->v_data, M_TEMP); 1048 vp->v_data = NULL; 1049 1050 return 0; 1051 } 1052 1053 int 1054 hfs_vop_print(void *v) 1055 { 1056 struct vop_print_args /* { 1057 struct vnode *a_vp; 1058 } */ *ap = v; 1059 struct vnode *vp; 1060 struct hfsnode *hp; 1061 1062 DPRINTF(("VOP = hfs_vop_print()\n")); 1063 1064 vp = ap->a_vp; 1065 hp = VTOH(vp); 1066 1067 printf("dummy = %X\n", (unsigned)hp->dummy); 1068 printf("\n"); 1069 1070 return 0; 1071 } 1072