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