1 /* $NetBSD: hfs_vnops.c,v 1.4 2007/08/17 17:44:43 pooka 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.4 2007/08/17 17:44:43 pooka 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 148 int (**hfs_vnodeop_p) (void *); 149 const struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { 150 { &vop_default_desc, vn_default_error }, 151 { &vop_lookup_desc, hfs_vop_lookup }, /* lookup */ 152 { &vop_create_desc, genfs_eopnotsupp }, /* create */ 153 { &vop_whiteout_desc, genfs_eopnotsupp }, /* whiteout */ 154 { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ 155 { &vop_open_desc, hfs_vop_open }, /* open */ 156 { &vop_close_desc, hfs_vop_close }, /* close */ 157 { &vop_access_desc, hfs_vop_access }, /* access */ 158 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 159 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 160 { &vop_read_desc, hfs_vop_read }, /* read */ 161 { &vop_write_desc, genfs_eopnotsupp }, /* write */ 162 { &vop_lease_desc, genfs_eopnotsupp }, /* lease */ 163 { &vop_ioctl_desc, genfs_eopnotsupp }, /* ioctl */ 164 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 165 { &vop_poll_desc, genfs_eopnotsupp }, /* poll */ 166 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 167 { &vop_revoke_desc, genfs_eopnotsupp }, /* revoke */ 168 { &vop_mmap_desc, genfs_mmap }, /* mmap */ 169 { &vop_fsync_desc, genfs_nullop }, /* fsync */ 170 { &vop_seek_desc, genfs_seek }, /* seek */ 171 { &vop_remove_desc, genfs_eopnotsupp }, /* remove */ 172 { &vop_link_desc, genfs_eopnotsupp }, /* link */ 173 { &vop_rename_desc, genfs_eopnotsupp }, /* rename */ 174 { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */ 175 { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */ 176 { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */ 177 { &vop_readdir_desc, hfs_vop_readdir }, /* readdir */ 178 { &vop_readlink_desc, hfs_vop_readlink }, /* readlink */ 179 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 180 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 181 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 182 { &vop_lock_desc, genfs_lock }, /* lock */ 183 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 184 { &vop_bmap_desc, hfs_vop_bmap }, /* bmap */ 185 { &vop_strategy_desc, genfs_eopnotsupp }, /* strategy */ 186 { &vop_print_desc, hfs_vop_print }, /* print */ 187 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 188 { &vop_pathconf_desc, genfs_eopnotsupp }, /* pathconf */ 189 { &vop_advlock_desc, genfs_eopnotsupp }, /* advlock */ 190 { &vop_bwrite_desc, genfs_eopnotsupp }, /* bwrite */ 191 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 192 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 193 { &vop_openextattr_desc, genfs_eopnotsupp }, /* openextattr */ 194 { &vop_closeextattr_desc, genfs_eopnotsupp }, /* closeextattr */ 195 { &vop_getextattr_desc, genfs_eopnotsupp }, /* getextattr */ 196 { &vop_setextattr_desc, genfs_eopnotsupp }, /* setextattr */ 197 { &vop_listextattr_desc, genfs_eopnotsupp }, /* listextattr */ 198 { &vop_deleteextattr_desc, genfs_eopnotsupp }, /* deleteextattr */ 199 { NULL, NULL } 200 }; 201 const struct vnodeopv_desc hfs_vnodeop_opv_desc = 202 { &hfs_vnodeop_p, hfs_vnodeop_entries }; 203 204 int (**hfs_specop_p) (void *); 205 const struct vnodeopv_entry_desc hfs_specop_entries[] = { 206 { &vop_default_desc, vn_default_error }, 207 { &vop_lookup_desc, spec_lookup }, /* lookup */ 208 { &vop_create_desc, spec_create }, /* create */ 209 { &vop_mknod_desc, spec_mknod }, /* mknod */ 210 { &vop_open_desc, spec_open }, /* open */ 211 { &vop_close_desc, spec_close }, /* close */ 212 { &vop_access_desc, hfs_vop_access }, /* access */ 213 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 214 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 215 { &vop_read_desc, spec_read }, /* read */ 216 { &vop_write_desc, spec_write }, /* write */ 217 { &vop_lease_desc, spec_lease_check }, /* lease */ 218 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 219 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 220 { &vop_poll_desc, spec_poll }, /* poll */ 221 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 222 { &vop_revoke_desc, spec_revoke }, /* revoke */ 223 { &vop_mmap_desc, spec_mmap }, /* mmap */ 224 { &vop_fsync_desc, genfs_nullop }, /* fsync */ 225 { &vop_seek_desc, spec_seek }, /* seek */ 226 { &vop_remove_desc, spec_remove }, /* remove */ 227 { &vop_link_desc, spec_link }, /* link */ 228 { &vop_rename_desc, spec_rename }, /* rename */ 229 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 230 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 231 { &vop_symlink_desc, spec_symlink }, /* symlink */ 232 { &vop_readdir_desc, spec_readdir }, /* readdir */ 233 { &vop_readlink_desc, spec_readlink }, /* readlink */ 234 { &vop_abortop_desc, spec_abortop }, /* abortop */ 235 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 236 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 237 { &vop_lock_desc, genfs_lock }, /* lock */ 238 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 239 { &vop_bmap_desc, spec_bmap }, /* bmap */ 240 { &vop_strategy_desc, spec_strategy }, /* strategy */ 241 { &vop_print_desc, hfs_vop_print }, /* print */ 242 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 243 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 244 { &vop_advlock_desc, spec_advlock }, /* advlock */ 245 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 246 { &vop_getpages_desc, spec_getpages }, /* getpages */ 247 { &vop_putpages_desc, spec_putpages }, /* putpages */ 248 #if 0 249 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 250 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 251 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 252 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 253 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 254 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 255 #endif 256 { NULL, NULL } 257 }; 258 const struct vnodeopv_desc hfs_specop_opv_desc = 259 { &hfs_specop_p, hfs_specop_entries }; 260 261 int (**hfs_fifoop_p) (void *); 262 const struct vnodeopv_entry_desc hfs_fifoop_entries[] = { 263 { &vop_default_desc, vn_default_error }, 264 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 265 { &vop_create_desc, fifo_create }, /* create */ 266 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 267 { &vop_open_desc, fifo_open }, /* open */ 268 { &vop_close_desc, fifo_close }, /* close */ 269 { &vop_access_desc, hfs_vop_access }, /* access */ 270 { &vop_getattr_desc, hfs_vop_getattr }, /* getattr */ 271 { &vop_setattr_desc, hfs_vop_setattr }, /* setattr */ 272 { &vop_read_desc, fifo_read }, /* read */ 273 { &vop_write_desc, fifo_write }, /* write */ 274 { &vop_lease_desc, fifo_lease_check }, /* lease */ 275 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 276 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 277 { &vop_poll_desc, fifo_poll }, /* poll */ 278 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 279 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 280 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 281 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 282 { &vop_seek_desc, fifo_seek }, /* seek */ 283 { &vop_remove_desc, fifo_remove }, /* remove */ 284 { &vop_link_desc, fifo_link }, /* link */ 285 { &vop_rename_desc, fifo_rename }, /* rename */ 286 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 287 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 288 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 289 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 290 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 291 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 292 { &vop_inactive_desc, genfs_eopnotsupp }, /* inactive */ 293 { &vop_reclaim_desc, hfs_vop_reclaim }, /* reclaim */ 294 { &vop_lock_desc, genfs_lock }, /* lock */ 295 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 296 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 297 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 298 { &vop_print_desc, hfs_vop_print }, /* print */ 299 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 300 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 301 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 302 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 303 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 304 #if 0 305 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ 306 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ 307 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ 308 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ 309 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ 310 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ 311 #endif 312 { NULL, NULL } 313 }; 314 const struct vnodeopv_desc hfs_fifoop_opv_desc = 315 { &hfs_fifoop_p, hfs_fifoop_entries }; 316 317 int 318 hfs_vop_lookup(void *v) 319 { 320 struct vop_lookup_args /* { 321 struct vnode * a_dvp; 322 struct vnode ** a_vpp; 323 struct componentname * a_cnp; 324 } */ *ap = v; 325 struct buf *bp; /* a buffer of directory entries */ 326 struct componentname *cnp; 327 struct hfsnode *dp; /* hfsnode for directory being searched */ 328 kauth_cred_t cred; 329 struct vnode **vpp; /* resultant vnode */ 330 struct vnode *pdp; /* saved dp during symlink work */ 331 struct vnode *tdp; /* returned by VFS_VGET */ 332 struct vnode *vdp; /* vnode for directory being searched */ 333 hfs_catalog_key_t key; /* hfs+ catalog search key for requested child */ 334 hfs_catalog_keyed_record_t rec; /* catalog record of requested child */ 335 unichar_t* unicn; /* name of component, in Unicode */ 336 const char *pname; 337 int error; 338 int flags; 339 int result; /* result of libhfs operations */ 340 341 #ifdef HFS_DEBUG 342 printf("VOP = hfs_vop_lookup()\n"); 343 #endif /* HFS_DEBUG */ 344 345 bp = NULL; 346 cnp = ap->a_cnp; 347 cred = cnp->cn_cred; 348 vdp = ap->a_dvp; 349 dp = VTOH(vdp); 350 error = 0; 351 pname = cnp->cn_nameptr; 352 result = 0; 353 unicn = NULL; 354 vpp = ap->a_vpp; 355 *vpp = NULL; 356 357 flags = cnp->cn_flags; 358 359 360 /* 361 * Check accessiblity of directory. 362 */ 363 if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_lwp)) != 0) 364 return error; 365 366 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 367 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 368 return EROFS; 369 370 /* 371 * We now have a segment name to search for, and a directory to search. 372 * 373 * Before tediously performing a linear scan of the directory, 374 * check the name cache to see if the directory/name pair 375 * we are looking for is known already. 376 */ 377 /* XXX Cache disabled until we can make sure it works. */ 378 /* if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) 379 return error; */ 380 381 382 /* if (cnp->cn_namelen == 1 && *pname == '.') { 383 *vpp = vdp; 384 VREF(vdp); 385 return (0); 386 }*/ 387 388 pdp = vdp; 389 if (flags & ISDOTDOT) { 390 /*printf("DOTDOT ");*/ 391 VOP_UNLOCK(pdp, 0); /* race to get the inode */ 392 error = VFS_VGET(vdp->v_mount, dp->h_parent, &tdp); 393 vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 394 if (error != 0) 395 goto error; 396 *vpp = tdp; 397 /* } else if (dp->h_rec.cnid == rec.file.cnid) {*/ 398 } else if (cnp->cn_namelen == 1 && pname[0] == '.') { 399 /*printf("DOT ");*/ 400 VREF(vdp); /* we want ourself, ie "." */ 401 *vpp = vdp; 402 } else { 403 hfs_callback_args cbargs; 404 hfs_libcb_argsread argsread; 405 uint8_t len; 406 407 hfslib_init_cbargs(&cbargs); 408 argsread.l = cnp->cn_lwp; 409 argsread.cred = cnp->cn_cred; 410 411 /* XXX: when decomposing, string could grow 412 and we have to handle overflow */ 413 unicn = malloc(cnp->cn_namelen*sizeof(unicn[0]), M_TEMP, M_WAITOK); 414 len = utf8_to_utf16(unicn, cnp->cn_namelen, 415 cnp->cn_nameptr, cnp->cn_namelen, 0, NULL); 416 /* XXX: check conversion errors? */ 417 if (hfslib_make_catalog_key(VTOH(vdp)->h_rec.cnid, len, unicn, 418 &key) == 0) { 419 /*printf("ERROR in hfslib_make_catalog_key\n");*/ 420 error = EINVAL; 421 goto error; 422 } 423 424 result = hfslib_find_catalog_record_with_key(&dp->h_hmp->hm_vol, &key, 425 &rec, &cbargs); 426 if (result > 0) { 427 error = EINVAL; 428 goto error; 429 } 430 if (result < 0) { 431 if (cnp->cn_nameiop == CREATE) 432 error = EROFS; 433 else 434 error = ENOENT; 435 goto error; 436 } 437 438 if (rec.file.user_info.file_type == HFS_HARD_LINK_FILE_TYPE 439 && rec.file.user_info.file_creator 440 == HFS_HFSLUS_CREATOR) { 441 if (hfslib_get_hardlink(&dp->h_hmp->hm_vol, 442 rec.file.bsd.special.inode_num, 443 &rec, &cbargs) != 0) { 444 error = EINVAL; 445 goto error; 446 } 447 } 448 449 if (rec.type == HFS_REC_FILE 450 && strcmp(cnp->cn_nameptr+cnp->cn_namelen, "/rsrc") == 0 451 && rec.file.rsrc_fork.logical_size > 0) { 452 /* advance namei next pointer to end of stirng */ 453 cnp->cn_consume = 5; 454 cnp->cn_flags &= ~REQUIREDIR; /* XXX: needed? */ 455 error = hfs_vget_internal(vdp->v_mount, rec.file.cnid, 456 HFS_RSRCFORK, &tdp); 457 } 458 else 459 error = VFS_VGET(vdp->v_mount, rec.file.cnid, &tdp); 460 if (error != 0) 461 goto error; 462 *vpp = tdp; 463 } 464 /*printf("\n");*/ 465 /* 466 * Insert name into cache if appropriate. 467 */ 468 /* XXX Cache disabled until we can make sure it works. */ 469 /* if (cnp->cn_flags & MAKEENTRY) 470 cache_enter(vdp, *vpp, cnp);*/ 471 472 error = 0; 473 474 /* FALLTHROUGH */ 475 error: 476 if (unicn != NULL) 477 free(unicn, M_TEMP); 478 479 return error; 480 } 481 482 int 483 hfs_vop_open(void *v) 484 { 485 #if 0 486 struct vop_open_args /* { 487 struct vnode *a_vp; 488 int a_mode; 489 kauth_cred_t a_cred; 490 struct lwp *a_l; 491 } */ *ap = v; 492 struct hfsnode *hn = VTOH(ap->a_vp); 493 #endif 494 #ifdef HFS_DEBUG 495 printf("VOP = hfs_vop_open()\n"); 496 #endif /* HFS_DEBUG */ 497 498 /* 499 * XXX This is a good place to read and cache the file's extents to avoid 500 * XXX doing it upon every read/write. Must however keep the cache in sync 501 * XXX when the file grows/shrinks. (So would that go in vop_truncate?) 502 */ 503 504 return 0; 505 } 506 507 int 508 hfs_vop_close(void *v) 509 { 510 #if 0 511 struct vop_close_args /* { 512 struct vnode *a_vp; 513 int a_fflag; 514 kauth_cred_t a_cred; 515 struct lwp *a_l; 516 } */ *ap = v; 517 struct hfsnode *hn = VTOH(ap->a_vp); 518 #endif 519 #ifdef HFS_DEBUG 520 printf("VOP = hfs_vop_close()\n"); 521 #endif /* HFS_DEBUG */ 522 523 /* Release extents cache here. */ 524 525 return 0; 526 } 527 528 int 529 hfs_vop_access(void *v) 530 { 531 struct vop_access_args /* { 532 struct vnode *a_vp; 533 int a_mode; 534 kauth_cred_t a_cred; 535 struct lwp *a_l; 536 } */ *ap = v; 537 struct vattr va; 538 int error; 539 540 #ifdef HFS_DEBUG 541 printf("VOP = hfs_vop_access()\n"); 542 #endif /* HFS_DEBUG */ 543 544 /* 545 * Disallow writes on files, directories, and symlinks 546 * since we have no write support yet. 547 */ 548 549 if (ap->a_mode & VWRITE) { 550 switch (ap->a_vp->v_type) { 551 case VDIR: 552 case VLNK: 553 case VREG: 554 return EROFS; 555 default: 556 break; 557 } 558 } 559 560 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0) 561 return error; 562 563 return vaccess(va.va_type, va.va_mode, va.va_uid, va.va_gid, 564 ap->a_mode, ap->a_cred); 565 } 566 567 int 568 hfs_vop_getattr(void *v) 569 { 570 struct vop_getattr_args /* { 571 struct vnode *a_vp; 572 struct vattr *a_vap; 573 struct ucred *a_cred; 574 struct lwp *a_l; 575 } */ *ap = v; 576 struct vnode *vp; 577 struct hfsnode *hp; 578 struct vattr *vap; 579 hfs_bsd_data_t *bsd; 580 hfs_fork_t *fork; 581 582 #ifdef HFS_DEBUG 583 printf("VOP = hfs_vop_getattr()\n"); 584 #endif /* HFS_DEBUG */ 585 586 vp = ap->a_vp; 587 hp = VTOH(vp); 588 vap = ap->a_vap; 589 590 vattr_null(vap); 591 592 /* 593 * XXX Cannot trust permissions/modes/flags stored in an HFS+ catalog record 594 * XXX record those values are not set on files created under Mac OS 9. 595 */ 596 vap->va_type = ap->a_vp->v_type; 597 if (hp->h_rec.rec_type == HFS_REC_FILE) { 598 if (hp->h_fork == HFS_RSRCFORK) 599 fork = &hp->h_rec.file.rsrc_fork; 600 else 601 fork = &hp->h_rec.file.data_fork; 602 vap->va_fileid = hp->h_rec.file.cnid; 603 bsd = &hp->h_rec.file.bsd; 604 vap->va_bytes = fork->total_blocks * HFS_BLOCKSIZE(vp); 605 vap->va_size = fork->logical_size; 606 hfs_time_to_timespec(hp->h_rec.file.date_created, &vap->va_ctime); 607 hfs_time_to_timespec(hp->h_rec.file.date_content_mod, &vap->va_mtime); 608 hfs_time_to_timespec(hp->h_rec.file.date_accessed, &vap->va_atime); 609 vap->va_nlink = 1; 610 } 611 else if (hp->h_rec.rec_type == HFS_REC_FLDR) { 612 vap->va_fileid = hp->h_rec.folder.cnid; 613 bsd = &hp->h_rec.folder.bsd; 614 vap->va_size = 512; /* XXX Temporary */ 615 vap->va_bytes = 512; /* XXX Temporary */ 616 hfs_time_to_timespec(hp->h_rec.folder.date_created, &vap->va_ctime); 617 hfs_time_to_timespec(hp->h_rec.folder.date_content_mod,&vap->va_mtime); 618 hfs_time_to_timespec(hp->h_rec.folder.date_accessed, &vap->va_atime); 619 vap->va_nlink = 2; /* XXX */ 620 } 621 else { 622 printf("hfslus: hfs_vop_getattr(): invalid record type %i", 623 hp->h_rec.rec_type); 624 return EINVAL; 625 } 626 627 if ((bsd->file_mode & S_IFMT) == 0) { 628 /* no bsd permissions recorded, use default values */ 629 if (hp->h_rec.rec_type == HFS_REC_FILE) 630 vap->va_mode = (S_IFREG | HFS_DEFAULT_FILE_MODE); 631 else 632 vap->va_mode = (S_IFDIR | HFS_DEFAULT_DIR_MODE); 633 vap->va_uid = HFS_DEFAULT_UID; 634 vap->va_gid = HFS_DEFAULT_GID; 635 } 636 else { 637 vap->va_mode = bsd->file_mode; 638 vap->va_uid = bsd->owner_id; 639 vap->va_gid = bsd->group_id; 640 if ((vap->va_mode & S_IFMT) == S_IFCHR 641 || (vap->va_mode & S_IFMT) == S_IFBLK) { 642 vap->va_rdev 643 = HFS_CONVERT_RDEV(bsd->special.raw_device); 644 } 645 else if (bsd->special.link_count != 0) { 646 /* XXX: only if in metadata directory */ 647 vap->va_nlink = bsd->special.link_count; 648 } 649 } 650 651 vap->va_fsid = hp->h_dev; 652 vap->va_blocksize = hp->h_hmp->hm_vol.vh.block_size; 653 vap->va_gen = 1; 654 vap->va_flags = 0; 655 656 return 0; 657 } 658 659 int 660 hfs_vop_setattr(void *v) 661 { 662 struct vop_setattr_args /* { 663 struct vnode *a_vp; 664 struct vattr *a_vap; 665 kauth_cred_t a_cred; 666 struct lwp *a_l; 667 } */ *ap = v; 668 struct vattr *vap; 669 struct vnode *vp; 670 671 vap = ap->a_vap; 672 vp = ap->a_vp; 673 674 /* 675 * Check for unsettable attributes. 676 */ 677 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 678 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 679 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 680 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 681 return EINVAL; 682 } 683 684 /* XXX: needs revisiting for write support */ 685 if (vap->va_flags != VNOVAL 686 || vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL 687 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL 688 || vap->va_birthtime.tv_sec != VNOVAL) { 689 return EROFS; 690 } 691 692 if (vap->va_size != VNOVAL) { 693 /* 694 * Disallow write attempts on read-only file systems; 695 * unless the file is a socket, fifo, or a block or 696 * character device resident on the file system. 697 */ 698 switch (vp->v_type) { 699 case VDIR: 700 return EISDIR; 701 case VCHR: 702 case VBLK: 703 case VFIFO: 704 break; 705 case VREG: 706 return EROFS; 707 default: 708 return EOPNOTSUPP; 709 } 710 } 711 712 return 0; 713 } 714 715 int 716 hfs_vop_bmap(void *v) 717 { 718 struct vop_bmap_args /* { 719 struct vnode *a_vp; 720 daddr_t a_bn; 721 struct vnode **a_vpp; 722 daddr_t *a_bnp; 723 int *a_runp; 724 } */ *ap = v; 725 struct vnode *vp; 726 struct hfsnode *hp; 727 daddr_t lblkno; 728 hfs_callback_args cbargs; 729 hfs_libcb_argsread argsread; 730 hfs_extent_descriptor_t *extents; 731 uint16_t numextents, i; 732 int bshift; 733 734 vp = ap->a_vp; 735 hp = VTOH(vp); 736 lblkno = ap->a_bn; 737 bshift = vp->v_mount->mnt_fs_bshift; 738 739 /* 740 * Check for underlying vnode requests and ensure that logical 741 * to physical mapping is requested. 742 */ 743 if (ap->a_vpp != NULL) 744 *ap->a_vpp = hp->h_devvp; 745 if (ap->a_bnp == NULL) 746 return (0); 747 748 hfslib_init_cbargs(&cbargs); 749 argsread.cred = NULL; 750 argsread.l = NULL; 751 cbargs.read = &argsread; 752 753 numextents = hfslib_get_file_extents(&hp->h_hmp->hm_vol, 754 hp->h_rec.cnid, hp->h_fork, &extents, &cbargs); 755 756 /* XXX: is this correct for 0-length files? */ 757 if (numextents == 0) 758 return EBADF; 759 760 for (i=0; i<numextents; i++) { 761 if (lblkno < extents[i].block_count) 762 break; 763 lblkno -= extents[i].block_count; 764 } 765 766 if (i == numextents) { 767 /* XXX: block number past EOF */ 768 i--; 769 lblkno += extents[i].block_count; 770 } 771 772 *ap->a_bnp = ((extents[i].start_block + lblkno) 773 << (bshift-DEV_BSHIFT)) 774 + (hp->h_hmp->hm_vol.offset >> DEV_BSHIFT); 775 776 if (ap->a_runp) { 777 int nblk; 778 779 nblk = extents[i].block_count - lblkno - 1; 780 if (nblk <= 0) 781 *ap->a_runp = 0; 782 else if (nblk > MAXBSIZE >> bshift) 783 *ap->a_runp = (MAXBSIZE >> bshift) - 1; 784 else 785 *ap->a_runp = nblk; 786 787 } 788 789 free(extents, /*M_HFSMNT*/ M_TEMP); 790 791 return 0; 792 } 793 794 int 795 hfs_vop_read(void *v) 796 { 797 struct vop_read_args /* { 798 struct vnode *a_vp; 799 struct uio *a_uio; 800 int a_ioflag; 801 kauth_cred_t a_cred; 802 } */ *ap = v; 803 struct vnode *vp; 804 struct hfsnode *hp; 805 struct uio *uio; 806 uint64_t fsize; /* logical size of file */ 807 int advice; 808 int error; 809 810 vp = ap->a_vp; 811 hp = VTOH(vp); 812 uio = ap->a_uio; 813 if (hp->h_fork == HFS_RSRCFORK) 814 fsize = hp->h_rec.file.rsrc_fork.logical_size; 815 else 816 fsize = hp->h_rec.file.data_fork.logical_size; 817 error = 0; 818 advice = IO_ADV_DECODE(ap->a_ioflag); 819 820 if (uio->uio_offset < 0) 821 return EINVAL; 822 823 if (uio->uio_resid == 0 || uio->uio_offset >= fsize) 824 return 0; 825 826 if (vp->v_type != VREG && vp->v_type != VLNK) 827 return EINVAL; 828 829 error = 0; 830 while (uio->uio_resid > 0 && error == 0) { 831 int flags; 832 vsize_t len; 833 void *win; 834 835 len = MIN(uio->uio_resid, fsize - uio->uio_offset); 836 if (len == 0) 837 break; 838 839 win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &len, 840 advice, UBC_READ); 841 error = uiomove(win, len, uio); 842 flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; 843 ubc_release(win, flags); 844 } 845 846 return error; 847 } 848 849 int 850 hfs_vop_readdir(void *v) 851 { 852 struct vop_readdir_args /* { 853 struct vnode *a_vp; 854 struct uio *a_uio; 855 kauth_cred_t a_cred; 856 int *a_eofflag; 857 off_t **a_cookies; 858 int a_*ncookies; 859 } */ *ap = v; 860 861 #ifdef HFS_DEBUG 862 printf("VOP = hfs_vop_readdir()\n"); 863 #endif /* HFS_DEBUG */ 864 865 struct dirent curent; /* the dirent entry we're currently constructing */ 866 struct hfsnode *hp; 867 hfs_catalog_keyed_record_t *children; 868 hfs_unistr255_t *childnames; 869 hfs_callback_args cbargs; 870 hfs_libcb_argsread argsread; 871 struct uio *uio; 872 off_t bufoff; /* current position in buffer relative to start of dirents */ 873 uint32_t numchildren; 874 uint32_t curchild; /* index of child we're currently stuffing into dirent */ 875 size_t namlen; 876 int error; 877 int i; /* dummy variable */ 878 879 bufoff = 0; 880 children = NULL; 881 error = 0; 882 numchildren = 0; 883 hp = VTOH(ap->a_vp); 884 uio = ap->a_uio; 885 886 if (uio->uio_offset < 0) 887 return EINVAL; 888 if (ap->a_eofflag != NULL) 889 *ap->a_eofflag = 0; 890 891 /* XXX Inform that we don't support NFS, for now. */ 892 /* if(ap->a_eofflag != NULL || ap->a_cookies != NULL || ap->a_ncookies != NULL) 893 return EOPNOTSUPP;*/ 894 /*printf("READDIR uio: offset=%i, resid=%i\n", 895 (int)uio->uio_offset, (int)uio->uio_resid);*/ 896 hfslib_init_cbargs(&cbargs); 897 argsread.cred = ap->a_cred; 898 argsread.l = NULL; 899 cbargs.read = &argsread; 900 901 /* XXX Should we cache this? */ 902 if (hfslib_get_directory_contents(&hp->h_hmp->hm_vol, hp->h_rec.cnid, 903 &children, &childnames, &numchildren, &cbargs) != 0) { 904 /*printf("NOENT\n");*/ 905 error = ENOENT; 906 goto error; 907 } 908 909 /*printf("numchildren = %i\n", numchildren);*/ 910 for (curchild = 0; curchild < numchildren && uio->uio_resid>0; curchild++) { 911 namlen = utf16_to_utf8(curent.d_name, MAXNAMLEN, 912 childnames[curchild].unicode, 913 childnames[curchild].length, 914 0, NULL); 915 /* XXX: check conversion errors? */ 916 if (namlen > MAXNAMLEN) { 917 /* XXX: how to handle name too long? */ 918 continue; 919 } 920 curent.d_namlen = namlen; 921 curent.d_reclen = _DIRENT_SIZE(&curent); 922 923 /* Skip to desired dirent. */ 924 if ((bufoff += curent.d_reclen) - curent.d_reclen < uio->uio_offset) 925 continue; 926 927 /* Make sure we don't return partial entries. */ 928 if (uio->uio_resid < curent.d_reclen) { 929 /*printf("PARTIAL ENTRY\n");*/ 930 if (ap->a_eofflag != NULL) 931 *ap->a_eofflag = 1; 932 break; 933 } 934 935 curent.d_fileno = children[curchild].file.cnid; 936 switch (hfs_catalog_keyed_record_vtype(children+curchild)) { 937 case VREG: 938 curent.d_type = DT_REG; 939 break; 940 case VDIR: 941 curent.d_type = DT_DIR; 942 break; 943 case VBLK: 944 curent.d_type = DT_BLK; 945 break; 946 case VCHR: 947 curent.d_type = DT_CHR; 948 break; 949 case VLNK: 950 curent.d_type = DT_LNK; 951 break; 952 case VSOCK: 953 curent.d_type = DT_SOCK; 954 break; 955 case VFIFO: 956 curent.d_type = DT_FIFO; 957 break; 958 default: 959 curent.d_type = DT_UNKNOWN; 960 break; 961 } 962 /*printf("curchildname = %s\t\t", curchildname);*/ 963 /* pad curent.d_name to aligned byte boundary */ 964 for (i=curent.d_namlen; 965 i<curent.d_reclen-_DIRENT_NAMEOFF(&curent); i++) 966 curent.d_name[i] = 0; 967 968 /*printf("curent.d_name = %s\n", curent.d_name);*/ 969 970 if ((error = uiomove(&curent, curent.d_reclen, uio)) != 0) 971 goto error; 972 } 973 974 975 /* FALLTHROUGH */ 976 977 error: 978 if (numchildren > 0) { 979 if (children != NULL) 980 free(children, M_TEMP); 981 if (childnames != NULL) 982 free(childnames, M_TEMP); 983 } 984 985 /*if (error) 986 printf("ERROR = %i\n", error);*/ 987 return error; 988 } 989 990 int 991 hfs_vop_readlink(void *v) { 992 struct vop_readlink_args /* { 993 struct vnode *a_vp; 994 struct uio *a_uio; 995 kauth_cred_t a_cred; 996 } */ *ap = v; 997 998 return VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred); 999 } 1000 1001 int 1002 hfs_vop_reclaim(void *v) 1003 { 1004 struct vop_reclaim_args /* { 1005 struct vnode *a_vp; 1006 struct lwp *a_l; 1007 } */ *ap = v; 1008 struct vnode *vp; 1009 struct hfsnode *hp; 1010 struct hfsmount *hmp; 1011 1012 #ifdef HFS_DEBUG 1013 printf("VOP = hfs_vop_reclaim()\n"); 1014 #endif /* HFS_DEBUG */ 1015 1016 vp = ap->a_vp; 1017 hp = VTOH(vp); 1018 hmp = hp->h_hmp; 1019 1020 /* Remove the hfsnode from its hash chain. */ 1021 hfs_nhashremove(hp); 1022 1023 /* Purge name lookup cache. */ 1024 cache_purge(vp); 1025 1026 /* Decrement the reference count to the volume's device. */ 1027 if (hp->h_devvp) { 1028 vrele(hp->h_devvp); 1029 hp->h_devvp = 0; 1030 } 1031 1032 genfs_node_destroy(vp); 1033 FREE(vp->v_data, M_TEMP); 1034 vp->v_data = 0; 1035 1036 return 0; 1037 } 1038 1039 int 1040 hfs_vop_print(void *v) 1041 { 1042 struct vop_print_args /* { 1043 struct vnode *a_vp; 1044 } */ *ap = v; 1045 struct vnode *vp; 1046 struct hfsnode *hp; 1047 1048 #ifdef HFS_DEBUG 1049 printf("VOP = hfs_vop_print()\n"); 1050 #endif /* HFS_DEBUG */ 1051 1052 vp = ap->a_vp; 1053 hp = VTOH(vp); 1054 1055 printf("dummy = %X\n", (unsigned)hp->dummy); 1056 lockmgr_printinfo(&vp->v_lock); 1057 printf("\n"); 1058 1059 return 0; 1060 } 1061