]> git.saurik.com Git - apple/hfs.git/blob - core/hfs_vfsops.c
hfs-407.1.3.tar.gz
[apple/hfs.git] / core / hfs_vfsops.c
1 /*
2 * Copyright (c) 1999-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1991, 1993, 1994
30 * The Regents of the University of California. All rights reserved.
31 * (c) UNIX System Laboratories, Inc.
32 * All or some portions of this file are derived from material licensed
33 * to the University of California by American Telephone and Telegraph
34 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
35 * the permission of UNIX System Laboratories, Inc.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * hfs_vfsops.c
66 * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
67 *
68 * (c) Copyright 1997-2002 Apple Inc. All rights reserved.
69 *
70 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
71 *
72 */
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/kauth.h>
76
77 #include <sys/ubc.h>
78 #include <sys/sysctl.h>
79 #include <sys/malloc.h>
80 #include <sys/stat.h>
81 #include <sys/quota.h>
82 #include <sys/disk.h>
83 #include <sys/paths.h>
84 #include <sys/utfconv.h>
85 #include <sys/kdebug.h>
86 #include <sys/fslog.h>
87 #include <sys/ubc.h>
88
89 /* for parsing boot-args */
90 #include <pexpert/pexpert.h>
91
92
93 #include <kern/locks.h>
94
95 #include "hfs_journal.h"
96
97 #include <miscfs/specfs/specdev.h>
98 #include "hfs_mount.h"
99
100 #include <libkern/crypto/md5.h>
101 #include <uuid/uuid.h>
102
103 #include "hfs_iokit.h"
104 #include "hfs.h"
105 #include "hfs_catalog.h"
106 #include "hfs_cnode.h"
107 #include "hfs_dbg.h"
108 #include "hfs_endian.h"
109 #include "hfs_hotfiles.h"
110 #include "hfs_quota.h"
111 #include "hfs_btreeio.h"
112 #include "hfs_kdebug.h"
113 #include "hfs_cprotect.h"
114
115 #include "FileMgrInternal.h"
116 #include "BTreesInternal.h"
117
118 #define HFS_MOUNT_DEBUG 1
119
120 /* Enable/disable debugging code for live volume resizing, defined in hfs_resize.c */
121 extern int hfs_resize_debug;
122
123 lck_grp_attr_t * hfs_group_attr;
124 lck_attr_t * hfs_lock_attr;
125 lck_grp_t * hfs_mutex_group;
126 lck_grp_t * hfs_rwlock_group;
127 lck_grp_t * hfs_spinlock_group;
128
129 extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
130
131 #if CONFIG_HFS_STD
132 extern struct vnodeopv_desc hfs_std_vnodeop_opv_desc;
133 static int hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush);
134 #endif
135
136 /* not static so we can re-use in hfs_readwrite.c for build_path calls */
137 int hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, vfs_context_t context);
138
139 static int hfs_changefs(struct mount *mp, struct hfs_mount_args *args);
140 static int hfs_fhtovp(struct mount *mp, int fhlen, unsigned char *fhp, struct vnode **vpp, vfs_context_t context);
141 static int hfs_flushfiles(struct mount *, int, struct proc *);
142 static int hfs_init(struct vfsconf *vfsp);
143 static void hfs_locks_destroy(struct hfsmount *hfsmp);
144 static int hfs_quotactl(struct mount *, int, uid_t, caddr_t, vfs_context_t context);
145 static int hfs_start(struct mount *mp, int flags, vfs_context_t context);
146 static int hfs_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, vfs_context_t context);
147 static void hfs_syncer_free(struct hfsmount *hfsmp);
148
149 void hfs_initialize_allocator (struct hfsmount *hfsmp);
150 int hfs_teardown_allocator (struct hfsmount *hfsmp);
151
152 int hfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context);
153 int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args, int journal_replay_only, vfs_context_t context);
154 int hfs_reload(struct mount *mp);
155 int hfs_statfs(struct mount *mp, register struct vfsstatfs *sbp, vfs_context_t context);
156 int hfs_sync(struct mount *mp, int waitfor, vfs_context_t context);
157 int hfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
158 user_addr_t newp, size_t newlen, vfs_context_t context);
159 int hfs_unmount(struct mount *mp, int mntflags, vfs_context_t context);
160
161 static int hfs_journal_replay(vnode_t devvp, vfs_context_t context);
162
163 #if HFS_LEAK_DEBUG
164
165 #include <libkern/OSAtomic.h>
166 #include <IOKit/IOLib.h>
167
168 int hfs_active_mounts;
169
170 #endif
171
172 /*
173 * VFS Operations.
174 *
175 * mount system call
176 */
177
178 int
179 hfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
180 {
181
182 #if HFS_LEAK_DEBUG
183
184 #warning HFS_LEAK_DEBUG is on
185
186 hfs_alloc_trace_enable();
187
188 #endif
189
190 struct proc *p = vfs_context_proc(context);
191 struct hfsmount *hfsmp = NULL;
192 struct hfs_mount_args args;
193 int retval = E_NONE;
194 u_int32_t cmdflags;
195
196 if (data && (retval = copyin(data, (caddr_t)&args, sizeof(args)))) {
197 if (HFS_MOUNT_DEBUG) {
198 printf("hfs_mount: copyin returned %d for fs\n", retval);
199 }
200 return (retval);
201 }
202 cmdflags = (u_int32_t)vfs_flags(mp) & MNT_CMDFLAGS;
203 if (cmdflags & MNT_UPDATE) {
204 hfs_assert(data);
205
206 hfsmp = VFSTOHFS(mp);
207
208 /* Reload incore data after an fsck. */
209 if (cmdflags & MNT_RELOAD) {
210 if (vfs_isrdonly(mp)) {
211 int error = hfs_reload(mp);
212 if (error && HFS_MOUNT_DEBUG) {
213 printf("hfs_mount: hfs_reload returned %d on %s \n", error, hfsmp->vcbVN);
214 }
215 return error;
216 }
217 else {
218 if (HFS_MOUNT_DEBUG) {
219 printf("hfs_mount: MNT_RELOAD not supported on rdwr filesystem %s\n", hfsmp->vcbVN);
220 }
221 return (EINVAL);
222 }
223 }
224
225 /* Change to a read-only file system. */
226 if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) &&
227 vfs_isrdonly(mp)) {
228 int flags;
229
230 /* Set flag to indicate that a downgrade to read-only
231 * is in progress and therefore block any further
232 * modifications to the file system.
233 */
234 hfs_lock_global (hfsmp, HFS_EXCLUSIVE_LOCK);
235 hfsmp->hfs_flags |= HFS_RDONLY_DOWNGRADE;
236 hfsmp->hfs_downgrading_thread = current_thread();
237 hfs_unlock_global (hfsmp);
238 hfs_syncer_free(hfsmp);
239
240 /* use hfs_sync to push out System (btree) files */
241 retval = hfs_sync(mp, MNT_WAIT, context);
242 if (retval && ((cmdflags & MNT_FORCE) == 0)) {
243 hfsmp->hfs_flags &= ~HFS_RDONLY_DOWNGRADE;
244 hfsmp->hfs_downgrading_thread = NULL;
245 if (HFS_MOUNT_DEBUG) {
246 printf("hfs_mount: VFS_SYNC returned %d during b-tree sync of %s \n", retval, hfsmp->vcbVN);
247 }
248 goto out;
249 }
250
251 flags = WRITECLOSE;
252 if (cmdflags & MNT_FORCE)
253 flags |= FORCECLOSE;
254
255 if ((retval = hfs_flushfiles(mp, flags, p))) {
256 hfsmp->hfs_flags &= ~HFS_RDONLY_DOWNGRADE;
257 hfsmp->hfs_downgrading_thread = NULL;
258 if (HFS_MOUNT_DEBUG) {
259 printf("hfs_mount: hfs_flushfiles returned %d on %s \n", retval, hfsmp->vcbVN);
260 }
261 goto out;
262 }
263
264 /* mark the volume cleanly unmounted */
265 hfsmp->vcbAtrb |= kHFSVolumeUnmountedMask;
266 retval = hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT);
267 hfsmp->hfs_flags |= HFS_READ_ONLY;
268
269 /*
270 * Close down the journal.
271 *
272 * NOTE: It is critically important to close down the journal
273 * and have it issue all pending I/O prior to calling VNOP_FSYNC below.
274 * In a journaled environment it is expected that the journal be
275 * the only actor permitted to issue I/O for metadata blocks in HFS.
276 * If we were to call VNOP_FSYNC prior to closing down the journal,
277 * we would inadvertantly issue (and wait for) the I/O we just
278 * initiated above as part of the flushvolumeheader call.
279 *
280 * To avoid this, we follow the same order of operations as in
281 * unmount and issue the journal_close prior to calling VNOP_FSYNC.
282 */
283
284 if (hfsmp->jnl) {
285 hfs_lock_global (hfsmp, HFS_EXCLUSIVE_LOCK);
286
287 journal_close(hfsmp->jnl);
288 hfsmp->jnl = NULL;
289
290 // Note: we explicitly don't want to shutdown
291 // access to the jvp because we may need
292 // it later if we go back to being read-write.
293
294 hfs_unlock_global (hfsmp);
295
296 vfs_clearflags(hfsmp->hfs_mp, MNT_JOURNALED);
297 }
298
299 /*
300 * Write out any pending I/O still outstanding against the device node
301 * now that the journal has been closed.
302 */
303 if (retval == 0) {
304 vnode_get(hfsmp->hfs_devvp);
305 retval = VNOP_FSYNC(hfsmp->hfs_devvp, MNT_WAIT, context);
306 vnode_put(hfsmp->hfs_devvp);
307 }
308
309 if (retval) {
310 if (HFS_MOUNT_DEBUG) {
311 printf("hfs_mount: FSYNC on devvp returned %d for fs %s\n", retval, hfsmp->vcbVN);
312 }
313 hfsmp->hfs_flags &= ~HFS_RDONLY_DOWNGRADE;
314 hfsmp->hfs_downgrading_thread = NULL;
315 hfsmp->hfs_flags &= ~HFS_READ_ONLY;
316 goto out;
317 }
318
319 if (hfsmp->hfs_flags & HFS_SUMMARY_TABLE) {
320 if (hfsmp->hfs_summary_table) {
321 int err = 0;
322 /*
323 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
324 */
325 if (hfsmp->hfs_allocation_vp) {
326 err = hfs_lock (VTOC(hfsmp->hfs_allocation_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
327 }
328 hfs_free(hfsmp->hfs_summary_table, hfsmp->hfs_summary_bytes);
329 hfsmp->hfs_summary_table = NULL;
330 hfsmp->hfs_flags &= ~HFS_SUMMARY_TABLE;
331 if (err == 0 && hfsmp->hfs_allocation_vp){
332 hfs_unlock (VTOC(hfsmp->hfs_allocation_vp));
333 }
334 }
335 }
336
337 hfsmp->hfs_downgrading_thread = NULL;
338 }
339
340 /* Change to a writable file system. */
341 if (vfs_iswriteupgrade(mp)) {
342 /*
343 * On inconsistent disks, do not allow read-write mount
344 * unless it is the boot volume being mounted.
345 */
346 if (!(vfs_flags(mp) & MNT_ROOTFS) &&
347 (hfsmp->vcbAtrb & kHFSVolumeInconsistentMask)) {
348 if (HFS_MOUNT_DEBUG) {
349 printf("hfs_mount: attempting to mount inconsistent non-root volume %s\n", (hfsmp->vcbVN));
350 }
351 retval = EINVAL;
352 goto out;
353 }
354
355 // If the journal was shut-down previously because we were
356 // asked to be read-only, let's start it back up again now
357
358 if ( (HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask)
359 && hfsmp->jnl == NULL
360 && hfsmp->jvp != NULL) {
361 int jflags;
362
363 if (hfsmp->hfs_flags & HFS_NEED_JNL_RESET) {
364 jflags = JOURNAL_RESET;
365 } else {
366 jflags = 0;
367 }
368
369 hfs_lock_global (hfsmp, HFS_EXCLUSIVE_LOCK);
370
371 /* We provide the mount point twice here: The first is used as
372 * an opaque argument to be passed back when hfs_sync_metadata
373 * is called. The second is provided to the throttling code to
374 * indicate which mount's device should be used when accounting
375 * for metadata writes.
376 */
377 hfsmp->jnl = journal_open(hfsmp->jvp,
378 hfs_blk_to_bytes(hfsmp->jnl_start, HFSTOVCB(hfsmp)->blockSize) + (off_t)HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
379 hfsmp->jnl_size,
380 hfsmp->hfs_devvp,
381 hfsmp->hfs_logical_block_size,
382 jflags,
383 0,
384 hfs_sync_metadata, hfsmp->hfs_mp,
385 hfsmp->hfs_mp);
386
387 /*
388 * Set up the trim callback function so that we can add
389 * recently freed extents to the free extent cache once
390 * the transaction that freed them is written to the
391 * journal on disk.
392 */
393 if (hfsmp->jnl)
394 journal_trim_set_callback(hfsmp->jnl, hfs_trim_callback, hfsmp);
395
396 hfs_unlock_global (hfsmp);
397
398 if (hfsmp->jnl == NULL) {
399 if (HFS_MOUNT_DEBUG) {
400 printf("hfs_mount: journal_open == NULL; couldn't be opened on %s \n", (hfsmp->vcbVN));
401 }
402 retval = EINVAL;
403 goto out;
404 } else {
405 hfsmp->hfs_flags &= ~HFS_NEED_JNL_RESET;
406 vfs_setflags(hfsmp->hfs_mp, MNT_JOURNALED);
407 }
408 }
409
410 /* See if we need to erase unused Catalog nodes due to <rdar://problem/6947811>. */
411 retval = hfs_erase_unused_nodes(hfsmp);
412 if (retval != E_NONE) {
413 if (HFS_MOUNT_DEBUG) {
414 printf("hfs_mount: hfs_erase_unused_nodes returned %d for fs %s\n", retval, hfsmp->vcbVN);
415 }
416 goto out;
417 }
418
419 /* If this mount point was downgraded from read-write
420 * to read-only, clear that information as we are now
421 * moving back to read-write.
422 */
423 hfsmp->hfs_flags &= ~HFS_RDONLY_DOWNGRADE;
424 hfsmp->hfs_downgrading_thread = NULL;
425
426 /* mark the volume dirty (clear clean unmount bit) */
427 hfsmp->vcbAtrb &= ~kHFSVolumeUnmountedMask;
428
429 retval = hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT);
430 if (retval != E_NONE) {
431 if (HFS_MOUNT_DEBUG) {
432 printf("hfs_mount: hfs_flushvolumeheader returned %d for fs %s\n", retval, hfsmp->vcbVN);
433 }
434 goto out;
435 }
436
437 /* Only clear HFS_READ_ONLY after a successful write */
438 hfsmp->hfs_flags &= ~HFS_READ_ONLY;
439
440
441 if (!(hfsmp->hfs_flags & (HFS_READ_ONLY | HFS_STANDARD))) {
442 /* Setup private/hidden directories for hardlinks. */
443 hfs_privatedir_init(hfsmp, FILE_HARDLINKS);
444 hfs_privatedir_init(hfsmp, DIR_HARDLINKS);
445
446 hfs_remove_orphans(hfsmp);
447
448 /*
449 * Since we're upgrading to a read-write mount, allow
450 * hot file clustering if conditions allow.
451 *
452 * Note: this normally only would happen if you booted
453 * single-user and upgraded the mount to read-write
454 *
455 * Note: at this point we are not allowed to fail the
456 * mount operation because the HotFile init code
457 * in hfs_recording_init() will lookup vnodes with
458 * VNOP_LOOKUP() which hangs vnodes off the mount
459 * (and if we were to fail, VFS is not prepared to
460 * clean that up at this point. Since HotFiles are
461 * optional, this is not a big deal.
462 */
463 if (ISSET(hfsmp->hfs_flags, HFS_METADATA_ZONE)
464 && (!ISSET(hfsmp->hfs_flags, HFS_SSD)
465 || ISSET(hfsmp->hfs_flags, HFS_CS_HOTFILE_PIN))) {
466 hfs_recording_init(hfsmp);
467 }
468 /* Force ACLs on HFS+ file systems. */
469 if (vfs_extendedsecurity(HFSTOVFS(hfsmp)) == 0) {
470 vfs_setextendedsecurity(HFSTOVFS(hfsmp));
471 }
472 }
473 }
474
475 /* Update file system parameters. */
476 retval = hfs_changefs(mp, &args);
477 if (retval && HFS_MOUNT_DEBUG) {
478 printf("hfs_mount: hfs_changefs returned %d for %s\n", retval, hfsmp->vcbVN);
479 }
480
481 } else /* not an update request */ {
482 if (devvp == NULL) {
483 retval = EINVAL;
484 goto out;
485 }
486 /* Set the mount flag to indicate that we support volfs */
487 vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_DOVOLFS));
488
489 retval = hfs_mountfs(devvp, mp, data ? &args : NULL, 0, context);
490 if (retval) {
491 const char *name = vnode_getname(devvp);
492 printf("hfs_mount: hfs_mountfs returned error=%d for device %s\n", retval, (name ? name : "unknown-dev"));
493 if (name) {
494 vnode_putname(name);
495 }
496 goto out;
497 }
498
499 /* After hfs_mountfs succeeds, we should have valid hfsmp */
500 hfsmp = VFSTOHFS(mp);
501
502 /* Set up the maximum defrag file size */
503 hfsmp->hfs_defrag_max = HFS_INITIAL_DEFRAG_SIZE;
504
505
506 if (!data) {
507 // Root mount
508
509 hfsmp->hfs_uid = UNKNOWNUID;
510 hfsmp->hfs_gid = UNKNOWNGID;
511 hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
512 hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
513
514 /* Establish the free block reserve. */
515 hfsmp->reserveBlocks = ((u_int64_t)hfsmp->totalBlocks * HFS_MINFREE) / 100;
516 hfsmp->reserveBlocks = MIN(hfsmp->reserveBlocks, HFS_MAXRESERVE / hfsmp->blockSize);
517 }
518
519 #if HFS_LEAK_DEBUG
520 OSIncrementAtomic(&hfs_active_mounts);
521 #endif
522 }
523
524 out:
525 if (retval == 0) {
526 (void)hfs_statfs(mp, vfs_statfs(mp), context);
527 }
528 return (retval);
529 }
530
531
532 struct hfs_changefs_cargs {
533 struct hfsmount *hfsmp;
534 int namefix;
535 int permfix;
536 int permswitch;
537 };
538
539 static int
540 hfs_changefs_callback(struct vnode *vp, void *cargs)
541 {
542 ExtendedVCB *vcb;
543 struct cnode *cp;
544 struct cat_desc cndesc;
545 struct cat_attr cnattr;
546 struct hfs_changefs_cargs *args;
547 int lockflags;
548 int error;
549
550 args = (struct hfs_changefs_cargs *)cargs;
551
552 cp = VTOC(vp);
553 vcb = HFSTOVCB(args->hfsmp);
554
555 lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
556 error = cat_lookup(args->hfsmp, &cp->c_desc, 0, 0, &cndesc, &cnattr, NULL, NULL);
557 hfs_systemfile_unlock(args->hfsmp, lockflags);
558 if (error) {
559 /*
560 * If we couldn't find this guy skip to the next one
561 */
562 if (args->namefix)
563 cache_purge(vp);
564
565 return (VNODE_RETURNED);
566 }
567 /*
568 * Get the real uid/gid and perm mask from disk.
569 */
570 if (args->permswitch || args->permfix) {
571 cp->c_uid = cnattr.ca_uid;
572 cp->c_gid = cnattr.ca_gid;
573 cp->c_mode = cnattr.ca_mode;
574 }
575 /*
576 * If we're switching name converters then...
577 * Remove the existing entry from the namei cache.
578 * Update name to one based on new encoder.
579 */
580 if (args->namefix) {
581 cache_purge(vp);
582 replace_desc(cp, &cndesc);
583
584 if (cndesc.cd_cnid == kHFSRootFolderID) {
585 strlcpy((char *)vcb->vcbVN, (const char *)cp->c_desc.cd_nameptr, NAME_MAX+1);
586 cp->c_desc.cd_encoding = args->hfsmp->hfs_encoding;
587 }
588 } else {
589 cat_releasedesc(&cndesc);
590 }
591 return (VNODE_RETURNED);
592 }
593
594 /* Change fs mount parameters */
595 static int
596 hfs_changefs(struct mount *mp, struct hfs_mount_args *args)
597 {
598 int retval = 0;
599 int namefix, permfix, permswitch;
600 struct hfsmount *hfsmp;
601 ExtendedVCB *vcb;
602 struct hfs_changefs_cargs cargs;
603 u_int32_t mount_flags;
604
605 #if CONFIG_HFS_STD
606 u_int32_t old_encoding = 0;
607 hfs_to_unicode_func_t get_unicode_func;
608 unicode_to_hfs_func_t get_hfsname_func = NULL;
609 #endif
610
611 hfsmp = VFSTOHFS(mp);
612 vcb = HFSTOVCB(hfsmp);
613 mount_flags = (unsigned int)vfs_flags(mp);
614
615 hfsmp->hfs_flags |= HFS_IN_CHANGEFS;
616
617 permswitch = (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) &&
618 ((mount_flags & MNT_UNKNOWNPERMISSIONS) == 0)) ||
619 (((hfsmp->hfs_flags & HFS_UNKNOWN_PERMS) == 0) &&
620 (mount_flags & MNT_UNKNOWNPERMISSIONS)));
621
622 /* The root filesystem must operate with actual permissions: */
623 if (permswitch && (mount_flags & MNT_ROOTFS) && (mount_flags & MNT_UNKNOWNPERMISSIONS)) {
624 vfs_clearflags(mp, (u_int64_t)((unsigned int)MNT_UNKNOWNPERMISSIONS)); /* Just say "No". */
625 retval = EINVAL;
626 goto exit;
627 }
628 if (mount_flags & MNT_UNKNOWNPERMISSIONS)
629 hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS;
630 else
631 hfsmp->hfs_flags &= ~HFS_UNKNOWN_PERMS;
632
633 namefix = permfix = 0;
634
635 /*
636 * Tracking of hot files requires up-to-date access times. So if
637 * access time updates are disabled, we must also disable hot files.
638 */
639 if (mount_flags & MNT_NOATIME) {
640 (void) hfs_recording_suspend(hfsmp);
641 }
642
643 /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
644 if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
645 gTimeZone = args->hfs_timezone;
646 }
647
648 /* Change the default uid, gid and/or mask */
649 if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
650 hfsmp->hfs_uid = args->hfs_uid;
651 if (vcb->vcbSigWord == kHFSPlusSigWord)
652 ++permfix;
653 }
654 if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
655 hfsmp->hfs_gid = args->hfs_gid;
656 if (vcb->vcbSigWord == kHFSPlusSigWord)
657 ++permfix;
658 }
659 if (args->hfs_mask != (mode_t)VNOVAL) {
660 if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
661 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
662 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
663 if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
664 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
665 if (vcb->vcbSigWord == kHFSPlusSigWord)
666 ++permfix;
667 }
668 }
669
670 #if CONFIG_HFS_STD
671 /* Change the hfs encoding value (hfs only) */
672 if ((vcb->vcbSigWord == kHFSSigWord) &&
673 (args->hfs_encoding != (u_int32_t)VNOVAL) &&
674 (hfsmp->hfs_encoding != args->hfs_encoding)) {
675
676 retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
677 if (retval)
678 goto exit;
679
680 /*
681 * Connect the new hfs_get_unicode converter but leave
682 * the old hfs_get_hfsname converter in place so that
683 * we can lookup existing vnodes to get their correctly
684 * encoded names.
685 *
686 * When we're all finished, we can then connect the new
687 * hfs_get_hfsname converter and release our interest
688 * in the old converters.
689 */
690 hfsmp->hfs_get_unicode = get_unicode_func;
691 old_encoding = hfsmp->hfs_encoding;
692 hfsmp->hfs_encoding = args->hfs_encoding;
693 ++namefix;
694 }
695 #endif
696
697 if (!(namefix || permfix || permswitch))
698 goto exit;
699
700 /* XXX 3762912 hack to support HFS filesystem 'owner' */
701 if (permfix) {
702 vfs_setowner(mp,
703 hfsmp->hfs_uid == UNKNOWNUID ? KAUTH_UID_NONE : hfsmp->hfs_uid,
704 hfsmp->hfs_gid == UNKNOWNGID ? KAUTH_GID_NONE : hfsmp->hfs_gid);
705 }
706
707 /*
708 * For each active vnode fix things that changed
709 *
710 * Note that we can visit a vnode more than once
711 * and we can race with fsync.
712 *
713 * hfs_changefs_callback will be called for each vnode
714 * hung off of this mount point
715 *
716 * The vnode will be properly referenced and unreferenced
717 * around the callback
718 */
719 cargs.hfsmp = hfsmp;
720 cargs.namefix = namefix;
721 cargs.permfix = permfix;
722 cargs.permswitch = permswitch;
723
724 vnode_iterate(mp, 0, hfs_changefs_callback, (void *)&cargs);
725
726 #if CONFIG_HFS_STD
727 /*
728 * If we're switching name converters we can now
729 * connect the new hfs_get_hfsname converter and
730 * release our interest in the old converters.
731 */
732 if (namefix) {
733 /* HFS standard only */
734 hfsmp->hfs_get_hfsname = get_hfsname_func;
735 vcb->volumeNameEncodingHint = args->hfs_encoding;
736 (void) hfs_relconverter(old_encoding);
737 }
738 #endif
739
740 exit:
741 hfsmp->hfs_flags &= ~HFS_IN_CHANGEFS;
742 return (retval);
743 }
744
745
746 struct hfs_reload_cargs {
747 struct hfsmount *hfsmp;
748 int error;
749 };
750
751 static int
752 hfs_reload_callback(struct vnode *vp, void *cargs)
753 {
754 struct cnode *cp;
755 struct hfs_reload_cargs *args;
756 int lockflags;
757
758 args = (struct hfs_reload_cargs *)cargs;
759 /*
760 * flush all the buffers associated with this node
761 */
762 (void) buf_invalidateblks(vp, 0, 0, 0);
763
764 cp = VTOC(vp);
765 /*
766 * Remove any directory hints
767 */
768 if (vnode_isdir(vp))
769 hfs_reldirhints(cp, 0);
770
771 /*
772 * Re-read cnode data for all active vnodes (non-metadata files).
773 */
774 if (!vnode_issystem(vp) && !VNODE_IS_RSRC(vp) && (cp->c_fileid >= kHFSFirstUserCatalogNodeID)) {
775 struct cat_fork *datafork;
776 struct cat_desc desc;
777
778 datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
779
780 /* lookup by fileID since name could have changed */
781 lockflags = hfs_systemfile_lock(args->hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
782 args->error = cat_idlookup(args->hfsmp, cp->c_fileid, 0, 0, &desc, &cp->c_attr, datafork);
783 hfs_systemfile_unlock(args->hfsmp, lockflags);
784 if (args->error) {
785 return (VNODE_RETURNED_DONE);
786 }
787
788 /* update cnode's catalog descriptor */
789 (void) replace_desc(cp, &desc);
790 }
791 return (VNODE_RETURNED);
792 }
793
794 /*
795 * Reload all incore data for a filesystem (used after running fsck on
796 * the root filesystem and finding things to fix). The filesystem must
797 * be mounted read-only.
798 *
799 * Things to do to update the mount:
800 * invalidate all cached meta-data.
801 * invalidate all inactive vnodes.
802 * invalidate all cached file data.
803 * re-read volume header from disk.
804 * re-load meta-file info (extents, file size).
805 * re-load B-tree header data.
806 * re-read cnode data for all active vnodes.
807 */
808 int
809 hfs_reload(struct mount *mountp)
810 {
811 register struct vnode *devvp;
812 struct buf *bp;
813 int error, i;
814 struct hfsmount *hfsmp;
815 struct HFSPlusVolumeHeader *vhp;
816 ExtendedVCB *vcb;
817 struct filefork *forkp;
818 struct cat_desc cndesc;
819 struct hfs_reload_cargs args;
820 daddr64_t priIDSector;
821
822 hfsmp = VFSTOHFS(mountp);
823 vcb = HFSTOVCB(hfsmp);
824
825 if (vcb->vcbSigWord == kHFSSigWord)
826 return (EINVAL); /* rooting from HFS is not supported! */
827
828 /*
829 * Invalidate all cached meta-data.
830 */
831 devvp = hfsmp->hfs_devvp;
832 if (buf_invalidateblks(devvp, 0, 0, 0))
833 panic("hfs_reload: dirty1");
834
835 args.hfsmp = hfsmp;
836 args.error = 0;
837 /*
838 * hfs_reload_callback will be called for each vnode
839 * hung off of this mount point that can't be recycled...
840 * vnode_iterate will recycle those that it can (the VNODE_RELOAD option)
841 * the vnode will be in an 'unbusy' state (VNODE_WAIT) and
842 * properly referenced and unreferenced around the callback
843 */
844 vnode_iterate(mountp, VNODE_RELOAD | VNODE_WAIT, hfs_reload_callback, (void *)&args);
845
846 if (args.error)
847 return (args.error);
848
849 /*
850 * Re-read VolumeHeader from disk.
851 */
852 priIDSector = (daddr64_t)((vcb->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) +
853 HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size));
854
855 error = (int)buf_meta_bread(hfsmp->hfs_devvp,
856 HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys),
857 hfsmp->hfs_physical_block_size, NOCRED, &bp);
858 if (error) {
859 if (bp != NULL)
860 buf_brelse(bp);
861 return (error);
862 }
863
864 vhp = (HFSPlusVolumeHeader *) (buf_dataptr(bp) + HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
865
866 /* Do a quick sanity check */
867 if ((SWAP_BE16(vhp->signature) != kHFSPlusSigWord &&
868 SWAP_BE16(vhp->signature) != kHFSXSigWord) ||
869 (SWAP_BE16(vhp->version) != kHFSPlusVersion &&
870 SWAP_BE16(vhp->version) != kHFSXVersion) ||
871 SWAP_BE32(vhp->blockSize) != vcb->blockSize) {
872 buf_brelse(bp);
873 return (EIO);
874 }
875
876 vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate));
877 vcb->vcbAtrb = SWAP_BE32 (vhp->attributes);
878 vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
879 vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
880 vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
881 vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate));
882 vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
883 vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
884 vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
885 HFS_UPDATE_NEXT_ALLOCATION(vcb, SWAP_BE32 (vhp->nextAllocation));
886 vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
887 vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
888 vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
889 bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
890 vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */
891
892 /*
893 * Re-load meta-file vnode data (extent info, file size, etc).
894 */
895 forkp = VTOF((struct vnode *)vcb->extentsRefNum);
896 for (i = 0; i < kHFSPlusExtentDensity; i++) {
897 forkp->ff_extents[i].startBlock =
898 SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
899 forkp->ff_extents[i].blockCount =
900 SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
901 }
902 forkp->ff_size = SWAP_BE64 (vhp->extentsFile.logicalSize);
903 forkp->ff_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks);
904 forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize);
905
906
907 forkp = VTOF((struct vnode *)vcb->catalogRefNum);
908 for (i = 0; i < kHFSPlusExtentDensity; i++) {
909 forkp->ff_extents[i].startBlock =
910 SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
911 forkp->ff_extents[i].blockCount =
912 SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
913 }
914 forkp->ff_size = SWAP_BE64 (vhp->catalogFile.logicalSize);
915 forkp->ff_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks);
916 forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize);
917
918 if (hfsmp->hfs_attribute_vp) {
919 forkp = VTOF(hfsmp->hfs_attribute_vp);
920 for (i = 0; i < kHFSPlusExtentDensity; i++) {
921 forkp->ff_extents[i].startBlock =
922 SWAP_BE32 (vhp->attributesFile.extents[i].startBlock);
923 forkp->ff_extents[i].blockCount =
924 SWAP_BE32 (vhp->attributesFile.extents[i].blockCount);
925 }
926 forkp->ff_size = SWAP_BE64 (vhp->attributesFile.logicalSize);
927 forkp->ff_blocks = SWAP_BE32 (vhp->attributesFile.totalBlocks);
928 forkp->ff_clumpsize = SWAP_BE32 (vhp->attributesFile.clumpSize);
929 }
930
931 forkp = VTOF((struct vnode *)vcb->allocationsRefNum);
932 for (i = 0; i < kHFSPlusExtentDensity; i++) {
933 forkp->ff_extents[i].startBlock =
934 SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
935 forkp->ff_extents[i].blockCount =
936 SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
937 }
938 forkp->ff_size = SWAP_BE64 (vhp->allocationFile.logicalSize);
939 forkp->ff_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks);
940 forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize);
941
942 buf_brelse(bp);
943 vhp = NULL;
944
945 /*
946 * Re-load B-tree header data
947 */
948 forkp = VTOF((struct vnode *)vcb->extentsRefNum);
949 if ( (error = MacToVFSError( BTReloadData((FCB*)forkp) )) )
950 return (error);
951
952 forkp = VTOF((struct vnode *)vcb->catalogRefNum);
953 if ( (error = MacToVFSError( BTReloadData((FCB*)forkp) )) )
954 return (error);
955
956 if (hfsmp->hfs_attribute_vp) {
957 forkp = VTOF(hfsmp->hfs_attribute_vp);
958 if ( (error = MacToVFSError( BTReloadData((FCB*)forkp) )) )
959 return (error);
960 }
961
962 /* Reload the volume name */
963 if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, 0, 0, &cndesc, NULL, NULL)))
964 return (error);
965 vcb->volumeNameEncodingHint = cndesc.cd_encoding;
966 bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
967 cat_releasedesc(&cndesc);
968
969 /* Re-establish private/hidden directories. */
970 hfs_privatedir_init(hfsmp, FILE_HARDLINKS);
971 hfs_privatedir_init(hfsmp, DIR_HARDLINKS);
972
973 /* In case any volume information changed to trigger a notification */
974 hfs_generate_volume_notifications(hfsmp);
975
976 return (0);
977 }
978
979 __unused
980 static uint64_t tv_to_usecs(struct timeval *tv)
981 {
982 return tv->tv_sec * 1000000ULL + tv->tv_usec;
983 }
984
985 // Returns TRUE if b - a >= usecs
986 static bool hfs_has_elapsed (const struct timeval *a,
987 const struct timeval *b,
988 uint64_t usecs)
989 {
990 struct timeval diff;
991 timersub(b, a, &diff);
992 return diff.tv_sec * 1000000ULL + diff.tv_usec >= usecs;
993 }
994
995 void hfs_syncer(void *arg, __unused wait_result_t wr)
996 {
997 struct hfsmount *hfsmp = arg;
998 struct timeval now;
999
1000 KDBG(HFSDBG_SYNCER | DBG_FUNC_START, obfuscate_addr(hfsmp));
1001
1002 hfs_syncer_lock(hfsmp);
1003
1004 while (ISSET(hfsmp->hfs_flags, HFS_RUN_SYNCER)
1005 && timerisset(&hfsmp->hfs_sync_req_oldest)) {
1006
1007 hfs_syncer_wait(hfsmp, &HFS_META_DELAY_TS);
1008
1009 if (!ISSET(hfsmp->hfs_flags, HFS_RUN_SYNCER)
1010 || !timerisset(&hfsmp->hfs_sync_req_oldest)) {
1011 break;
1012 }
1013
1014 /* Check to see whether we should flush now: either the oldest
1015 is > HFS_MAX_META_DELAY or HFS_META_DELAY has elapsed since
1016 the request and there are no pending writes. */
1017
1018 microuptime(&now);
1019 uint64_t idle_time = vfs_idle_time(hfsmp->hfs_mp);
1020
1021 if (!hfs_has_elapsed(&hfsmp->hfs_sync_req_oldest, &now,
1022 HFS_MAX_META_DELAY)
1023 && idle_time < HFS_META_DELAY) {
1024 continue;
1025 }
1026
1027 timerclear(&hfsmp->hfs_sync_req_oldest);
1028
1029 hfs_syncer_unlock(hfsmp);
1030
1031 KDBG(HFSDBG_SYNCER_TIMED | DBG_FUNC_START, obfuscate_addr(hfsmp));
1032
1033 /*
1034 * We intentionally do a synchronous flush (of the journal or entire volume) here.
1035 * For journaled volumes, this means we wait until the metadata blocks are written
1036 * to both the journal and their final locations (in the B-trees, etc.).
1037 *
1038 * This tends to avoid interleaving the metadata writes with other writes (for
1039 * example, user data, or to the journal when a later transaction notices that
1040 * an earlier transaction has finished its async writes, and then updates the
1041 * journal start in the journal header). Avoiding interleaving of writes is
1042 * very good for performance on simple flash devices like SD cards, thumb drives;
1043 * and on devices like floppies. Since removable devices tend to be this kind of
1044 * simple device, doing a synchronous flush actually improves performance in
1045 * practice.
1046 *
1047 * NOTE: For non-journaled volumes, the call to hfs_sync will also cause dirty
1048 * user data to be written.
1049 */
1050 if (hfsmp->jnl) {
1051 hfs_flush(hfsmp, HFS_FLUSH_JOURNAL_META);
1052 } else {
1053 hfs_sync(hfsmp->hfs_mp, MNT_WAIT, vfs_context_current());
1054 }
1055
1056 KDBG(HFSDBG_SYNCER_TIMED | DBG_FUNC_END);
1057
1058 hfs_syncer_lock(hfsmp);
1059 } // while (...)
1060
1061 hfsmp->hfs_syncer_thread = NULL;
1062 hfs_syncer_unlock(hfsmp);
1063 hfs_syncer_wakeup(hfsmp);
1064
1065 /* BE CAREFUL WHAT YOU ADD HERE: at this point hfs_unmount is free
1066 to continue and therefore hfsmp might be invalid. */
1067
1068 KDBG(HFSDBG_SYNCER | DBG_FUNC_END);
1069 }
1070
1071 /*
1072 * Call into the allocator code and perform a full scan of the bitmap file.
1073 *
1074 * This allows us to TRIM unallocated ranges if needed, and also to build up
1075 * an in-memory summary table of the state of the allocated blocks.
1076 */
1077 void hfs_scan_blocks (struct hfsmount *hfsmp) {
1078 /*
1079 * Take the allocation file lock. Journal transactions will block until
1080 * we're done here.
1081 */
1082
1083 int flags = hfs_systemfile_lock(hfsmp, SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
1084
1085 /*
1086 * We serialize here with the HFS mount lock as we're mounting.
1087 *
1088 * The mount can only proceed once this thread has acquired the bitmap
1089 * lock, since we absolutely do not want someone else racing in and
1090 * getting the bitmap lock, doing a read/write of the bitmap file,
1091 * then us getting the bitmap lock.
1092 *
1093 * To prevent this, the mount thread takes the HFS mount mutex, starts us
1094 * up, then immediately msleeps on the scan_var variable in the mount
1095 * point as a condition variable. This serialization is safe since
1096 * if we race in and try to proceed while they're still holding the lock,
1097 * we'll block trying to acquire the global lock. Since the mount thread
1098 * acquires the HFS mutex before starting this function in a new thread,
1099 * any lock acquisition on our part must be linearizably AFTER the mount thread's.
1100 *
1101 * Note that the HFS mount mutex is always taken last, and always for only
1102 * a short time. In this case, we just take it long enough to mark the
1103 * scan-in-flight bit.
1104 */
1105 (void) hfs_lock_mount (hfsmp);
1106 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_INFLIGHT;
1107 wakeup((caddr_t) &hfsmp->scan_var);
1108 hfs_unlock_mount (hfsmp);
1109
1110 /* Initialize the summary table */
1111 if (hfs_init_summary (hfsmp)) {
1112 printf("hfs: could not initialize summary table for %s\n", hfsmp->vcbVN);
1113 }
1114
1115 /*
1116 * ScanUnmapBlocks assumes that the bitmap lock is held when you
1117 * call the function. We don't care if there were any errors issuing unmaps.
1118 *
1119 * It will also attempt to build up the summary table for subsequent
1120 * allocator use, as configured.
1121 */
1122 (void) ScanUnmapBlocks(hfsmp);
1123
1124 (void) hfs_lock_mount (hfsmp);
1125 hfsmp->scan_var &= ~HFS_ALLOCATOR_SCAN_INFLIGHT;
1126 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_COMPLETED;
1127 wakeup((caddr_t) &hfsmp->scan_var);
1128 hfs_unlock_mount (hfsmp);
1129
1130 buf_invalidateblks(hfsmp->hfs_allocation_vp, 0, 0, 0);
1131
1132 hfs_systemfile_unlock(hfsmp, flags);
1133
1134 }
1135
1136 /*
1137 * Common code for mount and mountroot
1138 */
1139 int
1140 hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args,
1141 int journal_replay_only, vfs_context_t context)
1142 {
1143 struct proc *p = vfs_context_proc(context);
1144 int retval = E_NONE;
1145 struct hfsmount *hfsmp = NULL;
1146 struct buf *bp;
1147 dev_t dev;
1148 HFSMasterDirectoryBlock *mdbp = NULL;
1149 int ronly;
1150 #if QUOTA
1151 int i;
1152 #endif
1153 int mntwrapper;
1154 kauth_cred_t cred;
1155 u_int64_t disksize;
1156 daddr64_t log_blkcnt;
1157 u_int32_t log_blksize;
1158 u_int32_t phys_blksize;
1159 u_int32_t minblksize;
1160 u_int32_t iswritable;
1161 daddr64_t mdb_offset;
1162 int isvirtual = 0;
1163 int isroot = !journal_replay_only && args == NULL;
1164 u_int32_t device_features = 0;
1165 int isssd;
1166
1167 ronly = mp && vfs_isrdonly(mp);
1168 dev = vnode_specrdev(devvp);
1169 cred = p ? vfs_context_ucred(context) : NOCRED;
1170 mntwrapper = 0;
1171
1172 bp = NULL;
1173 hfsmp = NULL;
1174 mdbp = NULL;
1175 minblksize = kHFSBlockSize;
1176
1177 /* Advisory locking should be handled at the VFS layer */
1178 if (mp)
1179 vfs_setlocklocal(mp);
1180
1181 /* Get the logical block size (treated as physical block size everywhere) */
1182 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&log_blksize, 0, context)) {
1183 if (HFS_MOUNT_DEBUG) {
1184 printf("hfs_mountfs: DKIOCGETBLOCKSIZE failed\n");
1185 }
1186 retval = ENXIO;
1187 goto error_exit;
1188 }
1189 if (log_blksize == 0 || log_blksize > 1024*1024*1024) {
1190 printf("hfs: logical block size 0x%x looks bad. Not mounting.\n", log_blksize);
1191 retval = ENXIO;
1192 goto error_exit;
1193 }
1194
1195 /* Get the physical block size. */
1196 retval = VNOP_IOCTL(devvp, DKIOCGETPHYSICALBLOCKSIZE, (caddr_t)&phys_blksize, 0, context);
1197 if (retval) {
1198 if ((retval != ENOTSUP) && (retval != ENOTTY)) {
1199 if (HFS_MOUNT_DEBUG) {
1200 printf("hfs_mountfs: DKIOCGETPHYSICALBLOCKSIZE failed\n");
1201 }
1202 retval = ENXIO;
1203 goto error_exit;
1204 }
1205 /* If device does not support this ioctl, assume that physical
1206 * block size is same as logical block size
1207 */
1208 phys_blksize = log_blksize;
1209 }
1210 if (phys_blksize == 0 || phys_blksize > MAXBSIZE) {
1211 printf("hfs: physical block size 0x%x looks bad. Not mounting.\n", phys_blksize);
1212 retval = ENXIO;
1213 goto error_exit;
1214 }
1215
1216 /* Switch to 512 byte sectors (temporarily) */
1217 if (log_blksize > 512) {
1218 u_int32_t size512 = 512;
1219
1220 if (VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, context)) {
1221 if (HFS_MOUNT_DEBUG) {
1222 printf("hfs_mountfs: DKIOCSETBLOCKSIZE failed \n");
1223 }
1224 retval = ENXIO;
1225 goto error_exit;
1226 }
1227 }
1228 /* Get the number of 512 byte physical blocks. */
1229 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&log_blkcnt, 0, context)) {
1230 /* resetting block size may fail if getting block count did */
1231 (void)VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&log_blksize, FWRITE, context);
1232 if (HFS_MOUNT_DEBUG) {
1233 printf("hfs_mountfs: DKIOCGETBLOCKCOUNT failed\n");
1234 }
1235 retval = ENXIO;
1236 goto error_exit;
1237 }
1238 /* Compute an accurate disk size (i.e. within 512 bytes) */
1239 disksize = (u_int64_t)log_blkcnt * (u_int64_t)512;
1240
1241 /*
1242 * On Tiger it is not necessary to switch the device
1243 * block size to be 4k if there are more than 31-bits
1244 * worth of blocks but to insure compatibility with
1245 * pre-Tiger systems we have to do it.
1246 *
1247 * If the device size is not a multiple of 4K (8 * 512), then
1248 * switching the logical block size isn't going to help because
1249 * we will be unable to write the alternate volume header.
1250 * In this case, just leave the logical block size unchanged.
1251 */
1252 if (log_blkcnt > 0x000000007fffffff && (log_blkcnt & 7) == 0) {
1253 minblksize = log_blksize = 4096;
1254 if (phys_blksize < log_blksize)
1255 phys_blksize = log_blksize;
1256 }
1257
1258 /*
1259 * The cluster layer is not currently prepared to deal with a logical
1260 * block size larger than the system's page size. (It can handle
1261 * blocks per page, but not multiple pages per block.) So limit the
1262 * logical block size to the page size.
1263 */
1264 if (log_blksize > PAGE_SIZE) {
1265 log_blksize = PAGE_SIZE;
1266 }
1267
1268 /* Now switch to our preferred physical block size. */
1269 if (log_blksize > 512) {
1270 if (VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&log_blksize, FWRITE, context)) {
1271 if (HFS_MOUNT_DEBUG) {
1272 printf("hfs_mountfs: DKIOCSETBLOCKSIZE (2) failed\n");
1273 }
1274 retval = ENXIO;
1275 goto error_exit;
1276 }
1277 /* Get the count of physical blocks. */
1278 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&log_blkcnt, 0, context)) {
1279 if (HFS_MOUNT_DEBUG) {
1280 printf("hfs_mountfs: DKIOCGETBLOCKCOUNT (2) failed\n");
1281 }
1282 retval = ENXIO;
1283 goto error_exit;
1284 }
1285 }
1286 /*
1287 * At this point:
1288 * minblksize is the minimum physical block size
1289 * log_blksize has our preferred physical block size
1290 * log_blkcnt has the total number of physical blocks
1291 */
1292
1293 mdb_offset = (daddr64_t)HFS_PRI_SECTOR(log_blksize);
1294 if ((retval = (int)buf_meta_bread(devvp,
1295 HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (phys_blksize/log_blksize)),
1296 phys_blksize, cred, &bp))) {
1297 if (HFS_MOUNT_DEBUG) {
1298 printf("hfs_mountfs: buf_meta_bread failed with %d\n", retval);
1299 }
1300 goto error_exit;
1301 }
1302 mdbp = hfs_malloc(kMDBSize);
1303 bcopy((char *)buf_dataptr(bp) + HFS_PRI_OFFSET(phys_blksize), mdbp, kMDBSize);
1304 buf_brelse(bp);
1305 bp = NULL;
1306
1307 hfsmp = hfs_mallocz(sizeof(struct hfsmount));
1308
1309 hfs_chashinit_finish(hfsmp);
1310
1311 /* Init the ID lookup hashtable */
1312 hfs_idhash_init (hfsmp);
1313
1314 /*
1315 * See if the disk supports unmap (trim).
1316 *
1317 * NOTE: vfs_init_io_attributes has not been called yet, so we can't use the io_flags field
1318 * returned by vfs_ioattr. We need to call VNOP_IOCTL ourselves.
1319 */
1320 if (VNOP_IOCTL(devvp, DKIOCGETFEATURES, (caddr_t)&device_features, 0, context) == 0) {
1321 if (device_features & DK_FEATURE_UNMAP) {
1322 hfsmp->hfs_flags |= HFS_UNMAP;
1323 }
1324
1325 if(device_features & DK_FEATURE_BARRIER)
1326 hfsmp->hfs_flags |= HFS_FEATURE_BARRIER;
1327 }
1328
1329 /*
1330 * See if the disk is a solid state device, too. We need this to decide what to do about
1331 * hotfiles.
1332 */
1333 if (VNOP_IOCTL(devvp, DKIOCISSOLIDSTATE, (caddr_t)&isssd, 0, context) == 0) {
1334 if (isssd) {
1335 hfsmp->hfs_flags |= HFS_SSD;
1336 }
1337 }
1338
1339 /* See if the underlying device is Core Storage or not */
1340 dk_corestorage_info_t cs_info;
1341 memset(&cs_info, 0, sizeof(dk_corestorage_info_t));
1342 if (VNOP_IOCTL(devvp, DKIOCCORESTORAGE, (caddr_t)&cs_info, 0, context) == 0) {
1343 hfsmp->hfs_flags |= HFS_CS;
1344 if (isroot && (cs_info.flags & DK_CORESTORAGE_PIN_YOUR_METADATA)) {
1345 hfsmp->hfs_flags |= HFS_CS_METADATA_PIN;
1346 }
1347 if (isroot && (cs_info.flags & DK_CORESTORAGE_ENABLE_HOTFILES)) {
1348 hfsmp->hfs_flags |= HFS_CS_HOTFILE_PIN;
1349 hfsmp->hfs_cs_hotfile_size = cs_info.hotfile_size;
1350 }
1351 if ((cs_info.flags & DK_CORESTORAGE_PIN_YOUR_SWAPFILE)) {
1352 hfsmp->hfs_flags |= HFS_CS_SWAPFILE_PIN;
1353
1354 struct vfsioattr ioattr;
1355 vfs_ioattr(mp, &ioattr);
1356 ioattr.io_flags |= VFS_IOATTR_FLAGS_SWAPPIN_SUPPORTED;
1357 ioattr.io_max_swappin_available = cs_info.swapfile_pinning;
1358 vfs_setioattr(mp, &ioattr);
1359 }
1360 }
1361
1362 /*
1363 * Init the volume information structure
1364 */
1365
1366 lck_mtx_init(&hfsmp->hfs_mutex, hfs_mutex_group, hfs_lock_attr);
1367 lck_mtx_init(&hfsmp->hfc_mutex, hfs_mutex_group, hfs_lock_attr);
1368 lck_rw_init(&hfsmp->hfs_global_lock, hfs_rwlock_group, hfs_lock_attr);
1369 lck_spin_init(&hfsmp->vcbFreeExtLock, hfs_spinlock_group, hfs_lock_attr);
1370
1371 if (mp)
1372 vfs_setfsprivate(mp, hfsmp);
1373 hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
1374 hfsmp->hfs_raw_dev = vnode_specrdev(devvp);
1375 hfsmp->hfs_devvp = devvp;
1376 vnode_ref(devvp); /* Hold a ref on the device, dropped when hfsmp is freed. */
1377 hfsmp->hfs_logical_block_size = log_blksize;
1378 hfsmp->hfs_logical_block_count = log_blkcnt;
1379 hfsmp->hfs_logical_bytes = (uint64_t) log_blksize * (uint64_t) log_blkcnt;
1380 hfsmp->hfs_physical_block_size = phys_blksize;
1381 hfsmp->hfs_log_per_phys = (phys_blksize / log_blksize);
1382 hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA;
1383 if (ronly)
1384 hfsmp->hfs_flags |= HFS_READ_ONLY;
1385 if (mp && ((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS)
1386 hfsmp->hfs_flags |= HFS_UNKNOWN_PERMS;
1387
1388 #if QUOTA
1389 for (i = 0; i < MAXQUOTAS; i++)
1390 dqfileinit(&hfsmp->hfs_qfiles[i]);
1391 #endif
1392
1393 if (args) {
1394 hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
1395 if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
1396 hfsmp->hfs_gid = (args->hfs_gid == (gid_t)VNOVAL) ? UNKNOWNGID : args->hfs_gid;
1397 if (hfsmp->hfs_gid == 0xfffffffd) hfsmp->hfs_gid = UNKNOWNGID;
1398 vfs_setowner(mp, hfsmp->hfs_uid, hfsmp->hfs_gid); /* tell the VFS */
1399 if (args->hfs_mask != (mode_t)VNOVAL) {
1400 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
1401 if (args->flags & HFSFSMNT_NOXONFILES) {
1402 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
1403 } else {
1404 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
1405 }
1406 } else {
1407 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
1408 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
1409 }
1410 if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
1411 mntwrapper = 1;
1412 } else {
1413 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
1414 if (mp && ((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS) {
1415 hfsmp->hfs_uid = UNKNOWNUID;
1416 hfsmp->hfs_gid = UNKNOWNGID;
1417 vfs_setowner(mp, hfsmp->hfs_uid, hfsmp->hfs_gid); /* tell the VFS */
1418 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
1419 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
1420 }
1421 }
1422
1423 /* Find out if disk media is writable. */
1424 if (VNOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, context) == 0) {
1425 if (iswritable)
1426 hfsmp->hfs_flags |= HFS_WRITEABLE_MEDIA;
1427 else
1428 hfsmp->hfs_flags &= ~HFS_WRITEABLE_MEDIA;
1429 }
1430
1431 // Reservations
1432 rl_init(&hfsmp->hfs_reserved_ranges[0]);
1433 rl_init(&hfsmp->hfs_reserved_ranges[1]);
1434
1435 // record the current time at which we're mounting this volume
1436 struct timeval tv;
1437 microtime(&tv);
1438 hfsmp->hfs_mount_time = tv.tv_sec;
1439
1440 /* Mount a standard HFS disk */
1441 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
1442 (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
1443 #if CONFIG_HFS_STD
1444 /* If only journal replay is requested, exit immediately */
1445 if (journal_replay_only) {
1446 retval = 0;
1447 goto error_exit;
1448 }
1449
1450 /* On 10.6 and beyond, non read-only mounts for HFS standard vols get rejected */
1451 if (vfs_isrdwr(mp)) {
1452 retval = EROFS;
1453 goto error_exit;
1454 }
1455
1456 printf("hfs_mountfs: Mounting HFS Standard volumes was deprecated in Mac OS 10.7 \n");
1457
1458 /* Treat it as if it's read-only and not writeable */
1459 hfsmp->hfs_flags |= HFS_READ_ONLY;
1460 hfsmp->hfs_flags &= ~HFS_WRITEABLE_MEDIA;
1461
1462 if ((vfs_flags(mp) & MNT_ROOTFS)) {
1463 retval = EINVAL; /* Cannot root from HFS standard disks */
1464 goto error_exit;
1465 }
1466 /* HFS disks can only use 512 byte physical blocks */
1467 if (log_blksize > kHFSBlockSize) {
1468 log_blksize = kHFSBlockSize;
1469 if (VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&log_blksize, FWRITE, context)) {
1470 retval = ENXIO;
1471 goto error_exit;
1472 }
1473 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&log_blkcnt, 0, context)) {
1474 retval = ENXIO;
1475 goto error_exit;
1476 }
1477 hfsmp->hfs_logical_block_size = log_blksize;
1478 hfsmp->hfs_logical_block_count = log_blkcnt;
1479 hfsmp->hfs_logical_bytes = (uint64_t) log_blksize * (uint64_t) log_blkcnt;
1480 hfsmp->hfs_physical_block_size = log_blksize;
1481 hfsmp->hfs_log_per_phys = 1;
1482 }
1483 if (args) {
1484 hfsmp->hfs_encoding = args->hfs_encoding;
1485 HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
1486
1487 /* establish the timezone */
1488 gTimeZone = args->hfs_timezone;
1489 }
1490
1491 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
1492 &hfsmp->hfs_get_hfsname);
1493 if (retval)
1494 goto error_exit;
1495
1496 retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
1497 if (retval)
1498 (void) hfs_relconverter(hfsmp->hfs_encoding);
1499 #else
1500 /* On platforms where HFS Standard is not supported, deny the mount altogether */
1501 retval = EINVAL;
1502 goto error_exit;
1503 #endif
1504
1505 }
1506 else { /* Mount an HFS Plus disk */
1507 HFSPlusVolumeHeader *vhp;
1508 off_t embeddedOffset;
1509 int jnl_disable = 0;
1510
1511 /* Get the embedded Volume Header */
1512 if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
1513 embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
1514 embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
1515 (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1516
1517 /*
1518 * Cooperative Fusion is not allowed on embedded HFS+
1519 * filesystems (HFS+ inside HFS standard wrapper)
1520 */
1521 hfsmp->hfs_flags &= ~HFS_CS_METADATA_PIN;
1522
1523 /*
1524 * If the embedded volume doesn't start on a block
1525 * boundary, then switch the device to a 512-byte
1526 * block size so everything will line up on a block
1527 * boundary.
1528 */
1529 if ((embeddedOffset % log_blksize) != 0) {
1530 printf("hfs_mountfs: embedded volume offset not"
1531 " a multiple of physical block size (%d);"
1532 " switching to 512\n", log_blksize);
1533 log_blksize = 512;
1534 if (VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
1535 (caddr_t)&log_blksize, FWRITE, context)) {
1536
1537 if (HFS_MOUNT_DEBUG) {
1538 printf("hfs_mountfs: DKIOCSETBLOCKSIZE (3) failed\n");
1539 }
1540 retval = ENXIO;
1541 goto error_exit;
1542 }
1543 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT,
1544 (caddr_t)&log_blkcnt, 0, context)) {
1545 if (HFS_MOUNT_DEBUG) {
1546 printf("hfs_mountfs: DKIOCGETBLOCKCOUNT (3) failed\n");
1547 }
1548 retval = ENXIO;
1549 goto error_exit;
1550 }
1551 /* Note: relative block count adjustment */
1552 hfsmp->hfs_logical_block_count *=
1553 hfsmp->hfs_logical_block_size / log_blksize;
1554
1555 /* Update logical /physical block size */
1556 hfsmp->hfs_logical_block_size = log_blksize;
1557 hfsmp->hfs_physical_block_size = log_blksize;
1558
1559 phys_blksize = log_blksize;
1560 hfsmp->hfs_log_per_phys = 1;
1561 }
1562
1563 disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) *
1564 (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1565
1566 hfsmp->hfs_logical_block_count = disksize / log_blksize;
1567
1568 hfsmp->hfs_logical_bytes = (uint64_t) hfsmp->hfs_logical_block_count * (uint64_t) hfsmp->hfs_logical_block_size;
1569
1570 mdb_offset = (daddr64_t)((embeddedOffset / log_blksize) + HFS_PRI_SECTOR(log_blksize));
1571
1572 if (bp) {
1573 buf_markinvalid(bp);
1574 buf_brelse(bp);
1575 bp = NULL;
1576 }
1577 retval = (int)buf_meta_bread(devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, hfsmp->hfs_log_per_phys),
1578 phys_blksize, cred, &bp);
1579 if (retval) {
1580 if (HFS_MOUNT_DEBUG) {
1581 printf("hfs_mountfs: buf_meta_bread (2) failed with %d\n", retval);
1582 }
1583 goto error_exit;
1584 }
1585 bcopy((char *)buf_dataptr(bp) + HFS_PRI_OFFSET(phys_blksize), mdbp, 512);
1586 buf_brelse(bp);
1587 bp = NULL;
1588 vhp = (HFSPlusVolumeHeader*) mdbp;
1589
1590 }
1591 else { /* pure HFS+ */
1592 embeddedOffset = 0;
1593 vhp = (HFSPlusVolumeHeader*) mdbp;
1594 }
1595
1596 retval = hfs_ValidateHFSPlusVolumeHeader(hfsmp, vhp);
1597 if (retval)
1598 goto error_exit;
1599
1600 /*
1601 * If allocation block size is less than the physical block size,
1602 * invalidate the buffer read in using native physical block size
1603 * to ensure data consistency.
1604 *
1605 * HFS Plus reserves one allocation block for the Volume Header.
1606 * If the physical size is larger, then when we read the volume header,
1607 * we will also end up reading in the next allocation block(s).
1608 * If those other allocation block(s) is/are modified, and then the volume
1609 * header is modified, the write of the volume header's buffer will write
1610 * out the old contents of the other allocation blocks.
1611 *
1612 * We assume that the physical block size is same as logical block size.
1613 * The physical block size value is used to round down the offsets for
1614 * reading and writing the primary and alternate volume headers.
1615 *
1616 * The same logic is also in hfs_MountHFSPlusVolume to ensure that
1617 * hfs_mountfs, hfs_MountHFSPlusVolume and later are doing the I/Os
1618 * using same block size.
1619 */
1620 if (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_physical_block_size) {
1621 phys_blksize = hfsmp->hfs_logical_block_size;
1622 hfsmp->hfs_physical_block_size = hfsmp->hfs_logical_block_size;
1623 hfsmp->hfs_log_per_phys = 1;
1624 // There should be one bp associated with devvp in buffer cache.
1625 retval = buf_invalidateblks(devvp, 0, 0, 0);
1626 if (retval)
1627 goto error_exit;
1628 }
1629
1630 if (isroot && ((SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) != 0)) {
1631 vfs_set_root_unmounted_cleanly();
1632 }
1633
1634 /*
1635 * On inconsistent disks, do not allow read-write mount
1636 * unless it is the boot volume being mounted. We also
1637 * always want to replay the journal if the journal_replay_only
1638 * flag is set because that will (most likely) get the
1639 * disk into a consistent state before fsck_hfs starts
1640 * looking at it.
1641 */
1642 if (!journal_replay_only
1643 && !(vfs_flags(mp) & MNT_ROOTFS)
1644 && (SWAP_BE32(vhp->attributes) & kHFSVolumeInconsistentMask)
1645 && !(hfsmp->hfs_flags & HFS_READ_ONLY)) {
1646
1647 if (HFS_MOUNT_DEBUG) {
1648 printf("hfs_mountfs: failed to mount non-root inconsistent disk\n");
1649 }
1650 retval = EINVAL;
1651 goto error_exit;
1652 }
1653
1654
1655 // XXXdbg
1656 //
1657 hfsmp->jnl = NULL;
1658 hfsmp->jvp = NULL;
1659 if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) &&
1660 args->journal_disable) {
1661 jnl_disable = 1;
1662 }
1663
1664 //
1665 // We only initialize the journal here if the last person
1666 // to mount this volume was journaling aware. Otherwise
1667 // we delay journal initialization until later at the end
1668 // of hfs_MountHFSPlusVolume() because the last person who
1669 // mounted it could have messed things up behind our back
1670 // (so we need to go find the .journal file, make sure it's
1671 // the right size, re-sync up if it was moved, etc).
1672 //
1673 if ( (SWAP_BE32(vhp->lastMountedVersion) == kHFSJMountVersion)
1674 && (SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask)
1675 && !jnl_disable) {
1676
1677 // if we're able to init the journal, mark the mount
1678 // point as journaled.
1679 //
1680 if ((retval = hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred)) == 0) {
1681 if (mp)
1682 vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_JOURNALED));
1683 } else {
1684 if (retval == EROFS) {
1685 // EROFS is a special error code that means the volume has an external
1686 // journal which we couldn't find. in that case we do not want to
1687 // rewrite the volume header - we'll just refuse to mount the volume.
1688 if (HFS_MOUNT_DEBUG) {
1689 printf("hfs_mountfs: hfs_early_journal_init indicated external jnl \n");
1690 }
1691 retval = EINVAL;
1692 goto error_exit;
1693 }
1694
1695 // if the journal failed to open, then set the lastMountedVersion
1696 // to be "FSK!" which fsck_hfs will see and force the fsck instead
1697 // of just bailing out because the volume is journaled.
1698 if (!ronly) {
1699 if (HFS_MOUNT_DEBUG) {
1700 printf("hfs_mountfs: hfs_early_journal_init failed, setting to FSK \n");
1701 }
1702
1703 HFSPlusVolumeHeader *jvhp;
1704
1705 hfsmp->hfs_flags |= HFS_NEED_JNL_RESET;
1706
1707 if (mdb_offset == 0) {
1708 mdb_offset = (daddr64_t)((embeddedOffset / log_blksize) + HFS_PRI_SECTOR(log_blksize));
1709 }
1710
1711 bp = NULL;
1712 retval = (int)buf_meta_bread(devvp,
1713 HFS_PHYSBLK_ROUNDDOWN(mdb_offset, hfsmp->hfs_log_per_phys),
1714 phys_blksize, cred, &bp);
1715 if (retval == 0) {
1716 jvhp = (HFSPlusVolumeHeader *)(buf_dataptr(bp) + HFS_PRI_OFFSET(phys_blksize));
1717
1718 if (SWAP_BE16(jvhp->signature) == kHFSPlusSigWord || SWAP_BE16(jvhp->signature) == kHFSXSigWord) {
1719 printf ("hfs(1): Journal replay fail. Writing lastMountVersion as FSK!\n");
1720 jvhp->lastMountedVersion = SWAP_BE32(kFSKMountVersion);
1721 buf_bwrite(bp);
1722 } else {
1723 buf_brelse(bp);
1724 }
1725 bp = NULL;
1726 } else if (bp) {
1727 buf_brelse(bp);
1728 // clear this so the error exit path won't try to use it
1729 bp = NULL;
1730 }
1731 }
1732
1733 // if this isn't the root device just bail out.
1734 // If it is the root device we just continue on
1735 // in the hopes that fsck_hfs will be able to
1736 // fix any damage that exists on the volume.
1737 if (mp && !(vfs_flags(mp) & MNT_ROOTFS)) {
1738 if (HFS_MOUNT_DEBUG) {
1739 printf("hfs_mountfs: hfs_early_journal_init failed, erroring out \n");
1740 }
1741 retval = EINVAL;
1742 goto error_exit;
1743 }
1744 }
1745 }
1746
1747 /* Either the journal is replayed successfully, or there
1748 * was nothing to replay, or no journal exists. In any case,
1749 * return success.
1750 */
1751 if (journal_replay_only) {
1752 retval = 0;
1753 goto error_exit;
1754 }
1755
1756 #if CONFIG_HFS_STD
1757 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
1758 #endif
1759
1760 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args, cred);
1761 /*
1762 * If the backend didn't like our physical blocksize
1763 * then retry with physical blocksize of 512.
1764 */
1765 if ((retval == ENXIO) && (log_blksize > 512) && (log_blksize != minblksize)) {
1766 printf("hfs_mountfs: could not use physical block size "
1767 "(%d) switching to 512\n", log_blksize);
1768 log_blksize = 512;
1769 if (VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&log_blksize, FWRITE, context)) {
1770 if (HFS_MOUNT_DEBUG) {
1771 printf("hfs_mountfs: DKIOCSETBLOCKSIZE (4) failed \n");
1772 }
1773 retval = ENXIO;
1774 goto error_exit;
1775 }
1776 if (VNOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&log_blkcnt, 0, context)) {
1777 if (HFS_MOUNT_DEBUG) {
1778 printf("hfs_mountfs: DKIOCGETBLOCKCOUNT (4) failed \n");
1779 }
1780 retval = ENXIO;
1781 goto error_exit;
1782 }
1783 set_fsblocksize(devvp);
1784 /* Note: relative block count adjustment (in case this is an embedded volume). */
1785 hfsmp->hfs_logical_block_count *= hfsmp->hfs_logical_block_size / log_blksize;
1786 hfsmp->hfs_logical_block_size = log_blksize;
1787 hfsmp->hfs_log_per_phys = hfsmp->hfs_physical_block_size / log_blksize;
1788
1789 hfsmp->hfs_logical_bytes = (uint64_t) hfsmp->hfs_logical_block_count * (uint64_t) hfsmp->hfs_logical_block_size;
1790
1791 if (hfsmp->jnl && hfsmp->jvp == devvp) {
1792 // close and re-open this with the new block size
1793 journal_close(hfsmp->jnl);
1794 hfsmp->jnl = NULL;
1795 if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
1796 vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_JOURNALED));
1797 } else {
1798 // if the journal failed to open, then set the lastMountedVersion
1799 // to be "FSK!" which fsck_hfs will see and force the fsck instead
1800 // of just bailing out because the volume is journaled.
1801 if (!ronly) {
1802 if (HFS_MOUNT_DEBUG) {
1803 printf("hfs_mountfs: hfs_early_journal_init (2) resetting.. \n");
1804 }
1805 HFSPlusVolumeHeader *jvhp;
1806
1807 hfsmp->hfs_flags |= HFS_NEED_JNL_RESET;
1808
1809 if (mdb_offset == 0) {
1810 mdb_offset = (daddr64_t)((embeddedOffset / log_blksize) + HFS_PRI_SECTOR(log_blksize));
1811 }
1812
1813 bp = NULL;
1814 retval = (int)buf_meta_bread(devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, hfsmp->hfs_log_per_phys),
1815 phys_blksize, cred, &bp);
1816 if (retval == 0) {
1817 jvhp = (HFSPlusVolumeHeader *)(buf_dataptr(bp) + HFS_PRI_OFFSET(phys_blksize));
1818
1819 if (SWAP_BE16(jvhp->signature) == kHFSPlusSigWord || SWAP_BE16(jvhp->signature) == kHFSXSigWord) {
1820 printf ("hfs(2): Journal replay fail. Writing lastMountVersion as FSK!\n");
1821 jvhp->lastMountedVersion = SWAP_BE32(kFSKMountVersion);
1822 buf_bwrite(bp);
1823 } else {
1824 buf_brelse(bp);
1825 }
1826 bp = NULL;
1827 } else if (bp) {
1828 buf_brelse(bp);
1829 // clear this so the error exit path won't try to use it
1830 bp = NULL;
1831 }
1832 }
1833
1834 // if this isn't the root device just bail out.
1835 // If it is the root device we just continue on
1836 // in the hopes that fsck_hfs will be able to
1837 // fix any damage that exists on the volume.
1838 if ( !(vfs_flags(mp) & MNT_ROOTFS)) {
1839 if (HFS_MOUNT_DEBUG) {
1840 printf("hfs_mountfs: hfs_early_journal_init (2) failed \n");
1841 }
1842 retval = EINVAL;
1843 goto error_exit;
1844 }
1845 }
1846 }
1847
1848 /* Try again with a smaller block size... */
1849 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args, cred);
1850 if (retval && HFS_MOUNT_DEBUG) {
1851 printf("hfs_MountHFSPlusVolume (late) returned %d\n",retval);
1852 }
1853 }
1854 #if CONFIG_HFS_STD
1855 if (retval)
1856 (void) hfs_relconverter(0);
1857 #endif
1858 }
1859
1860 // save off a snapshot of the mtime from the previous mount
1861 // (for matador).
1862 hfsmp->hfs_last_mounted_mtime = hfsmp->hfs_mtime;
1863
1864 if ( retval ) {
1865 if (HFS_MOUNT_DEBUG) {
1866 printf("hfs_mountfs: encountered failure %d \n", retval);
1867 }
1868 goto error_exit;
1869 }
1870
1871 struct vfsstatfs *vsfs = vfs_statfs(mp);
1872 vsfs->f_fsid.val[0] = dev;
1873 vsfs->f_fsid.val[1] = vfs_typenum(mp);
1874
1875 vfs_setmaxsymlen(mp, 0);
1876
1877 #if CONFIG_HFS_STD
1878 if (ISSET(hfsmp->hfs_flags, HFS_STANDARD)) {
1879 /* HFS standard doesn't support extended readdir! */
1880 mount_set_noreaddirext (mp);
1881 }
1882 #endif
1883
1884 if (args) {
1885 /*
1886 * Set the free space warning levels for a non-root volume:
1887 *
1888 * Set the "danger" limit to 1% of the volume size or 150MB, whichever is less.
1889 * Set the "warning" limit to 2% of the volume size or 500MB, whichever is less.
1890 * Set the "near warning" limit to 10% of the volume size or 1GB, whichever is less.
1891 * And last, set the "desired" freespace level to to 12% of the volume size or 1.2GB,
1892 * whichever is less.
1893 */
1894 hfsmp->hfs_freespace_notify_dangerlimit =
1895 MIN(HFS_VERYLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1896 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_VERYLOWDISKTRIGGERFRACTION);
1897 hfsmp->hfs_freespace_notify_warninglimit =
1898 MIN(HFS_LOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1899 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKTRIGGERFRACTION);
1900 hfsmp->hfs_freespace_notify_nearwarninglimit =
1901 MIN(HFS_NEARLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1902 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_NEARLOWDISKTRIGGERFRACTION);
1903 hfsmp->hfs_freespace_notify_desiredlevel =
1904 MIN(HFS_LOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize,
1905 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_LOWDISKSHUTOFFFRACTION);
1906 } else {
1907 /*
1908 * Set the free space warning levels for the root volume:
1909 *
1910 * Set the "danger" limit to 5% of the volume size or 512MB, whichever is less.
1911 * Set the "warning" limit to 10% of the volume size or 1GB, whichever is less.
1912 * Set the "near warning" limit to 10.5% of the volume size or 1.1GB, whichever is less.
1913 * And last, set the "desired" freespace level to to 11% of the volume size or 1.25GB,
1914 * whichever is less.
1915 *
1916 * NOTE: While those are the default limits, KernelEventAgent (as of 3/2016)
1917 * will unilaterally override these to the following on OSX only:
1918 * Danger: 3GB
1919 * Warning: Min (2% of root volume, 10GB), with a floor of 10GB
1920 * Desired: Warning Threshold + 1.5GB
1921 */
1922 hfsmp->hfs_freespace_notify_dangerlimit =
1923 MIN(HFS_ROOTVERYLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1924 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTVERYLOWDISKTRIGGERFRACTION);
1925 hfsmp->hfs_freespace_notify_warninglimit =
1926 MIN(HFS_ROOTLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1927 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKTRIGGERFRACTION);
1928 hfsmp->hfs_freespace_notify_nearwarninglimit =
1929 MIN(HFS_ROOTNEARLOWDISKTRIGGERLEVEL / HFSTOVCB(hfsmp)->blockSize,
1930 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTNEARLOWDISKTRIGGERFRACTION);
1931 hfsmp->hfs_freespace_notify_desiredlevel =
1932 MIN(HFS_ROOTLOWDISKSHUTOFFLEVEL / HFSTOVCB(hfsmp)->blockSize,
1933 (HFSTOVCB(hfsmp)->totalBlocks / 100) * HFS_ROOTLOWDISKSHUTOFFFRACTION);
1934 };
1935
1936 /* Check if the file system exists on virtual device, like disk image */
1937 if (VNOP_IOCTL(devvp, DKIOCISVIRTUAL, (caddr_t)&isvirtual, 0, context) == 0) {
1938 if (isvirtual) {
1939 hfsmp->hfs_flags |= HFS_VIRTUAL_DEVICE;
1940 }
1941 }
1942
1943 if (!isroot
1944 && !ISSET(hfsmp->hfs_flags, HFS_VIRTUAL_DEVICE)
1945 && hfs_is_ejectable(vfs_statfs(mp)->f_mntfromname)) {
1946 SET(hfsmp->hfs_flags, HFS_RUN_SYNCER);
1947 }
1948
1949 const char *dev_name = (hfsmp->hfs_devvp
1950 ? vnode_getname_printable(hfsmp->hfs_devvp) : NULL);
1951
1952 printf("hfs: mounted %s on device %s\n",
1953 (hfsmp->vcbVN[0] ? (const char*) hfsmp->vcbVN : "unknown"),
1954 dev_name ?: "unknown device");
1955
1956 if (dev_name)
1957 vnode_putname_printable(dev_name);
1958
1959 /*
1960 * Start looking for free space to drop below this level and generate a
1961 * warning immediately if needed:
1962 */
1963 hfsmp->hfs_notification_conditions = 0;
1964 hfs_generate_volume_notifications(hfsmp);
1965
1966 if (ronly == 0) {
1967 (void) hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT);
1968 }
1969 hfs_free(mdbp, kMDBSize);
1970 return (0);
1971
1972 error_exit:
1973 if (bp)
1974 buf_brelse(bp);
1975
1976 hfs_free(mdbp, kMDBSize);
1977
1978 hfs_close_jvp(hfsmp);
1979
1980 if (hfsmp) {
1981 if (hfsmp->hfs_devvp) {
1982 vnode_rele(hfsmp->hfs_devvp);
1983 }
1984 hfs_locks_destroy(hfsmp);
1985 hfs_delete_chash(hfsmp);
1986 hfs_idhash_destroy (hfsmp);
1987
1988 hfs_free(hfsmp, sizeof(*hfsmp));
1989 if (mp)
1990 vfs_setfsprivate(mp, NULL);
1991 }
1992 return (retval);
1993 }
1994
1995
1996 /*
1997 * Make a filesystem operational.
1998 * Nothing to do at the moment.
1999 */
2000 /* ARGSUSED */
2001 static int
2002 hfs_start(__unused struct mount *mp, __unused int flags, __unused vfs_context_t context)
2003 {
2004 return (0);
2005 }
2006
2007
2008 /*
2009 * unmount system call
2010 */
2011 int
2012 hfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
2013 {
2014 struct proc *p = vfs_context_proc(context);
2015 struct hfsmount *hfsmp = VFSTOHFS(mp);
2016 int retval = E_NONE;
2017 int flags;
2018 int force;
2019 int started_tr = 0;
2020
2021 flags = 0;
2022 force = 0;
2023 if (mntflags & MNT_FORCE) {
2024 flags |= FORCECLOSE;
2025 force = 1;
2026 }
2027
2028 const char *dev_name = (hfsmp->hfs_devvp
2029 ? vnode_getname_printable(hfsmp->hfs_devvp) : NULL);
2030
2031 printf("hfs: unmount initiated on %s on device %s\n",
2032 (hfsmp->vcbVN[0] ? (const char*) hfsmp->vcbVN : "unknown"),
2033 dev_name ?: "unknown device");
2034
2035 if (dev_name)
2036 vnode_putname_printable(dev_name);
2037
2038 if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
2039 return (retval);
2040
2041 if (hfsmp->hfs_flags & HFS_METADATA_ZONE)
2042 (void) hfs_recording_suspend(hfsmp);
2043
2044 hfs_syncer_free(hfsmp);
2045
2046 if (hfsmp->hfs_flags & HFS_SUMMARY_TABLE) {
2047 if (hfsmp->hfs_summary_table) {
2048 int err = 0;
2049 /*
2050 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
2051 */
2052 if (hfsmp->hfs_allocation_vp) {
2053 err = hfs_lock (VTOC(hfsmp->hfs_allocation_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2054 }
2055 hfs_free(hfsmp->hfs_summary_table, hfsmp->hfs_summary_bytes);
2056 hfsmp->hfs_summary_table = NULL;
2057 hfsmp->hfs_flags &= ~HFS_SUMMARY_TABLE;
2058
2059 if (err == 0 && hfsmp->hfs_allocation_vp){
2060 hfs_unlock (VTOC(hfsmp->hfs_allocation_vp));
2061 }
2062
2063 }
2064 }
2065
2066 /*
2067 * Flush out the b-trees, volume bitmap and Volume Header
2068 */
2069 if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
2070 retval = hfs_start_transaction(hfsmp);
2071 if (retval == 0) {
2072 started_tr = 1;
2073 } else if (!force) {
2074 goto err_exit;
2075 }
2076
2077 if (hfsmp->hfs_startup_vp) {
2078 (void) hfs_lock(VTOC(hfsmp->hfs_startup_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2079 retval = hfs_fsync(hfsmp->hfs_startup_vp, MNT_WAIT, 0, p);
2080 hfs_unlock(VTOC(hfsmp->hfs_startup_vp));
2081 if (retval && !force)
2082 goto err_exit;
2083 }
2084
2085 if (hfsmp->hfs_attribute_vp) {
2086 (void) hfs_lock(VTOC(hfsmp->hfs_attribute_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2087 retval = hfs_fsync(hfsmp->hfs_attribute_vp, MNT_WAIT, 0, p);
2088 hfs_unlock(VTOC(hfsmp->hfs_attribute_vp));
2089 if (retval && !force)
2090 goto err_exit;
2091 }
2092
2093 (void) hfs_lock(VTOC(hfsmp->hfs_catalog_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2094 retval = hfs_fsync(hfsmp->hfs_catalog_vp, MNT_WAIT, 0, p);
2095 hfs_unlock(VTOC(hfsmp->hfs_catalog_vp));
2096 if (retval && !force)
2097 goto err_exit;
2098
2099 (void) hfs_lock(VTOC(hfsmp->hfs_extents_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2100 retval = hfs_fsync(hfsmp->hfs_extents_vp, MNT_WAIT, 0, p);
2101 hfs_unlock(VTOC(hfsmp->hfs_extents_vp));
2102 if (retval && !force)
2103 goto err_exit;
2104
2105 if (hfsmp->hfs_allocation_vp) {
2106 (void) hfs_lock(VTOC(hfsmp->hfs_allocation_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2107 retval = hfs_fsync(hfsmp->hfs_allocation_vp, MNT_WAIT, 0, p);
2108 hfs_unlock(VTOC(hfsmp->hfs_allocation_vp));
2109 if (retval && !force)
2110 goto err_exit;
2111 }
2112
2113 if (hfsmp->hfc_filevp && vnode_issystem(hfsmp->hfc_filevp)) {
2114 retval = hfs_fsync(hfsmp->hfc_filevp, MNT_WAIT, 0, p);
2115 if (retval && !force)
2116 goto err_exit;
2117 }
2118
2119 /* If runtime corruption was detected, indicate that the volume
2120 * was not unmounted cleanly.
2121 */
2122 if (hfsmp->vcbAtrb & kHFSVolumeInconsistentMask) {
2123 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
2124 } else {
2125 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
2126 }
2127
2128 if (hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) {
2129 int i;
2130 u_int32_t min_start = hfsmp->totalBlocks;
2131
2132 // set the nextAllocation pointer to the smallest free block number
2133 // we've seen so on the next mount we won't rescan unnecessarily
2134 lck_spin_lock(&hfsmp->vcbFreeExtLock);
2135 for(i=0; i < (int)hfsmp->vcbFreeExtCnt; i++) {
2136 if (hfsmp->vcbFreeExt[i].startBlock < min_start) {
2137 min_start = hfsmp->vcbFreeExt[i].startBlock;
2138 }
2139 }
2140 lck_spin_unlock(&hfsmp->vcbFreeExtLock);
2141 if (min_start < hfsmp->nextAllocation) {
2142 hfsmp->nextAllocation = min_start;
2143 }
2144 }
2145
2146 retval = hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT);
2147 if (retval) {
2148 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
2149 if (!force)
2150 goto err_exit; /* could not flush everything */
2151 }
2152
2153 if (started_tr) {
2154 hfs_end_transaction(hfsmp);
2155 started_tr = 0;
2156 }
2157 }
2158
2159 if (hfsmp->jnl) {
2160 hfs_flush(hfsmp, HFS_FLUSH_FULL);
2161 }
2162
2163 /*
2164 * Invalidate our caches and release metadata vnodes
2165 */
2166 (void) hfsUnmount(hfsmp, p);
2167
2168 #if CONFIG_HFS_STD
2169 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
2170 (void) hfs_relconverter(hfsmp->hfs_encoding);
2171 }
2172 #endif
2173
2174 // XXXdbg
2175 if (hfsmp->jnl) {
2176 journal_close(hfsmp->jnl);
2177 hfsmp->jnl = NULL;
2178 }
2179
2180 VNOP_FSYNC(hfsmp->hfs_devvp, MNT_WAIT, context);
2181
2182 hfs_close_jvp(hfsmp);
2183
2184 /*
2185 * Last chance to dump unreferenced system files.
2186 */
2187 (void) vflush(mp, NULLVP, FORCECLOSE);
2188
2189 #if HFS_SPARSE_DEV
2190 /* Drop our reference on the backing fs (if any). */
2191 if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingvp) {
2192 struct vnode * tmpvp;
2193
2194 hfsmp->hfs_flags &= ~HFS_HAS_SPARSE_DEVICE;
2195 tmpvp = hfsmp->hfs_backingvp;
2196 hfsmp->hfs_backingvp = NULLVP;
2197 vnode_rele(tmpvp);
2198 }
2199 #endif /* HFS_SPARSE_DEV */
2200
2201 vnode_rele(hfsmp->hfs_devvp);
2202
2203 hfs_locks_destroy(hfsmp);
2204 hfs_delete_chash(hfsmp);
2205 hfs_idhash_destroy(hfsmp);
2206
2207 hfs_assert(TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_TENTATIVE_BLOCKS])
2208 && TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_LOCKED_BLOCKS]));
2209 hfs_assert(!hfsmp->lockedBlocks);
2210
2211 hfs_free(hfsmp, sizeof(*hfsmp));
2212
2213 #if HFS_LEAK_DEBUG
2214 if (OSDecrementAtomic(&hfs_active_mounts) == 1) {
2215 if (hfs_dump_allocations())
2216 Debugger(NULL);
2217 else {
2218 printf("hfs: last unmount and nothing was leaked!\n");
2219 msleep(hfs_unmount, NULL, PINOD, "hfs_unmount",
2220 &(struct timespec){ 5, 0 });
2221 }
2222 }
2223 #endif
2224
2225 return (0);
2226
2227 err_exit:
2228 if (started_tr) {
2229 hfs_end_transaction(hfsmp);
2230 }
2231 return retval;
2232 }
2233
2234
2235 /*
2236 * Return the root of a filesystem.
2237 */
2238 int hfs_vfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
2239 {
2240 return hfs_vget(VFSTOHFS(mp), (cnid_t)kHFSRootFolderID, vpp, 1, 0);
2241 }
2242
2243
2244 /*
2245 * Do operations associated with quotas
2246 */
2247 #if !QUOTA
2248 static int
2249 hfs_quotactl(__unused struct mount *mp, __unused int cmds, __unused uid_t uid, __unused caddr_t datap, __unused vfs_context_t context)
2250 {
2251 return (ENOTSUP);
2252 }
2253 #else
2254 static int
2255 hfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t datap, vfs_context_t context)
2256 {
2257 struct proc *p = vfs_context_proc(context);
2258 int cmd, type, error;
2259
2260 if (uid == ~0U)
2261 uid = kauth_cred_getuid(vfs_context_ucred(context));
2262 cmd = cmds >> SUBCMDSHIFT;
2263
2264 switch (cmd) {
2265 case Q_SYNC:
2266 case Q_QUOTASTAT:
2267 break;
2268 case Q_GETQUOTA:
2269 if (uid == kauth_cred_getuid(vfs_context_ucred(context)))
2270 break;
2271 /* fall through */
2272 default:
2273 if ( (error = vfs_context_suser(context)) )
2274 return (error);
2275 }
2276
2277 type = cmds & SUBCMDMASK;
2278 if ((u_int)type >= MAXQUOTAS)
2279 return (EINVAL);
2280 if (vfs_busy(mp, LK_NOWAIT))
2281 return (0);
2282
2283 switch (cmd) {
2284
2285 case Q_QUOTAON:
2286 error = hfs_quotaon(p, mp, type, datap);
2287 break;
2288
2289 case Q_QUOTAOFF:
2290 error = hfs_quotaoff(p, mp, type);
2291 break;
2292
2293 case Q_SETQUOTA:
2294 error = hfs_setquota(mp, uid, type, datap);
2295 break;
2296
2297 case Q_SETUSE:
2298 error = hfs_setuse(mp, uid, type, datap);
2299 break;
2300
2301 case Q_GETQUOTA:
2302 error = hfs_getquota(mp, uid, type, datap);
2303 break;
2304
2305 case Q_SYNC:
2306 error = hfs_qsync(mp);
2307 break;
2308
2309 case Q_QUOTASTAT:
2310 error = hfs_quotastat(mp, type, datap);
2311 break;
2312
2313 default:
2314 error = EINVAL;
2315 break;
2316 }
2317 vfs_unbusy(mp);
2318
2319 return (error);
2320 }
2321 #endif /* QUOTA */
2322
2323 /* Subtype is composite of bits */
2324 #define HFS_SUBTYPE_JOURNALED 0x01
2325 #define HFS_SUBTYPE_CASESENSITIVE 0x02
2326 /* bits 2 - 6 reserved */
2327 #define HFS_SUBTYPE_STANDARDHFS 0x80
2328
2329 /*
2330 * Get file system statistics.
2331 */
2332 int
2333 hfs_statfs(struct mount *mp, register struct vfsstatfs *sbp, __unused vfs_context_t context)
2334 {
2335 ExtendedVCB *vcb = VFSTOVCB(mp);
2336 struct hfsmount *hfsmp = VFSTOHFS(mp);
2337 u_int16_t subtype = 0;
2338
2339 sbp->f_bsize = (u_int32_t)vcb->blockSize;
2340 sbp->f_iosize = (size_t)cluster_max_io_size(mp, 0);
2341 sbp->f_blocks = (u_int64_t)((u_int32_t)vcb->totalBlocks);
2342 sbp->f_bfree = (u_int64_t)((u_int32_t )hfs_freeblks(hfsmp, 0));
2343 sbp->f_bavail = (u_int64_t)((u_int32_t )hfs_freeblks(hfsmp, 1));
2344 sbp->f_files = (u_int64_t)HFS_MAX_FILES;
2345 sbp->f_ffree = (u_int64_t)hfs_free_cnids(hfsmp);
2346
2347 /*
2348 * Subtypes (flavors) for HFS
2349 * 0: Mac OS Extended
2350 * 1: Mac OS Extended (Journaled)
2351 * 2: Mac OS Extended (Case Sensitive)
2352 * 3: Mac OS Extended (Case Sensitive, Journaled)
2353 * 4 - 127: Reserved
2354 * 128: Mac OS Standard
2355 *
2356 */
2357 if ((hfsmp->hfs_flags & HFS_STANDARD) == 0) {
2358 /* HFS+ & variants */
2359 if (hfsmp->jnl) {
2360 subtype |= HFS_SUBTYPE_JOURNALED;
2361 }
2362 if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE) {
2363 subtype |= HFS_SUBTYPE_CASESENSITIVE;
2364 }
2365 }
2366 #if CONFIG_HFS_STD
2367 else {
2368 /* HFS standard */
2369 subtype = HFS_SUBTYPE_STANDARDHFS;
2370 }
2371 #endif
2372 sbp->f_fssubtype = subtype;
2373
2374 return (0);
2375 }
2376
2377
2378 //
2379 // XXXdbg -- this is a callback to be used by the journal to
2380 // get meta data blocks flushed out to disk.
2381 //
2382 // XXXdbg -- be smarter and don't flush *every* block on each
2383 // call. try to only flush some so we don't wind up
2384 // being too synchronous.
2385 //
2386 void
2387 hfs_sync_metadata(void *arg)
2388 {
2389 struct mount *mp = (struct mount *)arg;
2390 struct hfsmount *hfsmp;
2391 ExtendedVCB *vcb;
2392 buf_t bp;
2393 int retval;
2394 daddr64_t priIDSector;
2395 hfsmp = VFSTOHFS(mp);
2396 vcb = HFSTOVCB(hfsmp);
2397
2398 // now make sure the super block is flushed
2399 priIDSector = (daddr64_t)((vcb->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) +
2400 HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size));
2401
2402 retval = (int)buf_meta_bread(hfsmp->hfs_devvp,
2403 HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys),
2404 hfsmp->hfs_physical_block_size, NOCRED, &bp);
2405 if ((retval != 0 ) && (retval != ENXIO)) {
2406 printf("hfs_sync_metadata: can't read volume header at %d! (retval 0x%x)\n",
2407 (int)priIDSector, retval);
2408 }
2409
2410 if (retval == 0 && ((buf_flags(bp) & (B_DELWRI | B_LOCKED)) == B_DELWRI)) {
2411 buf_bwrite(bp);
2412 } else if (bp) {
2413 buf_brelse(bp);
2414 }
2415
2416 /* Note that these I/Os bypass the journal (no calls to journal_start_modify_block) */
2417
2418 // the alternate super block...
2419 // XXXdbg - we probably don't need to do this each and every time.
2420 // hfs_btreeio.c:FlushAlternate() should flag when it was
2421 // written...
2422 if (hfsmp->hfs_partition_avh_sector) {
2423 retval = (int)buf_meta_bread(hfsmp->hfs_devvp,
2424 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_partition_avh_sector, hfsmp->hfs_log_per_phys),
2425 hfsmp->hfs_physical_block_size, NOCRED, &bp);
2426 if (retval == 0 && ((buf_flags(bp) & (B_DELWRI | B_LOCKED)) == B_DELWRI)) {
2427 /*
2428 * note this I/O can fail if the partition shrank behind our backs!
2429 * So failure should be OK here.
2430 */
2431 buf_bwrite(bp);
2432 } else if (bp) {
2433 buf_brelse(bp);
2434 }
2435 }
2436
2437 /* Is the FS's idea of the AVH different than the partition ? */
2438 if ((hfsmp->hfs_fs_avh_sector) && (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)) {
2439 retval = (int)buf_meta_bread(hfsmp->hfs_devvp,
2440 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
2441 hfsmp->hfs_physical_block_size, NOCRED, &bp);
2442 if (retval == 0 && ((buf_flags(bp) & (B_DELWRI | B_LOCKED)) == B_DELWRI)) {
2443 buf_bwrite(bp);
2444 } else if (bp) {
2445 buf_brelse(bp);
2446 }
2447 }
2448
2449 }
2450
2451
2452 struct hfs_sync_cargs {
2453 kauth_cred_t cred;
2454 struct proc *p;
2455 int waitfor;
2456 int error;
2457 int atime_only_syncs;
2458 time_t sync_start_time;
2459 };
2460
2461
2462 static int
2463 hfs_sync_callback(struct vnode *vp, void *cargs)
2464 {
2465 struct cnode *cp = VTOC(vp);
2466 struct hfs_sync_cargs *args;
2467 int error;
2468
2469 args = (struct hfs_sync_cargs *)cargs;
2470
2471 if (hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT) != 0) {
2472 return (VNODE_RETURNED);
2473 }
2474
2475 hfs_dirty_t dirty_state = hfs_is_dirty(cp);
2476
2477 bool sync = dirty_state == HFS_DIRTY || vnode_hasdirtyblks(vp);
2478
2479 if (!sync && dirty_state == HFS_DIRTY_ATIME
2480 && args->atime_only_syncs < 256) {
2481 // We only update if the atime changed more than 60s ago
2482 if (args->sync_start_time - cp->c_attr.ca_atime > 60) {
2483 sync = true;
2484 ++args->atime_only_syncs;
2485 }
2486 }
2487
2488 if (sync) {
2489 error = hfs_fsync(vp, args->waitfor, 0, args->p);
2490
2491 if (error)
2492 args->error = error;
2493 } else if (cp->c_touch_acctime)
2494 hfs_touchtimes(VTOHFS(vp), cp);
2495
2496 hfs_unlock(cp);
2497 return (VNODE_RETURNED);
2498 }
2499
2500
2501
2502 /*
2503 * Go through the disk queues to initiate sandbagged IO;
2504 * go through the inodes to write those that have been modified;
2505 * initiate the writing of the super block if it has been modified.
2506 *
2507 * Note: we are always called with the filesystem marked `MPBUSY'.
2508 */
2509 int
2510 hfs_sync(struct mount *mp, int waitfor, vfs_context_t context)
2511 {
2512 struct proc *p = vfs_context_proc(context);
2513 struct cnode *cp;
2514 struct hfsmount *hfsmp;
2515 ExtendedVCB *vcb;
2516 struct vnode *meta_vp[4];
2517 int i;
2518 int error, allerror = 0;
2519 struct hfs_sync_cargs args;
2520
2521 hfsmp = VFSTOHFS(mp);
2522
2523 // Back off if hfs_changefs or a freeze is underway
2524 hfs_lock_mount(hfsmp);
2525 if ((hfsmp->hfs_flags & HFS_IN_CHANGEFS)
2526 || hfsmp->hfs_freeze_state != HFS_THAWED) {
2527 hfs_unlock_mount(hfsmp);
2528 return 0;
2529 }
2530
2531 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
2532 hfs_unlock_mount(hfsmp);
2533 return (EROFS);
2534 }
2535
2536 ++hfsmp->hfs_syncers;
2537 hfs_unlock_mount(hfsmp);
2538
2539 args.cred = kauth_cred_get();
2540 args.waitfor = waitfor;
2541 args.p = p;
2542 args.error = 0;
2543 args.atime_only_syncs = 0;
2544
2545 struct timeval tv;
2546 microtime(&tv);
2547
2548 args.sync_start_time = tv.tv_sec;
2549
2550 /*
2551 * hfs_sync_callback will be called for each vnode
2552 * hung off of this mount point... the vnode will be
2553 * properly referenced and unreferenced around the callback
2554 */
2555 vnode_iterate(mp, 0, hfs_sync_callback, (void *)&args);
2556
2557 if (args.error)
2558 allerror = args.error;
2559
2560 vcb = HFSTOVCB(hfsmp);
2561
2562 meta_vp[0] = vcb->extentsRefNum;
2563 meta_vp[1] = vcb->catalogRefNum;
2564 meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */
2565 meta_vp[3] = hfsmp->hfs_attribute_vp; /* Optional file */
2566
2567 /* Now sync our three metadata files */
2568 for (i = 0; i < 4; ++i) {
2569 struct vnode *btvp;
2570
2571 btvp = meta_vp[i];;
2572 if ((btvp==0) || (vnode_mount(btvp) != mp))
2573 continue;
2574
2575 /* XXX use hfs_systemfile_lock instead ? */
2576 (void) hfs_lock(VTOC(btvp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
2577 cp = VTOC(btvp);
2578
2579 if (!hfs_is_dirty(cp) && !vnode_hasdirtyblks(btvp)) {
2580 hfs_unlock(VTOC(btvp));
2581 continue;
2582 }
2583 error = vnode_get(btvp);
2584 if (error) {
2585 hfs_unlock(VTOC(btvp));
2586 continue;
2587 }
2588 if ((error = hfs_fsync(btvp, waitfor, 0, p)))
2589 allerror = error;
2590
2591 hfs_unlock(cp);
2592 vnode_put(btvp);
2593 };
2594
2595
2596 #if CONFIG_HFS_STD
2597 /*
2598 * Force stale file system control information to be flushed.
2599 */
2600 if (vcb->vcbSigWord == kHFSSigWord) {
2601 if ((error = VNOP_FSYNC(hfsmp->hfs_devvp, waitfor, context))) {
2602 allerror = error;
2603 }
2604 }
2605 #endif
2606
2607 #if QUOTA
2608 hfs_qsync(mp);
2609 #endif /* QUOTA */
2610
2611 hfs_hotfilesync(hfsmp, vfs_context_kernel());
2612
2613 /*
2614 * Write back modified superblock.
2615 */
2616 if (IsVCBDirty(vcb)) {
2617 error = hfs_flushvolumeheader(hfsmp, waitfor == MNT_WAIT ? HFS_FVH_WAIT : 0);
2618 if (error)
2619 allerror = error;
2620 }
2621
2622 if (hfsmp->jnl) {
2623 hfs_flush(hfsmp, HFS_FLUSH_JOURNAL);
2624 }
2625
2626 hfs_lock_mount(hfsmp);
2627 boolean_t wake = (!--hfsmp->hfs_syncers
2628 && hfsmp->hfs_freeze_state == HFS_WANT_TO_FREEZE);
2629 hfs_unlock_mount(hfsmp);
2630 if (wake)
2631 wakeup(&hfsmp->hfs_freeze_state);
2632
2633 return (allerror);
2634 }
2635
2636
2637 /*
2638 * File handle to vnode
2639 *
2640 * Have to be really careful about stale file handles:
2641 * - check that the cnode id is valid
2642 * - call hfs_vget() to get the locked cnode
2643 * - check for an unallocated cnode (i_mode == 0)
2644 * - check that the given client host has export rights and return
2645 * those rights via. exflagsp and credanonp
2646 */
2647 static int
2648 hfs_fhtovp(struct mount *mp, int fhlen, unsigned char *fhp, struct vnode **vpp, __unused vfs_context_t context)
2649 {
2650 struct hfsfid *hfsfhp;
2651 struct vnode *nvp;
2652 int result;
2653
2654 *vpp = NULL;
2655 hfsfhp = (struct hfsfid *)fhp;
2656
2657 if (fhlen < (int)sizeof(struct hfsfid))
2658 return (EINVAL);
2659
2660 result = hfs_vget(VFSTOHFS(mp), ntohl(hfsfhp->hfsfid_cnid), &nvp, 0, 0);
2661 if (result) {
2662 if (result == ENOENT)
2663 result = ESTALE;
2664 return result;
2665 }
2666
2667 /*
2668 * We used to use the create time as the gen id of the file handle,
2669 * but it is not static enough because it can change at any point
2670 * via system calls. We still don't have another volume ID or other
2671 * unique identifier to use for a generation ID across reboots that
2672 * persists until the file is removed. Using only the CNID exposes
2673 * us to the potential wrap-around case, but as of 2/2008, it would take
2674 * over 2 months to wrap around if the machine did nothing but allocate
2675 * CNIDs. Using some kind of wrap counter would only be effective if
2676 * each file had the wrap counter associated with it. For now,
2677 * we use only the CNID to identify the file as it's good enough.
2678 */
2679
2680 *vpp = nvp;
2681
2682 hfs_unlock(VTOC(nvp));
2683 return (0);
2684 }
2685
2686
2687 /*
2688 * Vnode pointer to File handle
2689 */
2690 /* ARGSUSED */
2691 static int
2692 hfs_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, __unused vfs_context_t context)
2693 {
2694 struct cnode *cp;
2695 struct hfsfid *hfsfhp;
2696
2697 if (ISHFS(VTOVCB(vp)))
2698 return (ENOTSUP); /* hfs standard is not exportable */
2699
2700 if (*fhlenp < (int)sizeof(struct hfsfid))
2701 return (EOVERFLOW);
2702
2703 cp = VTOC(vp);
2704 hfsfhp = (struct hfsfid *)fhp;
2705 /* only the CNID is used to identify the file now */
2706 hfsfhp->hfsfid_cnid = htonl(cp->c_fileid);
2707 hfsfhp->hfsfid_gen = htonl(cp->c_fileid);
2708 *fhlenp = sizeof(struct hfsfid);
2709
2710 return (0);
2711 }
2712
2713
2714 /*
2715 * Initialize HFS filesystems, done only once per boot.
2716 *
2717 * HFS is not a kext-based file system. This makes it difficult to find
2718 * out when the last HFS file system was unmounted and call hfs_uninit()
2719 * to deallocate data structures allocated in hfs_init(). Therefore we
2720 * never deallocate memory allocated by lock attribute and group initializations
2721 * in this function.
2722 */
2723 static int
2724 hfs_init(__unused struct vfsconf *vfsp)
2725 {
2726 static int done = 0;
2727
2728 if (done)
2729 return (0);
2730 done = 1;
2731 hfs_chashinit();
2732
2733 BTReserveSetup();
2734
2735 hfs_lock_attr = lck_attr_alloc_init();
2736 hfs_group_attr = lck_grp_attr_alloc_init();
2737 hfs_mutex_group = lck_grp_alloc_init("hfs-mutex", hfs_group_attr);
2738 hfs_rwlock_group = lck_grp_alloc_init("hfs-rwlock", hfs_group_attr);
2739 hfs_spinlock_group = lck_grp_alloc_init("hfs-spinlock", hfs_group_attr);
2740
2741 #if HFS_COMPRESSION
2742 decmpfs_init();
2743 #endif
2744
2745 journal_init();
2746
2747 return (0);
2748 }
2749
2750
2751 /*
2752 * Destroy all locks, mutexes and spinlocks in hfsmp on unmount or failed mount
2753 */
2754 static void
2755 hfs_locks_destroy(struct hfsmount *hfsmp)
2756 {
2757
2758 lck_mtx_destroy(&hfsmp->hfs_mutex, hfs_mutex_group);
2759 lck_mtx_destroy(&hfsmp->hfc_mutex, hfs_mutex_group);
2760 lck_rw_destroy(&hfsmp->hfs_global_lock, hfs_rwlock_group);
2761 lck_spin_destroy(&hfsmp->vcbFreeExtLock, hfs_spinlock_group);
2762
2763 return;
2764 }
2765
2766
2767 static int
2768 hfs_getmountpoint(struct vnode *vp, struct hfsmount **hfsmpp)
2769 {
2770 struct hfsmount * hfsmp;
2771 char fstypename[MFSNAMELEN];
2772
2773 if (vp == NULL)
2774 return (EINVAL);
2775
2776 if (!vnode_isvroot(vp))
2777 return (EINVAL);
2778
2779 vnode_vfsname(vp, fstypename);
2780 if (strncmp(fstypename, "hfs", sizeof(fstypename)) != 0)
2781 return (EINVAL);
2782
2783 hfsmp = VTOHFS(vp);
2784
2785 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
2786 return (EINVAL);
2787
2788 *hfsmpp = hfsmp;
2789
2790 return (0);
2791 }
2792
2793 // Replace user-space value
2794 static errno_t ureplace(user_addr_t oldp, size_t *oldlenp,
2795 user_addr_t newp, size_t newlen,
2796 void *data, size_t len)
2797 {
2798 errno_t error;
2799 if (!oldlenp)
2800 return EFAULT;
2801 if (oldp && *oldlenp < len)
2802 return ENOMEM;
2803 if (newp && newlen != len)
2804 return EINVAL;
2805 *oldlenp = len;
2806 if (oldp) {
2807 error = copyout(data, oldp, len);
2808 if (error)
2809 return error;
2810 }
2811 return newp ? copyin(newp, data, len) : 0;
2812 }
2813
2814 #define UREPLACE(oldp, oldlenp, newp, newlenp, v) \
2815 ureplace(oldp, oldlenp, newp, newlenp, &v, sizeof(v))
2816
2817 static hfsmount_t *hfs_mount_from_cwd(vfs_context_t ctx)
2818 {
2819 vnode_t vp = vfs_context_cwd(ctx);
2820
2821 if (!vp)
2822 return NULL;
2823
2824 /*
2825 * We could use vnode_tag, but it is probably more future proof to
2826 * compare fstypename.
2827 */
2828 char fstypename[MFSNAMELEN];
2829 vnode_vfsname(vp, fstypename);
2830
2831 if (strcmp(fstypename, "hfs"))
2832 return NULL;
2833
2834 return VTOHFS(vp);
2835 }
2836
2837 /*
2838 * HFS filesystem related variables.
2839 */
2840 int
2841 hfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
2842 user_addr_t newp, size_t newlen, vfs_context_t context)
2843 {
2844 #if !TARGET_OS_EMBEDDED
2845 struct proc *p = vfs_context_proc(context);
2846 #endif
2847 int error;
2848 struct hfsmount *hfsmp;
2849
2850 /* all sysctl names at this level are terminal */
2851
2852 #if !TARGET_OS_EMBEDDED
2853 if (name[0] == HFS_ENCODINGBIAS) {
2854 int bias;
2855
2856 bias = hfs_getencodingbias();
2857
2858 error = UREPLACE(oldp, oldlenp, newp, newlen, bias);
2859 if (error || !newp)
2860 return error;
2861
2862 hfs_setencodingbias(bias);
2863
2864 return 0;
2865 } else
2866 #endif
2867 if (name[0] == HFS_EXTEND_FS) {
2868 u_int64_t newsize = 0;
2869 vnode_t vp = vfs_context_cwd(context);
2870
2871 if (newp == USER_ADDR_NULL || vp == NULLVP
2872 || newlen != sizeof(quad_t) || !oldlenp)
2873 return EINVAL;
2874 if ((error = hfs_getmountpoint(vp, &hfsmp)))
2875 return (error);
2876
2877 /* Start with the 'size' set to the current number of bytes in the filesystem */
2878 newsize = ((uint64_t)hfsmp->totalBlocks) * ((uint64_t)hfsmp->blockSize);
2879
2880 error = UREPLACE(oldp, oldlenp, newp, newlen, newsize);
2881 if (error)
2882 return error;
2883
2884 return hfs_extendfs(hfsmp, newsize, context);
2885 } else if (name[0] == HFS_ENABLE_JOURNALING) {
2886 // make the file system journaled...
2887 vnode_t jvp;
2888 ExtendedVCB *vcb;
2889 struct cat_attr jnl_attr;
2890 struct cat_attr jinfo_attr;
2891 struct cat_fork jnl_fork;
2892 struct cat_fork jinfo_fork;
2893 buf_t jib_buf;
2894 uint64_t jib_blkno;
2895 uint32_t tmpblkno;
2896 uint64_t journal_byte_offset;
2897 uint64_t journal_size;
2898 vnode_t jib_vp = NULLVP;
2899 struct JournalInfoBlock local_jib;
2900 int err = 0;
2901 void *jnl = NULL;
2902 int lockflags;
2903
2904 /* Only root can enable journaling */
2905 if (!kauth_cred_issuser(kauth_cred_get())) {
2906 return (EPERM);
2907 }
2908 if (namelen != 4)
2909 return EINVAL;
2910 hfsmp = hfs_mount_from_cwd(context);
2911 if (!hfsmp)
2912 return EINVAL;
2913
2914 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
2915 return EROFS;
2916 }
2917 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
2918 printf("hfs: can't make a plain hfs volume journaled.\n");
2919 return EINVAL;
2920 }
2921
2922 if (hfsmp->jnl) {
2923 printf("hfs: volume %s is already journaled!\n", hfsmp->vcbVN);
2924 return EAGAIN;
2925 }
2926 vcb = HFSTOVCB(hfsmp);
2927
2928 /* Set up local copies of the initialization info */
2929 tmpblkno = (uint32_t) name[1];
2930 jib_blkno = (uint64_t) tmpblkno;
2931 journal_byte_offset = (uint64_t) name[2];
2932 journal_byte_offset *= hfsmp->blockSize;
2933 journal_byte_offset += hfsmp->hfsPlusIOPosOffset;
2934 journal_size = (uint64_t)((unsigned)name[3]);
2935
2936 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
2937 if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
2938 BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
2939
2940 printf("hfs: volume has a btree w/non-contiguous nodes. can not enable journaling.\n");
2941 hfs_systemfile_unlock(hfsmp, lockflags);
2942 return EINVAL;
2943 }
2944 hfs_systemfile_unlock(hfsmp, lockflags);
2945
2946 // make sure these both exist!
2947 if ( GetFileInfo(vcb, kHFSRootFolderID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
2948 || GetFileInfo(vcb, kHFSRootFolderID, ".journal", &jnl_attr, &jnl_fork) == 0) {
2949
2950 return EINVAL;
2951 }
2952
2953 /*
2954 * At this point, we have a copy of the metadata that lives in the catalog for the
2955 * journal info block. Compare that the journal info block's single extent matches
2956 * that which was passed into this sysctl.
2957 *
2958 * If it is different, deny the journal enable call.
2959 */
2960 if (jinfo_fork.cf_blocks > 1) {
2961 /* too many blocks */
2962 return EINVAL;
2963 }
2964
2965 if (jinfo_fork.cf_extents[0].startBlock != jib_blkno) {
2966 /* Wrong block */
2967 return EINVAL;
2968 }
2969
2970 /*
2971 * We want to immediately purge the vnode for the JIB.
2972 *
2973 * Because it was written to from userland, there's probably
2974 * a vnode somewhere in the vnode cache (possibly with UBC backed blocks).
2975 * So we bring the vnode into core, then immediately do whatever
2976 * we can to flush/vclean it out. This is because those blocks will be
2977 * interpreted as user data, which may be treated separately on some platforms
2978 * than metadata. If the vnode is gone, then there cannot be backing blocks
2979 * in the UBC.
2980 */
2981 if (hfs_vget (hfsmp, jinfo_attr.ca_fileid, &jib_vp, 1, 0)) {
2982 return EINVAL;
2983 }
2984 /*
2985 * Now we have a vnode for the JIB. recycle it. Because we hold an iocount
2986 * on the vnode, we'll just mark it for termination when the last iocount
2987 * (hopefully ours), is dropped.
2988 */
2989 vnode_recycle (jib_vp);
2990 err = vnode_put (jib_vp);
2991 if (err) {
2992 return EINVAL;
2993 }
2994
2995 /* Initialize the local copy of the JIB (just like hfs.util) */
2996 memset (&local_jib, 'Z', sizeof(struct JournalInfoBlock));
2997 local_jib.flags = SWAP_BE32(kJIJournalInFSMask);
2998 /* Note that the JIB's offset is in bytes */
2999 local_jib.offset = SWAP_BE64(journal_byte_offset);
3000 local_jib.size = SWAP_BE64(journal_size);
3001
3002 /*
3003 * Now write out the local JIB. This essentially overwrites the userland
3004 * copy of the JIB. Read it as BLK_META to treat it as a metadata read/write.
3005 */
3006 jib_buf = buf_getblk (hfsmp->hfs_devvp,
3007 jib_blkno * (hfsmp->blockSize / hfsmp->hfs_logical_block_size),
3008 hfsmp->blockSize, 0, 0, BLK_META);
3009 char* buf_ptr = (char*) buf_dataptr (jib_buf);
3010
3011 /* Zero out the portion of the block that won't contain JIB data */
3012 memset (buf_ptr, 0, hfsmp->blockSize);
3013
3014 bcopy(&local_jib, buf_ptr, sizeof(local_jib));
3015 if (buf_bwrite (jib_buf)) {
3016 return EIO;
3017 }
3018
3019 /* Force a flush track cache */
3020 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
3021
3022 /* Now proceed with full volume sync */
3023 hfs_sync(hfsmp->hfs_mp, MNT_WAIT, context);
3024
3025 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
3026 (off_t)name[2], (off_t)name[3]);
3027
3028 //
3029 // XXXdbg - note that currently (Sept, 08) hfs_util does not support
3030 // enabling the journal on a separate device so it is safe
3031 // to just copy hfs_devvp here. If hfs_util gets the ability
3032 // to dynamically enable the journal on a separate device then
3033 // we will have to do the same thing as hfs_early_journal_init()
3034 // to locate and open the journal device.
3035 //
3036 jvp = hfsmp->hfs_devvp;
3037 jnl = journal_create(jvp, journal_byte_offset, journal_size,
3038 hfsmp->hfs_devvp,
3039 hfsmp->hfs_logical_block_size,
3040 0,
3041 0,
3042 hfs_sync_metadata, hfsmp->hfs_mp,
3043 hfsmp->hfs_mp);
3044
3045 /*
3046 * Set up the trim callback function so that we can add
3047 * recently freed extents to the free extent cache once
3048 * the transaction that freed them is written to the
3049 * journal on disk.
3050 */
3051 if (jnl)
3052 journal_trim_set_callback(jnl, hfs_trim_callback, hfsmp);
3053
3054 if (jnl == NULL) {
3055 printf("hfs: FAILED to create the journal!\n");
3056 return EIO;
3057 }
3058
3059 hfs_lock_global (hfsmp, HFS_EXCLUSIVE_LOCK);
3060
3061 /*
3062 * Flush all dirty metadata buffers.
3063 */
3064 buf_flushdirtyblks(hfsmp->hfs_devvp, TRUE, 0, "hfs_sysctl");
3065 buf_flushdirtyblks(hfsmp->hfs_extents_vp, TRUE, 0, "hfs_sysctl");
3066 buf_flushdirtyblks(hfsmp->hfs_catalog_vp, TRUE, 0, "hfs_sysctl");
3067 buf_flushdirtyblks(hfsmp->hfs_allocation_vp, TRUE, 0, "hfs_sysctl");
3068 if (hfsmp->hfs_attribute_vp)
3069 buf_flushdirtyblks(hfsmp->hfs_attribute_vp, TRUE, 0, "hfs_sysctl");
3070
3071 HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
3072 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
3073 hfsmp->jvp = jvp;
3074 hfsmp->jnl = jnl;
3075
3076 // save this off for the hack-y check in hfs_remove()
3077 hfsmp->jnl_start = (u_int32_t)name[2];
3078 hfsmp->jnl_size = (off_t)((unsigned)name[3]);
3079 hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
3080 hfsmp->hfs_jnlfileid = jnl_attr.ca_fileid;
3081
3082 vfs_setflags(hfsmp->hfs_mp, (u_int64_t)((unsigned int)MNT_JOURNALED));
3083
3084 hfs_unlock_global (hfsmp);
3085 hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT | HFS_FVH_WRITE_ALT);
3086
3087 {
3088 fsid_t fsid;
3089
3090 fsid.val[0] = (int32_t)hfsmp->hfs_raw_dev;
3091 fsid.val[1] = (int32_t)vfs_typenum(HFSTOVFS(hfsmp));
3092 vfs_event_signal(&fsid, VQ_UPDATE, (intptr_t)NULL);
3093 }
3094 return 0;
3095 } else if (name[0] == HFS_DISABLE_JOURNALING) {
3096 // clear the journaling bit
3097
3098 /* Only root can disable journaling */
3099 if (!kauth_cred_issuser(kauth_cred_get())) {
3100 return (EPERM);
3101 }
3102
3103 hfsmp = hfs_mount_from_cwd(context);
3104 if (!hfsmp)
3105 return EINVAL;
3106
3107 /*
3108 * Disabling journaling is disallowed on volumes with directory hard links
3109 * because we have not tested the relevant code path.
3110 */
3111 if (hfsmp->hfs_private_attr[DIR_HARDLINKS].ca_entries != 0){
3112 printf("hfs: cannot disable journaling on volumes with directory hardlinks\n");
3113 return EPERM;
3114 }
3115
3116 printf("hfs: disabling journaling for %s\n", hfsmp->vcbVN);
3117
3118 hfs_lock_global (hfsmp, HFS_EXCLUSIVE_LOCK);
3119
3120 // Lights out for you buddy!
3121 journal_close(hfsmp->jnl);
3122 hfsmp->jnl = NULL;
3123
3124 hfs_close_jvp(hfsmp);
3125 vfs_clearflags(hfsmp->hfs_mp, (u_int64_t)((unsigned int)MNT_JOURNALED));
3126 hfsmp->jnl_start = 0;
3127 hfsmp->hfs_jnlinfoblkid = 0;
3128 hfsmp->hfs_jnlfileid = 0;
3129
3130 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
3131
3132 hfs_unlock_global (hfsmp);
3133
3134 hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT | HFS_FVH_WRITE_ALT);
3135
3136 {
3137 fsid_t fsid;
3138
3139 fsid.val[0] = (int32_t)hfsmp->hfs_raw_dev;
3140 fsid.val[1] = (int32_t)vfs_typenum(HFSTOVFS(hfsmp));
3141 vfs_event_signal(&fsid, VQ_UPDATE, (intptr_t)NULL);
3142 }
3143 return 0;
3144 } else if (name[0] == VFS_CTL_QUERY) {
3145 #if TARGET_OS_EMBEDDED
3146 return EPERM;
3147 #else
3148 struct sysctl_req *req;
3149 union union_vfsidctl vc;
3150 struct mount *mp;
3151 struct vfsquery vq;
3152
3153 req = CAST_DOWN(struct sysctl_req *, oldp); /* we're new style vfs sysctl. */
3154 if (req == NULL) {
3155 return EFAULT;
3156 }
3157
3158 error = SYSCTL_IN(req, &vc, proc_is64bit(p)? sizeof(vc.vc64):sizeof(vc.vc32));
3159 if (error) return (error);
3160
3161 mp = vfs_getvfs(&vc.vc32.vc_fsid); /* works for 32 and 64 */
3162 if (mp == NULL) return (ENOENT);
3163
3164 hfsmp = VFSTOHFS(mp);
3165 bzero(&vq, sizeof(vq));
3166 vq.vq_flags = hfsmp->hfs_notification_conditions;
3167 return SYSCTL_OUT(req, &vq, sizeof(vq));;
3168 #endif
3169 } else if (name[0] == HFS_REPLAY_JOURNAL) {
3170 vnode_t devvp = NULL;
3171 int device_fd;
3172 if (namelen != 2) {
3173 return (EINVAL);
3174 }
3175 device_fd = name[1];
3176 error = file_vnode(device_fd, &devvp);
3177 if (error) {
3178 return error;
3179 }
3180 error = vnode_getwithref(devvp);
3181 if (error) {
3182 file_drop(device_fd);
3183 return error;
3184 }
3185 error = hfs_journal_replay(devvp, context);
3186 file_drop(device_fd);
3187 vnode_put(devvp);
3188 return error;
3189 }
3190 #if DEBUG || !TARGET_OS_EMBEDDED
3191 else if (name[0] == HFS_ENABLE_RESIZE_DEBUG) {
3192 if (!kauth_cred_issuser(kauth_cred_get())) {
3193 return (EPERM);
3194 }
3195
3196 int old = hfs_resize_debug;
3197
3198 int res = UREPLACE(oldp, oldlenp, newp, newlen, hfs_resize_debug);
3199
3200 if (old != hfs_resize_debug) {
3201 printf("hfs: %s resize debug\n",
3202 hfs_resize_debug ? "enabled" : "disabled");
3203 }
3204
3205 return res;
3206 }
3207 #endif
3208
3209 return (ENOTSUP);
3210 }
3211
3212 /*
3213 * hfs_vfs_vget is not static since it is used in hfs_readwrite.c to support
3214 * the build_path ioctl. We use it to leverage the code below that updates
3215 * the origin list cache if necessary
3216 */
3217
3218 int
3219 hfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
3220 {
3221 int error;
3222 int lockflags;
3223 struct hfsmount *hfsmp;
3224
3225 hfsmp = VFSTOHFS(mp);
3226
3227 error = hfs_vget(hfsmp, (cnid_t)ino, vpp, 1, 0);
3228 if (error)
3229 return error;
3230
3231 /*
3232 * If the look-up was via the object ID (rather than the link ID),
3233 * then we make sure there's a parent here. We can't leave this
3234 * until hfs_vnop_getattr because if there's a problem getting the
3235 * parent at that point, all the caller will do is call
3236 * hfs_vfs_vget again and we'll end up in an infinite loop.
3237 */
3238
3239 cnode_t *cp = VTOC(*vpp);
3240
3241 if (ISSET(cp->c_flag, C_HARDLINK) && ino == cp->c_fileid) {
3242 hfs_lock_always(cp, HFS_SHARED_LOCK);
3243
3244 if (!hfs_haslinkorigin(cp)) {
3245 if (!hfs_lock_upgrade(cp))
3246 hfs_lock_always(cp, HFS_EXCLUSIVE_LOCK);
3247
3248 if (cp->c_cnid == cp->c_fileid) {
3249 /*
3250 * Descriptor is stale, so we need to refresh it. We
3251 * pick the first link.
3252 */
3253 cnid_t link_id;
3254
3255 error = hfs_first_link(hfsmp, cp, &link_id);
3256
3257 if (!error) {
3258 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
3259 error = cat_findname(hfsmp, link_id, &cp->c_desc);
3260 hfs_systemfile_unlock(hfsmp, lockflags);
3261 }
3262 } else {
3263 // We'll use whatever link the descriptor happens to have
3264 error = 0;
3265 }
3266 if (!error)
3267 hfs_savelinkorigin(cp, cp->c_parentcnid);
3268 }
3269
3270 hfs_unlock(cp);
3271
3272 if (error) {
3273 vnode_put(*vpp);
3274 *vpp = NULL;
3275 }
3276 }
3277
3278 return error;
3279 }
3280
3281
3282 /*
3283 * Look up an HFS object by ID.
3284 *
3285 * The object is returned with an iocount reference and the cnode locked.
3286 *
3287 * If the object is a file then it will represent the data fork.
3288 */
3289 int
3290 hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock, int allow_deleted)
3291 {
3292 struct vnode *vp = NULLVP;
3293 struct cat_desc cndesc;
3294 struct cat_attr cnattr;
3295 struct cat_fork cnfork;
3296 u_int32_t linkref = 0;
3297 int error;
3298
3299 /* Check for cnids that should't be exported. */
3300 if ((cnid < kHFSFirstUserCatalogNodeID) &&
3301 (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) {
3302 return (ENOENT);
3303 }
3304 /* Don't export our private directories. */
3305 if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
3306 cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
3307 return (ENOENT);
3308 }
3309 /*
3310 * Check the hash first
3311 */
3312 vp = hfs_chash_getvnode(hfsmp, cnid, 0, skiplock, allow_deleted);
3313 if (vp) {
3314 *vpp = vp;
3315 return(0);
3316 }
3317
3318 bzero(&cndesc, sizeof(cndesc));
3319 bzero(&cnattr, sizeof(cnattr));
3320 bzero(&cnfork, sizeof(cnfork));
3321
3322 /*
3323 * Not in hash, lookup in catalog
3324 */
3325 if (cnid == kHFSRootParentID) {
3326 static char hfs_rootname[] = "/";
3327
3328 cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0];
3329 cndesc.cd_namelen = 1;
3330 cndesc.cd_parentcnid = kHFSRootParentID;
3331 cndesc.cd_cnid = kHFSRootFolderID;
3332 cndesc.cd_flags = CD_ISDIR;
3333
3334 cnattr.ca_fileid = kHFSRootFolderID;
3335 cnattr.ca_linkcount = 1;
3336 cnattr.ca_entries = 1;
3337 cnattr.ca_dircount = 1;
3338 cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
3339 } else {
3340 int lockflags;
3341 cnid_t pid;
3342 const char *nameptr;
3343
3344 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
3345 error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork);
3346 hfs_systemfile_unlock(hfsmp, lockflags);
3347
3348 if (error) {
3349 *vpp = NULL;
3350 return (error);
3351 }
3352
3353 /*
3354 * Check for a raw hardlink inode and save its linkref.
3355 */
3356 pid = cndesc.cd_parentcnid;
3357 nameptr = (const char *)cndesc.cd_nameptr;
3358
3359 if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
3360 cndesc.cd_namelen > HFS_INODE_PREFIX_LEN &&
3361 (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) {
3362 linkref = strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10);
3363
3364 } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
3365 cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN &&
3366 (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) {
3367 linkref = strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10);
3368
3369 } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
3370 cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN &&
3371 (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) {
3372 *vpp = NULL;
3373 cat_releasedesc(&cndesc);
3374 return (ENOENT); /* open unlinked file */
3375 }
3376 }
3377
3378 /*
3379 * Finish initializing cnode descriptor for hardlinks.
3380 *
3381 * We need a valid name and parent for reverse lookups.
3382 */
3383 if (linkref) {
3384 cnid_t lastid;
3385 struct cat_desc linkdesc;
3386 int linkerr = 0;
3387
3388 cnattr.ca_linkref = linkref;
3389 bzero (&linkdesc, sizeof (linkdesc));
3390
3391 /*
3392 * If the caller supplied the raw inode value, then we don't know exactly
3393 * which hardlink they wanted. It's likely that they acquired the raw inode
3394 * value BEFORE the item became a hardlink, in which case, they probably
3395 * want the oldest link. So request the oldest link from the catalog.
3396 *
3397 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
3398 * side, since we know that we want the last linkID, we can also have this one
3399 * call give us back the name of the last ID, since it's going to have it in-hand...
3400 */
3401 linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc);
3402 if ((linkerr == 0) && (lastid != 0)) {
3403 /*
3404 * Release any lingering buffers attached to our local descriptor.
3405 * Then copy the name and other business into the cndesc
3406 */
3407 cat_releasedesc (&cndesc);
3408 bcopy (&linkdesc, &cndesc, sizeof(linkdesc));
3409 }
3410 /* If it failed, the linkref code will just use whatever it had in-hand below. */
3411 }
3412
3413 if (linkref) {
3414 int newvnode_flags = 0;
3415
3416 error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr,
3417 &cnfork, &vp, &newvnode_flags);
3418 if (error == 0) {
3419 VTOC(vp)->c_flag |= C_HARDLINK;
3420 vnode_setmultipath(vp);
3421 }
3422 } else {
3423 int newvnode_flags = 0;
3424
3425 void *buf = hfs_malloc(MAXPATHLEN);
3426
3427 /* Supply hfs_getnewvnode with a component name. */
3428 struct componentname cn = {
3429 .cn_nameiop = LOOKUP,
3430 .cn_flags = ISLASTCN,
3431 .cn_pnlen = MAXPATHLEN,
3432 .cn_namelen = cndesc.cd_namelen,
3433 .cn_pnbuf = buf,
3434 .cn_nameptr = buf
3435 };
3436
3437 bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1);
3438
3439 error = hfs_getnewvnode(hfsmp, NULLVP, &cn, &cndesc, 0, &cnattr,
3440 &cnfork, &vp, &newvnode_flags);
3441
3442 if (error == 0 && (VTOC(vp)->c_flag & C_HARDLINK)) {
3443 hfs_savelinkorigin(VTOC(vp), cndesc.cd_parentcnid);
3444 }
3445
3446 hfs_free(buf, MAXPATHLEN);
3447 }
3448 cat_releasedesc(&cndesc);
3449
3450 *vpp = vp;
3451 if (vp && skiplock) {
3452 hfs_unlock(VTOC(vp));
3453 }
3454 return (error);
3455 }
3456
3457
3458 /*
3459 * Flush out all the files in a filesystem.
3460 */
3461 static int
3462 #if QUOTA
3463 hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
3464 #else
3465 hfs_flushfiles(struct mount *mp, int flags, __unused struct proc *p)
3466 #endif /* QUOTA */
3467 {
3468 struct hfsmount *hfsmp;
3469 struct vnode *skipvp = NULLVP;
3470 int error;
3471 int accounted_root_usecounts;
3472 #if QUOTA
3473 int i;
3474 #endif
3475
3476 hfsmp = VFSTOHFS(mp);
3477
3478 accounted_root_usecounts = 0;
3479 #if QUOTA
3480 /*
3481 * The open quota files have an indirect reference on
3482 * the root directory vnode. We must account for this
3483 * extra reference when doing the intial vflush.
3484 */
3485 if (((unsigned int)vfs_flags(mp)) & MNT_QUOTA) {
3486 /* Find out how many quota files we have open. */
3487 for (i = 0; i < MAXQUOTAS; i++) {
3488 if (hfsmp->hfs_qfiles[i].qf_vp != NULLVP)
3489 ++accounted_root_usecounts;
3490 }
3491 }
3492 #endif /* QUOTA */
3493
3494 if (accounted_root_usecounts > 0) {
3495 /* Obtain the root vnode so we can skip over it. */
3496 skipvp = hfs_chash_getvnode(hfsmp, kHFSRootFolderID, 0, 0, 0);
3497 }
3498
3499 error = vflush(mp, skipvp, SKIPSYSTEM | SKIPSWAP | flags);
3500 if (error != 0)
3501 return(error);
3502
3503 error = vflush(mp, skipvp, SKIPSYSTEM | flags);
3504
3505 if (skipvp) {
3506 /*
3507 * See if there are additional references on the
3508 * root vp besides the ones obtained from the open
3509 * quota files and CoreStorage.
3510 */
3511 if ((error == 0) &&
3512 (vnode_isinuse(skipvp, accounted_root_usecounts))) {
3513 error = EBUSY; /* root directory is still open */
3514 }
3515 hfs_unlock(VTOC(skipvp));
3516 /* release the iocount from the hfs_chash_getvnode call above. */
3517 vnode_put(skipvp);
3518 }
3519 if (error && (flags & FORCECLOSE) == 0)
3520 return (error);
3521
3522 #if QUOTA
3523 if (((unsigned int)vfs_flags(mp)) & MNT_QUOTA) {
3524 for (i = 0; i < MAXQUOTAS; i++) {
3525 if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
3526 continue;
3527 hfs_quotaoff(p, mp, i);
3528 }
3529 }
3530 #endif /* QUOTA */
3531
3532 if (skipvp) {
3533 error = vflush(mp, NULLVP, SKIPSYSTEM | flags);
3534 }
3535
3536 return (error);
3537 }
3538
3539 /*
3540 * Update volume encoding bitmap (HFS Plus only)
3541 *
3542 * Mark a legacy text encoding as in-use (as needed)
3543 * in the volume header of this HFS+ filesystem.
3544 */
3545 void
3546 hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
3547 {
3548 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
3549 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
3550
3551 u_int32_t index;
3552
3553 switch (encoding) {
3554 case kTextEncodingMacUkrainian:
3555 index = kIndexMacUkrainian;
3556 break;
3557 case kTextEncodingMacFarsi:
3558 index = kIndexMacFarsi;
3559 break;
3560 default:
3561 index = encoding;
3562 break;
3563 }
3564
3565 /* Only mark the encoding as in-use if it wasn't already set */
3566 if (index < 64 && (hfsmp->encodingsBitmap & (u_int64_t)(1ULL << index)) == 0) {
3567 hfs_lock_mount (hfsmp);
3568 hfsmp->encodingsBitmap |= (u_int64_t)(1ULL << index);
3569 MarkVCBDirty(hfsmp);
3570 hfs_unlock_mount(hfsmp);
3571 }
3572 }
3573
3574 /*
3575 * Update volume stats
3576 *
3577 * On journal volumes this will cause a volume header flush
3578 */
3579 int
3580 hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
3581 {
3582 struct timeval tv;
3583
3584 microtime(&tv);
3585
3586 hfs_lock_mount (hfsmp);
3587
3588 MarkVCBDirty(hfsmp);
3589 hfsmp->hfs_mtime = tv.tv_sec;
3590
3591 switch (op) {
3592 case VOL_UPDATE:
3593 break;
3594 case VOL_MKDIR:
3595 if (hfsmp->hfs_dircount != 0xFFFFFFFF)
3596 ++hfsmp->hfs_dircount;
3597 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
3598 ++hfsmp->vcbNmRtDirs;
3599 break;
3600 case VOL_RMDIR:
3601 if (hfsmp->hfs_dircount != 0)
3602 --hfsmp->hfs_dircount;
3603 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
3604 --hfsmp->vcbNmRtDirs;
3605 break;
3606 case VOL_MKFILE:
3607 if (hfsmp->hfs_filecount != 0xFFFFFFFF)
3608 ++hfsmp->hfs_filecount;
3609 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
3610 ++hfsmp->vcbNmFls;
3611 break;
3612 case VOL_RMFILE:
3613 if (hfsmp->hfs_filecount != 0)
3614 --hfsmp->hfs_filecount;
3615 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
3616 --hfsmp->vcbNmFls;
3617 break;
3618 }
3619
3620 hfs_unlock_mount (hfsmp);
3621
3622 if (hfsmp->jnl) {
3623 hfs_flushvolumeheader(hfsmp, 0);
3624 }
3625
3626 return (0);
3627 }
3628
3629
3630 #if CONFIG_HFS_STD
3631 /* HFS Standard MDB flush */
3632 static int
3633 hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
3634 {
3635 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
3636 struct filefork *fp;
3637 HFSMasterDirectoryBlock *mdb;
3638 struct buf *bp = NULL;
3639 int retval;
3640 int sector_size;
3641 ByteCount namelen;
3642
3643 sector_size = hfsmp->hfs_logical_block_size;
3644 retval = (int)buf_bread(hfsmp->hfs_devvp, (daddr64_t)HFS_PRI_SECTOR(sector_size), sector_size, NOCRED, &bp);
3645 if (retval) {
3646 if (bp)
3647 buf_brelse(bp);
3648 return retval;
3649 }
3650
3651 hfs_lock_mount (hfsmp);
3652
3653 mdb = (HFSMasterDirectoryBlock *)(buf_dataptr(bp) + HFS_PRI_OFFSET(sector_size));
3654
3655 mdb->drCrDate = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->hfs_itime)));
3656 mdb->drLsMod = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
3657 mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
3658 mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls);
3659 mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
3660 mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz);
3661 mdb->drNxtCNID = SWAP_BE32 (vcb->vcbNxtCNID);
3662 mdb->drFreeBks = SWAP_BE16 (vcb->freeBlocks);
3663
3664 namelen = strlen((char *)vcb->vcbVN);
3665 retval = utf8_to_hfs(vcb, namelen, vcb->vcbVN, mdb->drVN);
3666 /* Retry with MacRoman in case that's how it was exported. */
3667 if (retval)
3668 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
3669
3670 mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
3671 mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt);
3672 mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
3673 mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt);
3674 mdb->drDirCnt = SWAP_BE32 (vcb->vcbDirCnt);
3675
3676 bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
3677
3678 fp = VTOF(vcb->extentsRefNum);
3679 mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
3680 mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
3681 mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
3682 mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
3683 mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
3684 mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
3685 mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
3686 mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
3687 FTOC(fp)->c_flag &= ~C_MODIFIED;
3688
3689 fp = VTOF(vcb->catalogRefNum);
3690 mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
3691 mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
3692 mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
3693 mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
3694 mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
3695 mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
3696 mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
3697 mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
3698 FTOC(fp)->c_flag &= ~C_MODIFIED;
3699
3700 MarkVCBClean( vcb );
3701
3702 hfs_unlock_mount (hfsmp);
3703
3704 /* If requested, flush out the alternate MDB */
3705 if (altflush) {
3706 struct buf *alt_bp = NULL;
3707
3708 if (buf_meta_bread(hfsmp->hfs_devvp, hfsmp->hfs_partition_avh_sector, sector_size, NOCRED, &alt_bp) == 0) {
3709 bcopy(mdb, (char *)buf_dataptr(alt_bp) + HFS_ALT_OFFSET(sector_size), kMDBSize);
3710
3711 (void) VNOP_BWRITE(alt_bp);
3712 } else if (alt_bp)
3713 buf_brelse(alt_bp);
3714 }
3715
3716 if (waitfor != MNT_WAIT)
3717 buf_bawrite(bp);
3718 else
3719 retval = VNOP_BWRITE(bp);
3720
3721 return (retval);
3722 }
3723 #endif
3724
3725 /*
3726 * Flush any dirty in-memory mount data to the on-disk
3727 * volume header.
3728 *
3729 * Note: the on-disk volume signature is intentionally
3730 * not flushed since the on-disk "H+" and "HX" signatures
3731 * are always stored in-memory as "H+".
3732 */
3733 int
3734 hfs_flushvolumeheader(struct hfsmount *hfsmp,
3735 hfs_flush_volume_header_options_t options)
3736 {
3737 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
3738 struct filefork *fp;
3739 HFSPlusVolumeHeader *volumeHeader, *altVH;
3740 int retval;
3741 struct buf *bp, *alt_bp;
3742 int i;
3743 daddr64_t priIDSector;
3744 bool critical = false;
3745 u_int16_t signature;
3746 u_int16_t hfsversion;
3747 daddr64_t avh_sector;
3748 bool altflush = ISSET(options, HFS_FVH_WRITE_ALT);
3749
3750 if (ISSET(options, HFS_FVH_FLUSH_IF_DIRTY)
3751 && !hfs_header_needs_flushing(hfsmp)) {
3752 return 0;
3753 }
3754
3755 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
3756 return(0);
3757 }
3758 #if CONFIG_HFS_STD
3759 if (hfsmp->hfs_flags & HFS_STANDARD) {
3760 return hfs_flushMDB(hfsmp, ISSET(options, HFS_FVH_WAIT) ? MNT_WAIT : 0, altflush);
3761 }
3762 #endif
3763 priIDSector = (daddr64_t)((vcb->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) +
3764 HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size));
3765
3766 if (hfs_start_transaction(hfsmp) != 0) {
3767 return EINVAL;
3768 }
3769
3770 bp = NULL;
3771 alt_bp = NULL;
3772
3773 retval = (int)buf_meta_bread(hfsmp->hfs_devvp,
3774 HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys),
3775 hfsmp->hfs_physical_block_size, NOCRED, &bp);
3776 if (retval) {
3777 printf("hfs: err %d reading VH blk (vol=%s)\n", retval, vcb->vcbVN);
3778 goto err_exit;
3779 }
3780
3781 volumeHeader = (HFSPlusVolumeHeader *)((char *)buf_dataptr(bp) +
3782 HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
3783
3784 /*
3785 * Sanity check what we just read. If it's bad, try the alternate
3786 * instead.
3787 */
3788 signature = SWAP_BE16 (volumeHeader->signature);
3789 hfsversion = SWAP_BE16 (volumeHeader->version);
3790 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
3791 (hfsversion < kHFSPlusVersion) || (hfsversion > 100) ||
3792 (SWAP_BE32 (volumeHeader->blockSize) != vcb->blockSize)) {
3793 printf("hfs: corrupt VH on %s, sig 0x%04x, ver %d, blksize %d\n",
3794 vcb->vcbVN, signature, hfsversion,
3795 SWAP_BE32 (volumeHeader->blockSize));
3796 hfs_mark_inconsistent(hfsmp, HFS_INCONSISTENCY_DETECTED);
3797
3798 /* Almost always we read AVH relative to the partition size */
3799 avh_sector = hfsmp->hfs_partition_avh_sector;
3800
3801 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector) {
3802 /*
3803 * The two altVH offsets do not match --- which means that a smaller file
3804 * system exists in a larger partition. Verify that we have the correct
3805 * alternate volume header sector as per the current parititon size.
3806 * The GPT device that we are mounted on top could have changed sizes
3807 * without us knowing.
3808 *
3809 * We're in a transaction, so it's safe to modify the partition_avh_sector
3810 * field if necessary.
3811 */
3812
3813 uint64_t sector_count;
3814
3815 /* Get underlying device block count */
3816 if ((retval = VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCGETBLOCKCOUNT,
3817 (caddr_t)&sector_count, 0, vfs_context_current()))) {
3818 printf("hfs_flushVH: err %d getting block count (%s) \n", retval, vcb->vcbVN);
3819 retval = ENXIO;
3820 goto err_exit;
3821 }
3822
3823 /* Partition size was changed without our knowledge */
3824 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count) {
3825 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) +
3826 HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
3827 /* Note: hfs_fs_avh_sector will remain unchanged */
3828 printf ("hfs_flushVH: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
3829 hfsmp->hfs_partition_avh_sector, hfsmp->hfs_fs_avh_sector);
3830
3831 /*
3832 * We just updated the offset for AVH relative to
3833 * the partition size, so the content of that AVH
3834 * will be invalid. But since we are also maintaining
3835 * a valid AVH relative to the file system size, we
3836 * can read it since primary VH and partition AVH
3837 * are not valid.
3838 */
3839 avh_sector = hfsmp->hfs_fs_avh_sector;
3840 }
3841 }
3842
3843 printf ("hfs: trying alternate (for %s) avh_sector=%qu\n",
3844 (avh_sector == hfsmp->hfs_fs_avh_sector) ? "file system" : "partition", avh_sector);
3845
3846 if (avh_sector) {
3847 retval = buf_meta_bread(hfsmp->hfs_devvp,
3848 HFS_PHYSBLK_ROUNDDOWN(avh_sector, hfsmp->hfs_log_per_phys),
3849 hfsmp->hfs_physical_block_size, NOCRED, &alt_bp);
3850 if (retval) {
3851 printf("hfs: err %d reading alternate VH (%s)\n", retval, vcb->vcbVN);
3852 goto err_exit;
3853 }
3854
3855 altVH = (HFSPlusVolumeHeader *)((char *)buf_dataptr(alt_bp) +
3856 HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size));
3857 signature = SWAP_BE16(altVH->signature);
3858 hfsversion = SWAP_BE16(altVH->version);
3859
3860 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
3861 (hfsversion < kHFSPlusVersion) || (kHFSPlusVersion > 100) ||
3862 (SWAP_BE32(altVH->blockSize) != vcb->blockSize)) {
3863 printf("hfs: corrupt alternate VH on %s, sig 0x%04x, ver %d, blksize %d\n",
3864 vcb->vcbVN, signature, hfsversion,
3865 SWAP_BE32(altVH->blockSize));
3866 retval = EIO;
3867 goto err_exit;
3868 }
3869
3870 /* The alternate is plausible, so use it. */
3871 bcopy(altVH, volumeHeader, kMDBSize);
3872 buf_brelse(alt_bp);
3873 alt_bp = NULL;
3874 } else {
3875 /* No alternate VH, nothing more we can do. */
3876 retval = EIO;
3877 goto err_exit;
3878 }
3879 }
3880
3881 if (hfsmp->jnl) {
3882 journal_modify_block_start(hfsmp->jnl, bp);
3883 }
3884
3885 /*
3886 * For embedded HFS+ volumes, update create date if it changed
3887 * (ie from a setattrlist call)
3888 */
3889 if ((vcb->hfsPlusIOPosOffset != 0) &&
3890 (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
3891 struct buf *bp2;
3892 HFSMasterDirectoryBlock *mdb;
3893
3894 retval = (int)buf_meta_bread(hfsmp->hfs_devvp,
3895 HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size), hfsmp->hfs_log_per_phys),
3896 hfsmp->hfs_physical_block_size, NOCRED, &bp2);
3897 if (retval) {
3898 if (bp2)
3899 buf_brelse(bp2);
3900 retval = 0;
3901 } else {
3902 mdb = (HFSMasterDirectoryBlock *)(buf_dataptr(bp2) +
3903 HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
3904
3905 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
3906 {
3907 if (hfsmp->jnl) {
3908 journal_modify_block_start(hfsmp->jnl, bp2);
3909 }
3910
3911 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
3912
3913 if (hfsmp->jnl) {
3914 journal_modify_block_end(hfsmp->jnl, bp2, NULL, NULL);
3915 } else {
3916 (void) VNOP_BWRITE(bp2); /* write out the changes */
3917 }
3918 }
3919 else
3920 {
3921 buf_brelse(bp2); /* just release it */
3922 }
3923 }
3924 }
3925
3926 hfs_lock_mount (hfsmp);
3927
3928 /* Note: only update the lower 16 bits worth of attributes */
3929 volumeHeader->attributes = SWAP_BE32 (vcb->vcbAtrb);
3930 volumeHeader->journalInfoBlock = SWAP_BE32 (vcb->vcbJinfoBlock);
3931 if (hfsmp->jnl) {
3932 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
3933 } else {
3934 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
3935 }
3936 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
3937 volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
3938 volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
3939 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
3940 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
3941 volumeHeader->totalBlocks = SWAP_BE32 (vcb->totalBlocks);
3942 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks + vcb->reclaimBlocks);
3943 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
3944 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
3945 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
3946 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
3947 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
3948 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
3949
3950 if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0) {
3951 bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
3952 critical = true;
3953 }
3954
3955 if (!altflush && !ISSET(options, HFS_FVH_FLUSH_IF_DIRTY)) {
3956 goto done;
3957 }
3958
3959 /* Sync Extents over-flow file meta data */
3960 fp = VTOF(vcb->extentsRefNum);
3961 if (FTOC(fp)->c_flag & C_MODIFIED) {
3962 for (i = 0; i < kHFSPlusExtentDensity; i++) {
3963 volumeHeader->extentsFile.extents[i].startBlock =
3964 SWAP_BE32 (fp->ff_extents[i].startBlock);
3965 volumeHeader->extentsFile.extents[i].blockCount =
3966 SWAP_BE32 (fp->ff_extents[i].blockCount);
3967 }
3968 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
3969 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
3970 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
3971 FTOC(fp)->c_flag &= ~C_MODIFIED;
3972 altflush = true;
3973 }
3974
3975 /* Sync Catalog file meta data */
3976 fp = VTOF(vcb->catalogRefNum);
3977 if (FTOC(fp)->c_flag & C_MODIFIED) {
3978 for (i = 0; i < kHFSPlusExtentDensity; i++) {
3979 volumeHeader->catalogFile.extents[i].startBlock =
3980 SWAP_BE32 (fp->ff_extents[i].startBlock);
3981 volumeHeader->catalogFile.extents[i].blockCount =
3982 SWAP_BE32 (fp->ff_extents[i].blockCount);
3983 }
3984 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
3985 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
3986 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
3987 FTOC(fp)->c_flag &= ~C_MODIFIED;
3988 altflush = true;
3989 }
3990
3991 /* Sync Allocation file meta data */
3992 fp = VTOF(vcb->allocationsRefNum);
3993 if (FTOC(fp)->c_flag & C_MODIFIED) {
3994 for (i = 0; i < kHFSPlusExtentDensity; i++) {
3995 volumeHeader->allocationFile.extents[i].startBlock =
3996 SWAP_BE32 (fp->ff_extents[i].startBlock);
3997 volumeHeader->allocationFile.extents[i].blockCount =
3998 SWAP_BE32 (fp->ff_extents[i].blockCount);
3999 }
4000 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
4001 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
4002 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
4003 FTOC(fp)->c_flag &= ~C_MODIFIED;
4004 altflush = true;
4005 }
4006
4007 /* Sync Attribute file meta data */
4008 if (hfsmp->hfs_attribute_vp) {
4009 fp = VTOF(hfsmp->hfs_attribute_vp);
4010 for (i = 0; i < kHFSPlusExtentDensity; i++) {
4011 volumeHeader->attributesFile.extents[i].startBlock =
4012 SWAP_BE32 (fp->ff_extents[i].startBlock);
4013 volumeHeader->attributesFile.extents[i].blockCount =
4014 SWAP_BE32 (fp->ff_extents[i].blockCount);
4015 }
4016 if (ISSET(FTOC(fp)->c_flag, C_MODIFIED)) {
4017 FTOC(fp)->c_flag &= ~C_MODIFIED;
4018 altflush = true;
4019 }
4020 volumeHeader->attributesFile.logicalSize = SWAP_BE64 (fp->ff_size);
4021 volumeHeader->attributesFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
4022 volumeHeader->attributesFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
4023 }
4024
4025 /* Sync Startup file meta data */
4026 if (hfsmp->hfs_startup_vp) {
4027 fp = VTOF(hfsmp->hfs_startup_vp);
4028 if (FTOC(fp)->c_flag & C_MODIFIED) {
4029 for (i = 0; i < kHFSPlusExtentDensity; i++) {
4030 volumeHeader->startupFile.extents[i].startBlock =
4031 SWAP_BE32 (fp->ff_extents[i].startBlock);
4032 volumeHeader->startupFile.extents[i].blockCount =
4033 SWAP_BE32 (fp->ff_extents[i].blockCount);
4034 }
4035 volumeHeader->startupFile.logicalSize = SWAP_BE64 (fp->ff_size);
4036 volumeHeader->startupFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
4037 volumeHeader->startupFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
4038 FTOC(fp)->c_flag &= ~C_MODIFIED;
4039 altflush = true;
4040 }
4041 }
4042
4043 if (altflush)
4044 critical = true;
4045
4046 done:
4047 MarkVCBClean(hfsmp);
4048 hfs_unlock_mount (hfsmp);
4049
4050 /* If requested, flush out the alternate volume header */
4051 if (altflush) {
4052 /*
4053 * The two altVH offsets do not match --- which means that a smaller file
4054 * system exists in a larger partition. Verify that we have the correct
4055 * alternate volume header sector as per the current parititon size.
4056 * The GPT device that we are mounted on top could have changed sizes
4057 * without us knowning.
4058 *
4059 * We're in a transaction, so it's safe to modify the partition_avh_sector
4060 * field if necessary.
4061 */
4062 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector) {
4063 uint64_t sector_count;
4064
4065 /* Get underlying device block count */
4066 if ((retval = VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCGETBLOCKCOUNT,
4067 (caddr_t)&sector_count, 0, vfs_context_current()))) {
4068 printf("hfs_flushVH: err %d getting block count (%s) \n", retval, vcb->vcbVN);
4069 retval = ENXIO;
4070 goto err_exit;
4071 }
4072
4073 /* Partition size was changed without our knowledge */
4074 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count) {
4075 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) +
4076 HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
4077 /* Note: hfs_fs_avh_sector will remain unchanged */
4078 printf ("hfs_flushVH: altflush: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
4079 hfsmp->hfs_partition_avh_sector, hfsmp->hfs_fs_avh_sector);
4080 }
4081 }
4082
4083 /*
4084 * First see if we need to write I/O to the "secondary" AVH
4085 * located at FS Size - 1024 bytes, because this one will
4086 * always go into the journal. We put this AVH into the journal
4087 * because even if the filesystem size has shrunk, this LBA should be
4088 * reachable after the partition-size modification has occurred.
4089 * The one where we need to be careful is partitionsize-1024, since the
4090 * partition size should hopefully shrink.
4091 *
4092 * Most of the time this block will not execute.
4093 */
4094 if ((hfsmp->hfs_fs_avh_sector) &&
4095 (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)) {
4096 if (buf_meta_bread(hfsmp->hfs_devvp,
4097 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
4098 hfsmp->hfs_physical_block_size, NOCRED, &alt_bp) == 0) {
4099 if (hfsmp->jnl) {
4100 journal_modify_block_start(hfsmp->jnl, alt_bp);
4101 }
4102
4103 bcopy(volumeHeader, (char *)buf_dataptr(alt_bp) +
4104 HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size),
4105 kMDBSize);
4106
4107 if (hfsmp->jnl) {
4108 journal_modify_block_end(hfsmp->jnl, alt_bp, NULL, NULL);
4109 } else {
4110 (void) VNOP_BWRITE(alt_bp);
4111 }
4112 } else if (alt_bp) {
4113 buf_brelse(alt_bp);
4114 }
4115 }
4116
4117 /*
4118 * Flush out alternate volume header located at 1024 bytes before
4119 * end of the partition as part of journal transaction. In
4120 * most cases, this will be the only alternate volume header
4121 * that we need to worry about because the file system size is
4122 * same as the partition size, therefore hfs_fs_avh_sector is
4123 * same as hfs_partition_avh_sector. This is the "priority" AVH.
4124 *
4125 * However, do not always put this I/O into the journal. If we skipped the
4126 * FS-Size AVH write above, then we will put this I/O into the journal as
4127 * that indicates the two were in sync. However, if the FS size is
4128 * not the same as the partition size, we are tracking two. We don't
4129 * put it in the journal in that case, since if the partition
4130 * size changes between uptimes, and we need to replay the journal,
4131 * this I/O could generate an EIO if during replay it is now trying
4132 * to access blocks beyond the device EOF.
4133 */
4134 if (hfsmp->hfs_partition_avh_sector) {
4135 if (buf_meta_bread(hfsmp->hfs_devvp,
4136 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_partition_avh_sector, hfsmp->hfs_log_per_phys),
4137 hfsmp->hfs_physical_block_size, NOCRED, &alt_bp) == 0) {
4138
4139 /* only one AVH, put this I/O in the journal. */
4140 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
4141 journal_modify_block_start(hfsmp->jnl, alt_bp);
4142 }
4143
4144 bcopy(volumeHeader, (char *)buf_dataptr(alt_bp) +
4145 HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size),
4146 kMDBSize);
4147
4148 /* If journaled and we only have one AVH to track */
4149 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
4150 journal_modify_block_end (hfsmp->jnl, alt_bp, NULL, NULL);
4151 } else {
4152 /*
4153 * If we don't have a journal or there are two AVH's at the
4154 * moment, then this one doesn't go in the journal. Note that
4155 * this one may generate I/O errors, since the partition
4156 * can be resized behind our backs at any moment and this I/O
4157 * may now appear to be beyond the device EOF.
4158 */
4159 (void) VNOP_BWRITE(alt_bp);
4160 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
4161 }
4162 } else if (alt_bp) {
4163 buf_brelse(alt_bp);
4164 }
4165 }
4166 }
4167
4168 /* Finish modifying the block for the primary VH */
4169 if (hfsmp->jnl) {
4170 journal_modify_block_end(hfsmp->jnl, bp, NULL, NULL);
4171 } else {
4172 if (!ISSET(options, HFS_FVH_WAIT)) {
4173 buf_bawrite(bp);
4174 } else {
4175 retval = VNOP_BWRITE(bp);
4176 /* When critical data changes, flush the device cache */
4177 if (critical && (retval == 0)) {
4178 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
4179 }
4180 }
4181 }
4182 hfs_end_transaction(hfsmp);
4183
4184 return (retval);
4185
4186 err_exit:
4187 if (alt_bp)
4188 buf_brelse(alt_bp);
4189 if (bp)
4190 buf_brelse(bp);
4191 hfs_end_transaction(hfsmp);
4192 return retval;
4193 }
4194
4195
4196 /*
4197 * Creates a UUID from a unique "name" in the HFS UUID Name space.
4198 * See version 3 UUID.
4199 */
4200 void
4201 hfs_getvoluuid(struct hfsmount *hfsmp, uuid_t result_uuid)
4202 {
4203
4204 if (uuid_is_null(hfsmp->hfs_full_uuid)) {
4205 uuid_t result;
4206
4207 MD5_CTX md5c;
4208 uint8_t rawUUID[8];
4209
4210 ((uint32_t *)rawUUID)[0] = hfsmp->vcbFndrInfo[6];
4211 ((uint32_t *)rawUUID)[1] = hfsmp->vcbFndrInfo[7];
4212
4213 MD5Init( &md5c );
4214 MD5Update( &md5c, HFS_UUID_NAMESPACE_ID, sizeof( uuid_t ) );
4215 MD5Update( &md5c, rawUUID, sizeof (rawUUID) );
4216 MD5Final( result, &md5c );
4217
4218 result[6] = 0x30 | ( result[6] & 0x0F );
4219 result[8] = 0x80 | ( result[8] & 0x3F );
4220
4221 uuid_copy(hfsmp->hfs_full_uuid, result);
4222 }
4223 uuid_copy (result_uuid, hfsmp->hfs_full_uuid);
4224
4225 }
4226
4227 /*
4228 * Get file system attributes.
4229 */
4230 static int
4231 hfs_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t context)
4232 {
4233 #define HFS_ATTR_FILE_VALIDMASK (ATTR_FILE_VALIDMASK & ~(ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | ATTR_FILE_CLUMPSIZE))
4234 #define HFS_ATTR_CMN_VOL_VALIDMASK (ATTR_CMN_VALIDMASK & ~(ATTR_CMN_DATA_PROTECT_FLAGS))
4235
4236 ExtendedVCB *vcb = VFSTOVCB(mp);
4237 struct hfsmount *hfsmp = VFSTOHFS(mp);
4238
4239 int searchfs_on = 0;
4240 int exchangedata_on = 1;
4241
4242 #if CONFIG_SEARCHFS
4243 searchfs_on = 1;
4244 #endif
4245
4246 #if CONFIG_PROTECT
4247 if (cp_fs_protected(mp)) {
4248 exchangedata_on = 0;
4249 }
4250 #endif
4251
4252 VFSATTR_RETURN(fsap, f_objcount, (u_int64_t)hfsmp->vcbFilCnt + (u_int64_t)hfsmp->vcbDirCnt);
4253 VFSATTR_RETURN(fsap, f_filecount, (u_int64_t)hfsmp->vcbFilCnt);
4254 VFSATTR_RETURN(fsap, f_dircount, (u_int64_t)hfsmp->vcbDirCnt);
4255 VFSATTR_RETURN(fsap, f_maxobjcount, (u_int64_t)0xFFFFFFFF);
4256 VFSATTR_RETURN(fsap, f_iosize, (size_t)cluster_max_io_size(mp, 0));
4257 VFSATTR_RETURN(fsap, f_blocks, (u_int64_t)hfsmp->totalBlocks);
4258 VFSATTR_RETURN(fsap, f_bfree, (u_int64_t)hfs_freeblks(hfsmp, 0));
4259 VFSATTR_RETURN(fsap, f_bavail, (u_int64_t)hfs_freeblks(hfsmp, 1));
4260 VFSATTR_RETURN(fsap, f_bsize, (u_int32_t)vcb->blockSize);
4261 /* XXX needs clarification */
4262 VFSATTR_RETURN(fsap, f_bused, hfsmp->totalBlocks - hfs_freeblks(hfsmp, 1));
4263 VFSATTR_RETURN(fsap, f_files, (u_int64_t)HFS_MAX_FILES);
4264 VFSATTR_RETURN(fsap, f_ffree, (u_int64_t)hfs_free_cnids(hfsmp));
4265
4266 fsap->f_fsid.val[0] = hfsmp->hfs_raw_dev;
4267 fsap->f_fsid.val[1] = vfs_typenum(mp);
4268 VFSATTR_SET_SUPPORTED(fsap, f_fsid);
4269
4270 VFSATTR_RETURN(fsap, f_signature, vcb->vcbSigWord);
4271 VFSATTR_RETURN(fsap, f_carbon_fsid, 0);
4272
4273 if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
4274 vol_capabilities_attr_t *cap;
4275
4276 cap = &fsap->f_capabilities;
4277
4278 if ((hfsmp->hfs_flags & HFS_STANDARD) == 0) {
4279 /* HFS+ & variants */
4280 cap->capabilities[VOL_CAPABILITIES_FORMAT] =
4281 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
4282 VOL_CAP_FMT_SYMBOLICLINKS |
4283 VOL_CAP_FMT_HARDLINKS |
4284 VOL_CAP_FMT_JOURNAL |
4285 VOL_CAP_FMT_ZERO_RUNS |
4286 (hfsmp->jnl ? VOL_CAP_FMT_JOURNAL_ACTIVE : 0) |
4287 (hfsmp->hfs_flags & HFS_CASE_SENSITIVE ? VOL_CAP_FMT_CASE_SENSITIVE : 0) |
4288 VOL_CAP_FMT_CASE_PRESERVING |
4289 VOL_CAP_FMT_FAST_STATFS |
4290 VOL_CAP_FMT_2TB_FILESIZE |
4291 VOL_CAP_FMT_HIDDEN_FILES |
4292 #if HFS_COMPRESSION
4293 VOL_CAP_FMT_DECMPFS_COMPRESSION |
4294 #endif
4295 #if CONFIG_HFS_DIRLINK
4296 VOL_CAP_FMT_DIR_HARDLINKS |
4297 #endif
4298 #ifdef VOL_CAP_FMT_DOCUMENT_ID
4299 VOL_CAP_FMT_DOCUMENT_ID |
4300 #endif /* VOL_CAP_FMT_DOCUMENT_ID */
4301 #ifdef VOL_CAP_FMT_WRITE_GENERATION_COUNT
4302 VOL_CAP_FMT_WRITE_GENERATION_COUNT |
4303 #endif /* VOL_CAP_FMT_WRITE_GENERATION_COUNT */
4304 VOL_CAP_FMT_PATH_FROM_ID;
4305 }
4306 #if CONFIG_HFS_STD
4307 else {
4308 /* HFS standard */
4309 cap->capabilities[VOL_CAPABILITIES_FORMAT] =
4310 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
4311 VOL_CAP_FMT_CASE_PRESERVING |
4312 VOL_CAP_FMT_FAST_STATFS |
4313 VOL_CAP_FMT_HIDDEN_FILES |
4314 VOL_CAP_FMT_PATH_FROM_ID;
4315 }
4316 #endif
4317
4318 /*
4319 * The capabilities word in 'cap' tell you whether or not
4320 * this particular filesystem instance has feature X enabled.
4321 */
4322
4323 cap->capabilities[VOL_CAPABILITIES_INTERFACES] =
4324 VOL_CAP_INT_ATTRLIST |
4325 VOL_CAP_INT_NFSEXPORT |
4326 VOL_CAP_INT_READDIRATTR |
4327 VOL_CAP_INT_ALLOCATE |
4328 VOL_CAP_INT_VOL_RENAME |
4329 VOL_CAP_INT_ADVLOCK |
4330 VOL_CAP_INT_FLOCK |
4331 #if VOL_CAP_INT_RENAME_EXCL
4332 VOL_CAP_INT_RENAME_EXCL |
4333 #endif
4334 #if NAMEDSTREAMS
4335 VOL_CAP_INT_EXTENDED_ATTR |
4336 VOL_CAP_INT_NAMEDSTREAMS;
4337 #else
4338 VOL_CAP_INT_EXTENDED_ATTR;
4339 #endif
4340
4341 /* HFS may conditionally support searchfs and exchangedata depending on the runtime */
4342
4343 if (searchfs_on) {
4344 cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_SEARCHFS;
4345 }
4346 if (exchangedata_on) {
4347 cap->capabilities[VOL_CAPABILITIES_INTERFACES] |= VOL_CAP_INT_EXCHANGEDATA;
4348 }
4349
4350 cap->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
4351 cap->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
4352
4353 cap->valid[VOL_CAPABILITIES_FORMAT] =
4354 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
4355 VOL_CAP_FMT_SYMBOLICLINKS |
4356 VOL_CAP_FMT_HARDLINKS |
4357 VOL_CAP_FMT_JOURNAL |
4358 VOL_CAP_FMT_JOURNAL_ACTIVE |
4359 VOL_CAP_FMT_NO_ROOT_TIMES |
4360 VOL_CAP_FMT_SPARSE_FILES |
4361 VOL_CAP_FMT_ZERO_RUNS |
4362 VOL_CAP_FMT_CASE_SENSITIVE |
4363 VOL_CAP_FMT_CASE_PRESERVING |
4364 VOL_CAP_FMT_FAST_STATFS |
4365 VOL_CAP_FMT_2TB_FILESIZE |
4366 VOL_CAP_FMT_OPENDENYMODES |
4367 VOL_CAP_FMT_HIDDEN_FILES |
4368 VOL_CAP_FMT_PATH_FROM_ID |
4369 VOL_CAP_FMT_DECMPFS_COMPRESSION |
4370 #ifdef VOL_CAP_FMT_DOCUMENT_ID
4371 VOL_CAP_FMT_DOCUMENT_ID |
4372 #endif /* VOL_CAP_FMT_DOCUMENT_ID */
4373 #ifdef VOL_CAP_FMT_WRITE_GENERATION_COUNT
4374 VOL_CAP_FMT_WRITE_GENERATION_COUNT |
4375 #endif /* VOL_CAP_FMT_WRITE_GENERATION_COUNT */
4376 VOL_CAP_FMT_DIR_HARDLINKS;
4377
4378 /*
4379 * Bits in the "valid" field tell you whether or not the on-disk
4380 * format supports feature X.
4381 */
4382
4383 cap->valid[VOL_CAPABILITIES_INTERFACES] =
4384 VOL_CAP_INT_ATTRLIST |
4385 VOL_CAP_INT_NFSEXPORT |
4386 VOL_CAP_INT_READDIRATTR |
4387 VOL_CAP_INT_COPYFILE |
4388 VOL_CAP_INT_ALLOCATE |
4389 VOL_CAP_INT_VOL_RENAME |
4390 VOL_CAP_INT_ADVLOCK |
4391 VOL_CAP_INT_FLOCK |
4392 VOL_CAP_INT_MANLOCK |
4393 #if VOL_CAP_INT_RENAME_EXCL
4394 VOL_CAP_INT_RENAME_EXCL |
4395 #endif
4396
4397 #if NAMEDSTREAMS
4398 VOL_CAP_INT_EXTENDED_ATTR |
4399 VOL_CAP_INT_NAMEDSTREAMS;
4400 #else
4401 VOL_CAP_INT_EXTENDED_ATTR;
4402 #endif
4403
4404 /* HFS always supports exchangedata and searchfs in the on-disk format natively */
4405 cap->valid[VOL_CAPABILITIES_INTERFACES] |= (VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_EXCHANGEDATA);
4406
4407
4408 cap->valid[VOL_CAPABILITIES_RESERVED1] = 0;
4409 cap->valid[VOL_CAPABILITIES_RESERVED2] = 0;
4410 VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
4411 }
4412 if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
4413 vol_attributes_attr_t *attrp = &fsap->f_attributes;
4414
4415 attrp->validattr.commonattr = HFS_ATTR_CMN_VOL_VALIDMASK;
4416 #if CONFIG_PROTECT
4417 attrp->validattr.commonattr |= ATTR_CMN_DATA_PROTECT_FLAGS;
4418 #endif // CONFIG_PROTECT
4419
4420 attrp->validattr.volattr = ATTR_VOL_VALIDMASK & ~ATTR_VOL_INFO;
4421 attrp->validattr.dirattr = ATTR_DIR_VALIDMASK;
4422 attrp->validattr.fileattr = HFS_ATTR_FILE_VALIDMASK;
4423 attrp->validattr.forkattr = 0;
4424
4425 attrp->nativeattr.commonattr = HFS_ATTR_CMN_VOL_VALIDMASK;
4426 #if CONFIG_PROTECT
4427 attrp->nativeattr.commonattr |= ATTR_CMN_DATA_PROTECT_FLAGS;
4428 #endif // CONFIG_PROTECT
4429
4430 attrp->nativeattr.volattr = ATTR_VOL_VALIDMASK & ~ATTR_VOL_INFO;
4431 attrp->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
4432 attrp->nativeattr.fileattr = HFS_ATTR_FILE_VALIDMASK;
4433 attrp->nativeattr.forkattr = 0;
4434 VFSATTR_SET_SUPPORTED(fsap, f_attributes);
4435 }
4436 fsap->f_create_time.tv_sec = hfsmp->hfs_itime;
4437 fsap->f_create_time.tv_nsec = 0;
4438 VFSATTR_SET_SUPPORTED(fsap, f_create_time);
4439 fsap->f_modify_time.tv_sec = hfsmp->vcbLsMod;
4440 fsap->f_modify_time.tv_nsec = 0;
4441 VFSATTR_SET_SUPPORTED(fsap, f_modify_time);
4442 // We really don't have volume access time, they should check the root node, fake it up
4443 if (VFSATTR_IS_ACTIVE(fsap, f_access_time)) {
4444 struct timeval tv;
4445
4446 microtime(&tv);
4447 fsap->f_access_time.tv_sec = tv.tv_sec;
4448 fsap->f_access_time.tv_nsec = 0;
4449 VFSATTR_SET_SUPPORTED(fsap, f_access_time);
4450 }
4451
4452 fsap->f_backup_time.tv_sec = hfsmp->vcbVolBkUp;
4453 fsap->f_backup_time.tv_nsec = 0;
4454 VFSATTR_SET_SUPPORTED(fsap, f_backup_time);
4455
4456 if (VFSATTR_IS_ACTIVE(fsap, f_fssubtype)) {
4457 u_int16_t subtype = 0;
4458
4459 /*
4460 * Subtypes (flavors) for HFS
4461 * 0: Mac OS Extended
4462 * 1: Mac OS Extended (Journaled)
4463 * 2: Mac OS Extended (Case Sensitive)
4464 * 3: Mac OS Extended (Case Sensitive, Journaled)
4465 * 4 - 127: Reserved
4466 * 128: Mac OS Standard
4467 *
4468 */
4469 if ((hfsmp->hfs_flags & HFS_STANDARD) == 0) {
4470 if (hfsmp->jnl) {
4471 subtype |= HFS_SUBTYPE_JOURNALED;
4472 }
4473 if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE) {
4474 subtype |= HFS_SUBTYPE_CASESENSITIVE;
4475 }
4476 }
4477 #if CONFIG_HFS_STD
4478 else {
4479 subtype = HFS_SUBTYPE_STANDARDHFS;
4480 }
4481 #endif
4482 fsap->f_fssubtype = subtype;
4483 VFSATTR_SET_SUPPORTED(fsap, f_fssubtype);
4484 }
4485
4486 if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) {
4487 strlcpy(fsap->f_vol_name, (char *) hfsmp->vcbVN, MAXPATHLEN);
4488 VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
4489 }
4490 if (VFSATTR_IS_ACTIVE(fsap, f_uuid)) {
4491 hfs_getvoluuid(hfsmp, fsap->f_uuid);
4492 VFSATTR_SET_SUPPORTED(fsap, f_uuid);
4493 }
4494 return (0);
4495 }
4496
4497 /*
4498 * Perform a volume rename. Requires the FS' root vp.
4499 */
4500 static int
4501 hfs_rename_volume(struct vnode *vp, const char *name, proc_t p)
4502 {
4503 ExtendedVCB *vcb = VTOVCB(vp);
4504 struct cnode *cp = VTOC(vp);
4505 struct hfsmount *hfsmp = VTOHFS(vp);
4506 struct cat_desc to_desc;
4507 struct cat_desc todir_desc;
4508 struct cat_desc new_desc;
4509 cat_cookie_t cookie;
4510 int lockflags;
4511 int error = 0;
4512 char converted_volname[256];
4513 size_t volname_length = 0;
4514 size_t conv_volname_length = 0;
4515
4516
4517 /*
4518 * Ignore attempts to rename a volume to a zero-length name.
4519 */
4520 if (name[0] == 0)
4521 return(0);
4522
4523 bzero(&to_desc, sizeof(to_desc));
4524 bzero(&todir_desc, sizeof(todir_desc));
4525 bzero(&new_desc, sizeof(new_desc));
4526 bzero(&cookie, sizeof(cookie));
4527
4528 todir_desc.cd_parentcnid = kHFSRootParentID;
4529 todir_desc.cd_cnid = kHFSRootFolderID;
4530 todir_desc.cd_flags = CD_ISDIR;
4531
4532 to_desc.cd_nameptr = (const u_int8_t *)name;
4533 to_desc.cd_namelen = strlen(name);
4534 to_desc.cd_parentcnid = kHFSRootParentID;
4535 to_desc.cd_cnid = cp->c_cnid;
4536 to_desc.cd_flags = CD_ISDIR;
4537
4538 if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT)) == 0) {
4539 if ((error = hfs_start_transaction(hfsmp)) == 0) {
4540 if ((error = cat_preflight(hfsmp, CAT_RENAME, &cookie, p)) == 0) {
4541 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
4542
4543 error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc);
4544
4545 /*
4546 * If successful, update the name in the VCB, ensure it's terminated.
4547 */
4548 if (error == 0) {
4549 strlcpy((char *)vcb->vcbVN, name, sizeof(vcb->vcbVN));
4550
4551 volname_length = strlen ((const char*)vcb->vcbVN);
4552 /* Send the volume name down to CoreStorage if necessary */
4553 error = utf8_normalizestr(vcb->vcbVN, volname_length, (u_int8_t*)converted_volname, &conv_volname_length, 256, UTF_PRECOMPOSED);
4554 if (error == 0) {
4555 (void) VNOP_IOCTL (hfsmp->hfs_devvp, _DKIOCCSSETLVNAME, converted_volname, 0, vfs_context_current());
4556 }
4557 error = 0;
4558 }
4559
4560 hfs_systemfile_unlock(hfsmp, lockflags);
4561 cat_postflight(hfsmp, &cookie, p);
4562
4563 if (error)
4564 MarkVCBDirty(vcb);
4565 (void) hfs_flushvolumeheader(hfsmp, HFS_FVH_WAIT);
4566 }
4567 hfs_end_transaction(hfsmp);
4568 }
4569 if (!error) {
4570 /* Release old allocated name buffer */
4571 if (cp->c_desc.cd_flags & CD_HASBUF) {
4572 const char *tmp_name = (const char *)cp->c_desc.cd_nameptr;
4573
4574 cp->c_desc.cd_nameptr = 0;
4575 cp->c_desc.cd_namelen = 0;
4576 cp->c_desc.cd_flags &= ~CD_HASBUF;
4577 vfs_removename(tmp_name);
4578 }
4579 /* Update cnode's catalog descriptor */
4580 replace_desc(cp, &new_desc);
4581 vcb->volumeNameEncodingHint = new_desc.cd_encoding;
4582 cp->c_touch_chgtime = TRUE;
4583 }
4584
4585 hfs_unlock(cp);
4586 }
4587
4588 return(error);
4589 }
4590
4591 /*
4592 * Get file system attributes.
4593 */
4594 static int
4595 hfs_vfs_setattr(struct mount *mp, struct vfs_attr *fsap, vfs_context_t context)
4596 {
4597 kauth_cred_t cred = vfs_context_ucred(context);
4598 int error = 0;
4599
4600 /*
4601 * Must be superuser or owner of filesystem to change volume attributes
4602 */
4603 if (!kauth_cred_issuser(cred) && (kauth_cred_getuid(cred) != vfs_statfs(mp)->f_owner))
4604 return(EACCES);
4605
4606 if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) {
4607 vnode_t root_vp;
4608
4609 error = hfs_vfs_root(mp, &root_vp, context);
4610 if (error)
4611 goto out;
4612
4613 error = hfs_rename_volume(root_vp, fsap->f_vol_name, vfs_context_proc(context));
4614 (void) vnode_put(root_vp);
4615 if (error)
4616 goto out;
4617
4618 VFSATTR_SET_SUPPORTED(fsap, f_vol_name);
4619 }
4620
4621 out:
4622 return error;
4623 }
4624
4625 /* If a runtime corruption is detected, set the volume inconsistent
4626 * bit in the volume attributes. The volume inconsistent bit is a persistent
4627 * bit which represents that the volume is corrupt and needs repair.
4628 * The volume inconsistent bit can be set from the kernel when it detects
4629 * runtime corruption or from file system repair utilities like fsck_hfs when
4630 * a repair operation fails. The bit should be cleared only from file system
4631 * verify/repair utility like fsck_hfs when a verify/repair succeeds.
4632 */
4633 void hfs_mark_inconsistent(struct hfsmount *hfsmp,
4634 hfs_inconsistency_reason_t reason)
4635 {
4636 hfs_lock_mount (hfsmp);
4637 if ((hfsmp->vcbAtrb & kHFSVolumeInconsistentMask) == 0) {
4638 hfsmp->vcbAtrb |= kHFSVolumeInconsistentMask;
4639 MarkVCBDirty(hfsmp);
4640 }
4641 if ((hfsmp->hfs_flags & HFS_READ_ONLY)==0) {
4642 switch (reason) {
4643 case HFS_INCONSISTENCY_DETECTED:
4644 printf("hfs_mark_inconsistent: Runtime corruption detected on %s, fsck will be forced on next mount.\n",
4645 hfsmp->vcbVN);
4646 break;
4647 case HFS_ROLLBACK_FAILED:
4648 printf("hfs_mark_inconsistent: Failed to roll back; volume `%s' might be inconsistent; fsck will be forced on next mount.\n",
4649 hfsmp->vcbVN);
4650 break;
4651 case HFS_OP_INCOMPLETE:
4652 printf("hfs_mark_inconsistent: Failed to complete operation; volume `%s' might be inconsistent; fsck will be forced on next mount.\n",
4653 hfsmp->vcbVN);
4654 break;
4655 case HFS_FSCK_FORCED:
4656 printf("hfs_mark_inconsistent: fsck requested for `%s'; fsck will be forced on next mount.\n",
4657 hfsmp->vcbVN);
4658 break;
4659 }
4660 }
4661 hfs_unlock_mount (hfsmp);
4662 }
4663
4664 /* Replay the journal on the device node provided. Returns zero if
4665 * journal replay succeeded or no journal was supposed to be replayed.
4666 */
4667 static int hfs_journal_replay(vnode_t devvp, vfs_context_t context)
4668 {
4669 int retval = 0;
4670 int error = 0;
4671
4672 /* Replay allowed only on raw devices */
4673 if (!vnode_ischr(devvp) && !vnode_isblk(devvp))
4674 return EINVAL;
4675
4676 retval = hfs_mountfs(devvp, NULL, NULL, /* journal_replay_only: */ 1, context);
4677 buf_flushdirtyblks(devvp, TRUE, 0, "hfs_journal_replay");
4678
4679 /* FSYNC the devnode to be sure all data has been flushed */
4680 error = VNOP_FSYNC(devvp, MNT_WAIT, context);
4681 if (error) {
4682 retval = error;
4683 }
4684
4685 return retval;
4686 }
4687
4688
4689 /*
4690 * Cancel the syncer
4691 */
4692 static void
4693 hfs_syncer_free(struct hfsmount *hfsmp)
4694 {
4695 if (hfsmp && ISSET(hfsmp->hfs_flags, HFS_RUN_SYNCER)) {
4696 hfs_syncer_lock(hfsmp);
4697 CLR(hfsmp->hfs_flags, HFS_RUN_SYNCER);
4698 hfs_syncer_unlock(hfsmp);
4699
4700 // Wait for the syncer thread to finish
4701 if (hfsmp->hfs_syncer_thread) {
4702 hfs_syncer_wakeup(hfsmp);
4703 hfs_syncer_lock(hfsmp);
4704 while (hfsmp->hfs_syncer_thread)
4705 hfs_syncer_wait(hfsmp, NULL);
4706 hfs_syncer_unlock(hfsmp);
4707 }
4708 }
4709 }
4710
4711 static int hfs_vfs_ioctl(struct mount *mp, u_long command, caddr_t data,
4712 __unused int flags, __unused vfs_context_t context)
4713 {
4714 switch (command) {
4715 #if CONFIG_PROTECT
4716 case FIODEVICELOCKED:
4717 cp_device_locked_callback(mp, (cp_lock_state_t)data);
4718 return 0;
4719 #endif
4720 }
4721 return ENOTTY;
4722 }
4723
4724 /*
4725 * hfs vfs operations.
4726 */
4727 struct vfsops hfs_vfsops = {
4728 .vfs_mount = hfs_mount,
4729 .vfs_start = hfs_start,
4730 .vfs_unmount = hfs_unmount,
4731 .vfs_root = hfs_vfs_root,
4732 .vfs_quotactl = hfs_quotactl,
4733 .vfs_getattr = hfs_vfs_getattr,
4734 .vfs_sync = hfs_sync,
4735 .vfs_vget = hfs_vfs_vget,
4736 .vfs_fhtovp = hfs_fhtovp,
4737 .vfs_vptofh = hfs_vptofh,
4738 .vfs_init = hfs_init,
4739 .vfs_sysctl = hfs_sysctl,
4740 .vfs_setattr = hfs_vfs_setattr,
4741 .vfs_ioctl = hfs_vfs_ioctl,
4742 };