1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
6 * Created by Or Haimovich on 18/3/18.
9 #include "lf_hfs_common.h"
10 #include <CommonCrypto/CommonDigest.h>
11 #include <stdatomic.h>
12 #include <sys/ioctl.h>
13 #include <sys/mount.h>
17 #include "lf_hfs_logger.h"
18 #include "lf_hfs_mount.h"
20 #include "lf_hfs_catalog.h"
21 #include "lf_hfs_cnode.h"
22 #include "lf_hfs_chash.h"
23 #include "lf_hfs_format.h"
24 #include "lf_hfs_locks.h"
25 #include "lf_hfs_endian.h"
26 #include "lf_hfs_locks.h"
27 #include "lf_hfs_utils.h"
28 #include "lf_hfs_raw_read_write.h"
29 #include "lf_hfs_vfsutils.h"
30 #include "lf_hfs_vfsops.h"
31 #include "lf_hfs_volume_allocation.h"
32 #include "lf_hfs_catalog.h"
33 #include "lf_hfs_link.h"
34 #include "lf_hfs_vnops.h"
35 #include "lf_hfs_generic_buf.h"
36 #include "lf_hfs_fsops_handler.h"
37 #include "lf_hfs_journal.h"
38 #include "lf_hfs_fileops_handler.h"
42 static void hfs_locks_destroy(struct hfsmount
*hfsmp
);
43 static int hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct hfs_mount_args
*args
);
47 setup_posix_file_action_for_fsck(posix_spawn_file_actions_t
*file_actions
, int fd
)
51 if (file_actions
== NULL
|| fd
< 0)
56 error
= posix_spawn_file_actions_init(file_actions
);
62 error
= posix_spawn_file_actions_addinherit_np(file_actions
, 0);
68 error
= posix_spawn_file_actions_addinherit_np(file_actions
, 1);
74 error
= posix_spawn_file_actions_addinherit_np(file_actions
, 2);
80 error
= posix_spawn_file_actions_addinherit_np(file_actions
, fd
);
87 setup_spawnattr_for_fsck(posix_spawnattr_t
*spawn_attr
)
91 error
= posix_spawnattr_init(spawn_attr
);
96 error
= posix_spawnattr_setflags(spawn_attr
, POSIX_SPAWN_CLOEXEC_DEFAULT
);
103 // fsck_mount_and_replay: executed on fsck_hfs -quick
104 // Try to mount, and if a journaled volume, play the journal.
107 // 1) On journaled volumes, the journal has been replayed and the dirty bit cleared.
108 // 2) On non-journalled volumes, the dirty is cleared.
110 // 1) On non-journalled volumes the dirty bit is set. Please run fsck_hfs to fix.
111 // 2) On journalled volume, the replay failed. Try fsck_hfs.
112 int fsck_mount_and_replay(int iFd
) {
115 LFHFS_LOG(LEVEL_DEBUG
, "fsck_mount_and_replay %d", iFd
);
117 UVFSFileNode sRootNode
;
119 iErr
= LFHFS_Taste(iFd
);
121 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_Taste returned %d", iErr
);
125 UVFSScanVolsRequest sScanVolsReq
= {0};
126 UVFSScanVolsReply sScanVolsReply
= {0};
127 iErr
= LFHFS_ScanVols(iFd
, &sScanVolsReq
, &sScanVolsReply
);
129 LFHFS_LOG(LEVEL_DEBUG
, "LFHFS_ScanVol returned %d", iErr
);
133 // Mount and replay journal if possible
134 iErr
= LFHFS_Mount(iFd
, 0, 0, NULL
, &sRootNode
); // On journaled volumes, this replays the journal.
135 // Non-journaled volumes fails to mount if dirty (Unmounted == 0).
137 LFHFS_LOG(LEVEL_DEBUG
, "fsck_mount_and_replay: LFHFS_Mount returned %d", iErr
);
141 LFHFS_Unmount (sRootNode
, UVFSUnmountHintNone
);
146 #define PATH_TO_FSCK "/System/Library/Filesystems/hfs.fs/Contents/Resources/fsck_hfs"
149 fsck_hfs(int fd
, check_flags_t how
)
154 extern char **environ
;
155 char fdescfs_path
[24];
156 posix_spawn_file_actions_t file_actions
;
158 posix_spawnattr_t spawn_attr
;
161 * XXXJRT There are dragons related to how the journal is replayed in
162 * fsck_hfs. Until we can sort out the mess, disable running fsck_hfs.
163 * <rdar://problem/47262605> USB: Re-enable Detonator fsck_hfs
165 if (how
== QUICK_CHECK
) {
166 if (fsck_mount_and_replay(fd
) == 0) {
171 LFHFS_LOG(LEVEL_DEFAULT
, "fsck_hfs - fsck start for %d", fd
);
172 snprintf(fdescfs_path
, sizeof(fdescfs_path
), "/dev/fd/%d", fd
);
173 const char * argv
[] = {"fsck_hfs", "-q", fdescfs_path
, NULL
};
178 /* Do nothing, already setup for this */
183 case CHECK_AND_REPAIR
:
187 LFHFS_LOG(LEVEL_ERROR
, "Invalid how flags for the check, ignoring; %d", how
);
191 LFHFS_LOG(LEVEL_DEBUG
, "fsck_hfs params: %s %s %s", argv
[1], argv
[2], argv
[3]);
192 result
= setup_posix_file_action_for_fsck(&file_actions
, fd
);
198 result
= setup_spawnattr_for_fsck(&spawn_attr
);
201 posix_spawn_file_actions_destroy(&file_actions
);
205 result
= posix_spawn(&child
,
209 (char * const *)argv
,
212 posix_spawn_file_actions_destroy(&file_actions
);
213 posix_spawnattr_destroy(&spawn_attr
);
216 LFHFS_LOG(LEVEL_ERROR
, "posix_spawn fsck_hfs: error=%d", result
);
220 // Wait for child to finish, XXXab: revisit, need sensible timeout?
222 child_found
= waitpid(child
, &child_status
, 0);
223 } while (child_found
== -1 && errno
== EINTR
);
225 if (child_found
== -1)
228 LFHFS_LOG(LEVEL_ERROR
, "waitpid fsck_hfs: errno=%d", result
);
232 if (WIFEXITED(child_status
))
234 result
= WEXITSTATUS(child_status
);
237 LFHFS_LOG(LEVEL_ERROR
, "fsck_hfs: exited with status %d", result
);
240 LFHFS_LOG(LEVEL_ERROR
, "fsck_hfs: exited with status %d", result
);
245 result
= WTERMSIG(child_status
);
246 LFHFS_LOG(LEVEL_ERROR
, "fsck_hfs: terminated by signal %d", result
);
251 LFHFS_LOG(LEVEL_DEFAULT
, "fsck_hfs - fsck finish for %d with err %d", fd
, result
);
256 hfs_mount(struct mount
*mp
, vnode_t devvp
, user_addr_t data
)
258 struct hfsmount
*hfsmp
= NULL
;
266 retval
= hfs_mountfs(devvp
, mp
, NULL
);
269 // ENOTSUP is for regular HFS -> just fail
270 if (retval
!= ENOTSUP
)
272 //Failed during mount, try to run fsck to fix and try mount again
273 retval
= fsck_hfs(devvp
->psFSRecord
->iFD
, CHECK_AND_REPAIR
);
275 // fsck succeeded, try to mount
277 retval
= hfs_mountfs(devvp
, mp
, NULL
);
283 LFHFS_LOG(LEVEL_ERROR
, "hfs_mount: hfs_mountfs returned error=%d\n", retval
);
287 /* After hfs_mountfs succeeds, we should have valid hfsmp */
288 hfsmp
= VFSTOHFS(mp
);
290 /* Set up the maximum defrag file size */
291 hfsmp
->hfs_defrag_max
= HFS_INITIAL_DEFRAG_SIZE
;
296 hfsmp
->hfs_uid
= UNKNOWNUID
;
297 hfsmp
->hfs_gid
= UNKNOWNGID
;
298 hfsmp
->hfs_dir_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
299 hfsmp
->hfs_file_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
301 /* Establish the free block reserve. */
302 hfsmp
->reserveBlocks
= (uint32_t) ((u_int64_t
)hfsmp
->totalBlocks
* HFS_MINFREE
) / 100;
303 hfsmp
->reserveBlocks
= MIN(hfsmp
->reserveBlocks
, HFS_MAXRESERVE
/ hfsmp
->blockSize
);
310 static int hfs_InitialMount(struct vnode
*devvp
, struct mount
*mp
, struct hfs_mount_args
*args
, HFSPlusVolumeHeader
**vhp
, off_t
*embeddedOffset
, struct hfsmount
**hfsmp
, bool bFailForDirty
)
313 HFSMasterDirectoryBlock
*mdbp
= NULL
;
314 void* pvBuffer
= NULL
;
317 u_int64_t log_blkcnt
;
318 u_int32_t log_blksize
;
319 u_int32_t phys_blksize
;
320 u_int32_t minblksize
;
321 u_int32_t iswritable
;
322 u_int64_t mdb_offset
;
323 u_int32_t device_features
= 0;
326 minblksize
= kHFSBlockSize
;
328 /* Get the logical block size (treated as physical block size everywhere) */
329 if (ioctl(devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKSIZE
, &log_blksize
))
331 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: DKIOCGETBLOCKSIZE failed\n");
335 if (log_blksize
== 0 || log_blksize
> 1024*1024*1024)
337 LFHFS_LOG(LEVEL_ERROR
, "hfs_mountfs: logical block size 0x%x looks bad. Not mounting.\n", log_blksize
);
342 /* Get the physical block size. */
343 if (ioctl(devvp
->psFSRecord
->iFD
, DKIOCGETPHYSICALBLOCKSIZE
, &phys_blksize
))
345 if ((retval
!= ENOTSUP
) && (retval
!= ENOTTY
))
347 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: DKIOCGETPHYSICALBLOCKSIZE failed\n");
351 /* If device does not support this ioctl, assume that physical
352 * block size is same as logical block size
354 phys_blksize
= log_blksize
;
357 if (phys_blksize
== 0 || phys_blksize
> MAXBSIZE
)
359 LFHFS_LOG(LEVEL_ERROR
, "hfs_mountfs: physical block size 0x%x looks bad. Not mounting.\n", phys_blksize
);
364 /* Get the number of physical blocks. */
365 if (ioctl(devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKCOUNT
, &log_blkcnt
))
367 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: DKIOCGETBLOCKCOUNT failed\n");
372 /* Compute an accurate disk size (i.e. within 512 bytes) */
373 disksize
= (u_int64_t
)log_blkcnt
* (u_int64_t
)log_blksize
;
377 * minblksize is the minimum physical block size
378 * log_blksize has our preferred physical block size
379 * log_blkcnt has the total number of physical blocks
381 mdbp
= hfs_mallocz(kMDBSize
);
388 pvBuffer
= hfs_malloc(phys_blksize
);
389 if (pvBuffer
== NULL
)
395 mdb_offset
= (uint64_t) HFS_PRI_SECTOR(log_blksize
);
396 retval
= raw_readwrite_read_mount( devvp
, HFS_PHYSBLK_ROUNDDOWN(mdb_offset
, (phys_blksize
/log_blksize
)), phys_blksize
, pvBuffer
, phys_blksize
, NULL
, NULL
);
399 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: raw_readwrite_read_mount failed with %d\n", retval
);
403 bcopy(pvBuffer
+ HFS_PRI_OFFSET(phys_blksize
), mdbp
, kMDBSize
);
407 *hfsmp
= hfs_malloc(sizeof(struct hfsmount
));
413 memset( *hfsmp
, 0, sizeof(struct hfsmount
) );
415 //Copy read only flag
416 if (mp
->mnt_flag
== MNT_RDONLY
) (*hfsmp
)->hfs_flags
= HFS_READ_ONLY
;
418 hfs_chashinit_finish(*hfsmp
);
420 /* Init the ID lookup hashtable */
421 hfs_idhash_init (*hfsmp
);
424 * See if the disk supports unmap (trim).
426 * NOTE: vfs_init_io_attributes has not been called yet, so we can't use the io_flags field
427 * returned by vfs_ioattr. We need to call VNOP_IOCTL ourselves.
429 if (ioctl(devvp
->psFSRecord
->iFD
, DKIOCGETFEATURES
, &device_features
) == 0)
431 if (device_features
& DK_FEATURE_UNMAP
)
433 (*hfsmp
)->hfs_flags
|= HFS_UNMAP
;
436 if(device_features
& DK_FEATURE_BARRIER
)
438 (*hfsmp
)->hfs_flags
|= HFS_FEATURE_BARRIER
;
443 * Init the volume information structure
445 lf_lck_mtx_init(&(*hfsmp
)->hfs_mutex
);
446 lf_lck_mtx_init(&(*hfsmp
)->sync_mutex
);
447 lf_lck_rw_init(&(*hfsmp
)->hfs_global_lock
);
448 lf_lck_spin_init(&(*hfsmp
)->vcbFreeExtLock
);
452 mp
->psHfsmount
= (*hfsmp
);
455 (*hfsmp
)->hfs_mp
= mp
; /* Make VFSTOHFS work */
456 (*hfsmp
)->hfs_raw_dev
= 0; //vnode_specrdev(devvp);
457 (*hfsmp
)->hfs_devvp
= devvp
;
458 (*hfsmp
)->hfs_logical_block_size
= log_blksize
;
459 (*hfsmp
)->hfs_logical_block_count
= log_blkcnt
;
460 (*hfsmp
)->hfs_logical_bytes
= (uint64_t) log_blksize
* (uint64_t) log_blkcnt
;
461 (*hfsmp
)->hfs_physical_block_size
= phys_blksize
;
462 (*hfsmp
)->hfs_log_per_phys
= (phys_blksize
/ log_blksize
);
463 (*hfsmp
)->hfs_flags
|= HFS_WRITEABLE_MEDIA
;
465 if (mp
&& (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
))
467 (*hfsmp
)->hfs_flags
|= HFS_UNKNOWN_PERMS
;
470 /* MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
471 if (mp
&& (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
))
473 (*hfsmp
)->hfs_uid
= UNKNOWNUID
;
474 (*hfsmp
)->hfs_gid
= UNKNOWNGID
;
475 // vfs_setowner(mp, hfsmp->hfs_uid, hfsmp->hfs_gid); /* tell the VFS */
476 (*hfsmp
)->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
477 (*hfsmp
)->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
480 /* Find out if disk media is writable. */
481 if (ioctl(devvp
->psFSRecord
->iFD
, DKIOCISWRITABLE
, &iswritable
) == 0)
485 (*hfsmp
)->hfs_flags
|= HFS_WRITEABLE_MEDIA
;
489 (*hfsmp
)->hfs_flags
&= ~HFS_WRITEABLE_MEDIA
;
494 rl_init(&(*hfsmp
)->hfs_reserved_ranges
[0]);
495 rl_init(&(*hfsmp
)->hfs_reserved_ranges
[1]);
497 // record the current time at which we're mounting this volume
500 (*hfsmp
)->hfs_mount_time
= tv
.tv_sec
;
502 /* Mount an HFS Plus disk */
505 /* Mount a standard HFS disk */
506 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) && (mntwrapper
|| (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
)))
508 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: Not supporting standard HFS\n");
512 /* Get the embedded Volume Header */
513 else if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
)
515 *embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * kHFSBlockSize
;
516 *embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) * (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
519 * If the embedded volume doesn't start on a block
520 * boundary, then switch the device to a 512-byte
521 * block size so everything will line up on a block
524 if ((*embeddedOffset
% log_blksize
) != 0)
526 // LF not support DKIOCSETBLOCKSIZE, return error.
527 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_mountfs: embedded volume offset not a multiple of physical block size (%d); switching to 512\n", log_blksize
);
532 disksize
= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.blockCount
) * (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
534 (*hfsmp
)->hfs_logical_block_count
= disksize
/ log_blksize
;
536 (*hfsmp
)->hfs_logical_bytes
= (uint64_t) (*hfsmp
)->hfs_logical_block_count
* (uint64_t) (*hfsmp
)->hfs_logical_block_size
;
538 mdb_offset
= (uint64_t)((*embeddedOffset
/ log_blksize
) + HFS_PRI_SECTOR(log_blksize
));
540 pvBuffer
= hfs_malloc(phys_blksize
);
541 if (pvBuffer
== NULL
)
547 retval
= raw_readwrite_read_mount( devvp
, HFS_PHYSBLK_ROUNDDOWN(mdb_offset
, (phys_blksize
/log_blksize
)), phys_blksize
, pvBuffer
, phys_blksize
, NULL
, NULL
);
550 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: raw_readwrite_read_mount (2) failed with %d\n", retval
);
554 bcopy(pvBuffer
+ HFS_PRI_OFFSET(phys_blksize
), mdbp
, kMDBSize
);
555 *vhp
= (HFSPlusVolumeHeader
*) mdbp
;
562 *vhp
= (HFSPlusVolumeHeader
*) mdbp
;
565 retval
= hfs_ValidateHFSPlusVolumeHeader(*hfsmp
, *vhp
);
570 * If allocation block size is less than the physical block size,
571 * invalidate the buffer read in using native physical block size
572 * to ensure data consistency.
574 * HFS Plus reserves one allocation block for the Volume Header.
575 * If the physical size is larger, then when we read the volume header,
576 * we will also end up reading in the next allocation block(s).
577 * If those other allocation block(s) is/are modified, and then the volume
578 * header is modified, the write of the volume header's buffer will write
579 * out the old contents of the other allocation blocks.
581 * We assume that the physical block size is same as logical block size.
582 * The physical block size value is used to round down the offsets for
583 * reading and writing the primary and alternate volume headers.
585 * The same logic is also in hfs_MountHFSPlusVolume to ensure that
586 * hfs_mountfs, hfs_MountHFSPlusVolume and later are doing the I/Os
587 * using same block size.
589 if (SWAP_BE32((*vhp
)->blockSize
) < (*hfsmp
)->hfs_physical_block_size
)
591 phys_blksize
= (*hfsmp
)->hfs_logical_block_size
;
592 (*hfsmp
)->hfs_physical_block_size
= (*hfsmp
)->hfs_logical_block_size
;
593 (*hfsmp
)->hfs_log_per_phys
= 1;
600 * On inconsistent disks, do not allow read-write mount
601 * unless it is the boot volume being mounted. We also
602 * always want to replay the journal if the journal_replay_only
603 * flag is set because that will (most likely) get the
604 * disk into a consistent state before fsck_hfs starts
607 if ( (mp
&& !(mp
->mnt_flag
& MNT_ROOTFS
))
608 && (SWAP_BE32((*vhp
)->attributes
) & kHFSVolumeInconsistentMask
)
609 && !((*hfsmp
)->hfs_flags
& HFS_READ_ONLY
))
611 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: failed to mount non-root inconsistent disk\n");
616 (*hfsmp
)->jnl
= NULL
;
617 (*hfsmp
)->jvp
= NULL
;
618 if (args
!= NULL
&& (args
->flags
& HFSFSMNT_EXTENDED_ARGS
) && args
->journal_disable
)
624 * We only initialize the journal here if the last person
625 * to mount this volume was journaling aware. Otherwise
626 * we delay journal initialization until later at the end
627 * of hfs_MountHFSPlusVolume() because the last person who
628 * mounted it could have messed things up behind our back
629 * (so we need to go find the .journal file, make sure it's
630 * the right size, re-sync up if it was moved, etc).
632 uint32_t lastMountedVersion
= SWAP_BE32((*vhp
)->lastMountedVersion
);
633 uint32_t attributes
= SWAP_BE32((*vhp
)->attributes
);
634 if ( (lastMountedVersion
== kHFSJMountVersion
) &&
635 (attributes
& kHFSVolumeJournaledMask
) &&
639 // if we're able to init the journal, mark the mount
640 // point as journaled.
641 if ((retval
= hfs_early_journal_init(*hfsmp
, *vhp
, args
, *embeddedOffset
, mdb_offset
, mdbp
)) != 0)
645 // EROFS is a special error code that means the volume has an external
646 // journal which we couldn't find. in that case we do not want to
647 // rewrite the volume header - we'll just refuse to mount the volume.
648 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_early_journal_init indicated external jnl \n");
653 // if the journal failed to open, then set the lastMountedVersion
654 // to be "FSK!" which fsck_hfs will see and force the fsck instead
655 // of just bailing out because the volume is journaled.
656 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_early_journal_init failed, setting to FSK \n");
657 HFSPlusVolumeHeader
*jvhp
;
659 (*hfsmp
)->hfs_flags
|= HFS_NEED_JNL_RESET
;
663 mdb_offset
= (uint64_t)((*embeddedOffset
/ log_blksize
) + HFS_PRI_SECTOR(log_blksize
));
666 pvBuffer
= hfs_malloc(phys_blksize
);
667 if (pvBuffer
== NULL
)
673 retval
= raw_readwrite_read_mount( devvp
, HFS_PHYSBLK_ROUNDDOWN(mdb_offset
, (*hfsmp
)->hfs_log_per_phys
), phys_blksize
, pvBuffer
, phys_blksize
, NULL
, NULL
);
676 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: raw_readwrite_read_mount (3) failed with %d\n", retval
);
680 jvhp
= (HFSPlusVolumeHeader
*)(pvBuffer
+ HFS_PRI_OFFSET(phys_blksize
));
682 if (SWAP_BE16(jvhp
->signature
) == kHFSPlusSigWord
|| SWAP_BE16(jvhp
->signature
) == kHFSXSigWord
)
684 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_mountfs: Journal replay fail. Writing lastMountVersion as FSK!\n");
686 jvhp
->lastMountedVersion
= SWAP_BE32(kFSKMountVersion
);
687 retval
= raw_readwrite_write_mount( devvp
, HFS_PHYSBLK_ROUNDDOWN(mdb_offset
, (*hfsmp
)->hfs_log_per_phys
), phys_blksize
, pvBuffer
, phys_blksize
, NULL
, NULL
);
690 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: raw_readwrite_write_mount (1) failed with %d\n", retval
);
697 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_early_journal_init failed, erroring out \n");
703 retval
= hfs_MountHFSPlusVolume(*hfsmp
, *vhp
, *embeddedOffset
, disksize
, bFailForDirty
);
705 * If the backend didn't like our physical blocksize
706 * then retry with physical blocksize of 512.
708 if ((retval
== ENXIO
) && (log_blksize
> 512) && (log_blksize
!= minblksize
))
710 // LF not support DKIOCSETBLOCKSIZE, return error.
711 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_mountfs: could not use physical block size (%d).\n", log_blksize
);
716 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_MountHFSPlusVolume encountered failure %d \n", retval
);
730 hfs_locks_destroy(*hfsmp
);
731 hfs_delete_chash(*hfsmp
);
732 hfs_idhash_destroy (*hfsmp
);
741 int hfs_ScanVolGetVolName(int iFd
, char* pcVolumeName
)
745 HFSPlusVolumeHeader
*vhp
;
746 off_t embeddedOffset
;
747 struct hfsmount
*hfsmp
;
748 struct mount
* psMount
= hfs_mallocz(sizeof(struct mount
));
749 struct vnode
* psDevVnode
= hfs_mallocz(sizeof(struct vnode
));
750 struct cnode
* psDevCnode
= hfs_mallocz(sizeof(struct cnode
));
751 struct filefork
* psDevFileFork
= hfs_mallocz(sizeof(struct filefork
));
752 FileSystemRecord_s
*psFSRecord
= hfs_mallocz(sizeof(FileSystemRecord_s
));
754 if ( psMount
== NULL
|| psDevVnode
== NULL
|| psDevCnode
== NULL
|| psDevFileFork
== NULL
|| psFSRecord
== NULL
)
757 LFHFS_LOG(LEVEL_ERROR
, "hfs_ScanVolGetVolName: failed to malloc initial system files\n");
761 psFSRecord
->iFD
= iFd
;
762 psDevVnode
->psFSRecord
= psFSRecord
;
763 psDevVnode
->sFSParams
.vnfs_marksystem
= 1;
764 psDevVnode
->bIsMountVnode
= true;
766 // Initializing inputs for hfs_mount
767 psDevFileFork
->ff_data
.cf_blocks
= 3;
768 psDevFileFork
->ff_data
.cf_extents
[0].blockCount
= 1;
769 psDevFileFork
->ff_data
.cf_extents
[0].startBlock
= 0;
771 psDevVnode
->sFSParams
.vnfs_fsnode
= psDevCnode
;
772 psDevCnode
->c_vp
= psDevVnode
;
773 psDevVnode
->is_rsrc
= false;
774 psDevCnode
->c_datafork
= psDevFileFork
;
775 psDevVnode
->sFSParams
.vnfs_mp
= psMount
;
777 retval
= hfs_InitialMount(psDevVnode
, psMount
, 0, &vhp
, &embeddedOffset
, &hfsmp
, false);
785 strlcpy(pcVolumeName
, (char*) hfsmp
->vcbVN
, UVFS_SCANVOLS_VOLNAME_MAX
);
792 journal_release(hfsmp
->jnl
);
798 hfs_locks_destroy(hfsmp
);
799 hfs_delete_chash(hfsmp
);
800 hfs_idhash_destroy (hfsmp
);
808 LFHFS_LOG(LEVEL_ERROR
, "hfs_ScanVolGetVolName: failed with error %d, returning empty name and no error\n",retval
);
809 pcVolumeName
[0] = '\0';
812 if (psMount
) free (psMount
);
813 if (psDevVnode
) free (psDevVnode
);
814 if (psDevCnode
) free (psDevCnode
);
815 if (psDevFileFork
) free (psDevFileFork
);
816 if (psFSRecord
) free (psFSRecord
);
822 * Common code for mount and mountroot
825 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct hfs_mount_args
*args
)
829 HFSPlusVolumeHeader
*vhp
;
830 off_t embeddedOffset
;
831 struct hfsmount
*hfsmp
;
832 retval
= hfs_InitialMount(devvp
, mp
, args
, &vhp
, &embeddedOffset
, &hfsmp
, true);
835 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_InitialMount encountered failure %d \n", retval
);
836 //No need to go to error_exit, since everything got reset at the Initial Mount
840 retval
= hfs_CollectBtreeStats(hfsmp
, vhp
, embeddedOffset
, args
);
845 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_CollectBtreeStats encountered failure %d \n", retval
);
849 // save off a snapshot of the mtime from the previous mount
851 hfsmp
->hfs_last_mounted_mtime
= hfsmp
->hfs_mtime
;
855 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: encountered failure %d \n", retval
);
859 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_mountfs: mounted %s on device %s\n", (hfsmp
->vcbVN
[0] ? (const char*) hfsmp
->vcbVN
: "unknown"), "unknown device");
861 hfs_flushvolumeheader(hfsmp
, 0);
872 hfs_locks_destroy(hfsmp
);
873 hfs_delete_chash(hfsmp
);
874 hfs_idhash_destroy (hfsmp
);
883 * Destroy all locks, mutexes and spinlocks in hfsmp on unmount or failed mount
886 hfs_locks_destroy(struct hfsmount
*hfsmp
)
889 lf_lck_mtx_destroy(&hfsmp
->hfs_mutex
);
890 lf_lck_mtx_destroy(&hfsmp
->sync_mutex
);
891 lf_lck_rw_destroy(&hfsmp
->hfs_global_lock
);
892 lf_lck_spin_destroy(&hfsmp
->vcbFreeExtLock
);
899 * Flush any dirty in-memory mount data to the on-disk
902 * Note: the on-disk volume signature is intentionally
903 * not flushed since the on-disk "H+" and "HX" signatures
904 * are always stored in-memory as "H+".
907 hfs_flushvolumeheader(struct hfsmount
*hfsmp
, hfs_flush_volume_header_options_t options
)
911 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
912 bool critical
= false;
913 daddr64_t avh_sector
;
914 bool altflush
= ISSET(options
, HFS_FVH_WRITE_ALT
);
916 void *pvVolHdrData
= NULL
;
917 GenericLFBuf
*psVolHdrBuf
= NULL
;
918 void *pvVolHdr2Data
= NULL
;
919 GenericLFBuf
*psVolHdr2Buf
= NULL
;
920 void *pvAltHdrData
= NULL
;
921 GenericLFBuf
*psAltHdrBuf
= NULL
;
924 if (ISSET(options
, HFS_FVH_FLUSH_IF_DIRTY
) && !hfs_header_needs_flushing(hfsmp
)) {
928 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
) {
932 if (options
& HFS_FVH_MARK_UNMOUNT
) {
933 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
935 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
938 daddr64_t priIDSector
= (daddr64_t
)((vcb
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_PRI_SECTOR(hfsmp
->hfs_logical_block_size
));
940 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
941 if (hfs_start_transaction(hfsmp
) != 0) {
946 psVolHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
947 HFS_PHYSBLK_ROUNDDOWN(priIDSector
, hfsmp
->hfs_log_per_phys
),
948 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
949 if (psVolHdrBuf
== NULL
) {
953 pvVolHdrData
= psVolHdrBuf
->pvData
;
955 retval
= lf_hfs_generic_buf_read(psVolHdrBuf
);
957 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
961 HFSPlusVolumeHeader
* volumeHeader
= (HFSPlusVolumeHeader
*)(pvVolHdrData
+ HFS_PRI_OFFSET(hfsmp
->hfs_physical_block_size
));
964 * Sanity check what we just read. If it's bad, try the alternate instead.
966 u_int16_t signature
= SWAP_BE16 (volumeHeader
->signature
);
967 u_int16_t hfsversion
= SWAP_BE16 (volumeHeader
->version
);
969 if ((signature
!= kHFSPlusSigWord
&& signature
!= kHFSXSigWord
) ||
970 (hfsversion
< kHFSPlusVersion
) || (hfsversion
> 100) ||
971 (SWAP_BE32 (volumeHeader
->blockSize
) != vcb
->blockSize
))
973 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_flushvolumeheader: corrupt VH on %s, sig 0x%04x, ver %d, blksize %d\n", vcb
->vcbVN
, signature
, hfsversion
, SWAP_BE32 (volumeHeader
->blockSize
));
974 hfs_mark_inconsistent(hfsmp
, HFS_INCONSISTENCY_DETECTED
);
976 /* Almost always we read AVH relative to the partition size */
977 avh_sector
= hfsmp
->hfs_partition_avh_sector
;
979 if (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
)
982 * The two altVH offsets do not match --- which means that a smaller file
983 * system exists in a larger partition. Verify that we have the correct
984 * alternate volume header sector as per the current parititon size.
985 * The GPT device that we are mounted on top could have changed sizes
986 * without us knowing.
988 * We're in a transaction, so it's safe to modify the partition_avh_sector
989 * field if necessary.
992 uint64_t sector_count
= 0;
994 /* Get underlying device block count */
995 retval
= ioctl(hfsmp
->hfs_devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKCOUNT
, §or_count
);
998 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval
, vcb
->vcbVN
);
1003 /* Partition size was changed without our knowledge */
1004 if (sector_count
!= (uint64_t)hfsmp
->hfs_logical_block_count
)
1006 hfsmp
->hfs_partition_avh_sector
= (hfsmp
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_ALT_SECTOR(hfsmp
->hfs_logical_block_size
, sector_count
);
1007 /* Note: hfs_fs_avh_sector will remain unchanged */
1008 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_flushvolumeheader: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n", hfsmp
->hfs_partition_avh_sector
, hfsmp
->hfs_fs_avh_sector
);
1011 * We just updated the offset for AVH relative to
1012 * the partition size, so the content of that AVH
1013 * will be invalid. But since we are also maintaining
1014 * a valid AVH relative to the file system size, we
1015 * can read it since primary VH and partition AVH
1018 avh_sector
= hfsmp
->hfs_fs_avh_sector
;
1022 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_flushvolumeheader: trying alternate (for %s) avh_sector=%qu\n", (avh_sector
== hfsmp
->hfs_fs_avh_sector
) ? "file system" : "partition", avh_sector
);
1026 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1027 HFS_PHYSBLK_ROUNDDOWN(avh_sector
, hfsmp
->hfs_log_per_phys
),
1028 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1029 if (psAltHdrBuf
== NULL
) {
1033 pvAltHdrData
= psAltHdrBuf
->pvData
;
1035 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1039 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1043 HFSPlusVolumeHeader
* altVH
= (HFSPlusVolumeHeader
*)(pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
));
1044 signature
= SWAP_BE16(altVH
->signature
);
1045 hfsversion
= SWAP_BE16(altVH
->version
);
1047 if ((signature
!= kHFSPlusSigWord
&& signature
!= kHFSXSigWord
) ||
1048 (hfsversion
< kHFSPlusVersion
) || (kHFSPlusVersion
> 100) ||
1049 (SWAP_BE32(altVH
->blockSize
) != vcb
->blockSize
))
1051 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: corrupt alternate VH on %s, sig 0x%04x, ver %d, blksize %d\n", vcb
->vcbVN
, signature
, hfsversion
, SWAP_BE32(altVH
->blockSize
));
1056 /* The alternate is plausible, so use it. */
1057 bcopy(altVH
, volumeHeader
, kMDBSize
);
1058 lf_hfs_generic_buf_release(psAltHdrBuf
);
1059 pvAltHdrData
= NULL
;
1063 /* No alternate VH, nothing more we can do. */
1071 journal_modify_block_start(hfsmp
->jnl
, psVolHdrBuf
);
1075 * For embedded HFS+ volumes, update create date if it changed
1076 * (ie from a setattrlist call)
1078 if ((vcb
->hfsPlusIOPosOffset
!= 0) && (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
))
1080 HFSMasterDirectoryBlock
*mdb
;
1082 psVolHdr2Buf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1083 HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp
->hfs_logical_block_size
), hfsmp
->hfs_log_per_phys
),
1084 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1085 if (psVolHdr2Buf
== NULL
) {
1089 void *pvVolHdr2Data
= psVolHdr2Buf
->pvData
;
1091 retval
= lf_hfs_generic_buf_read(psVolHdr2Buf
);
1095 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1096 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1100 mdb
= (HFSMasterDirectoryBlock
*)(pvVolHdr2Data
+ HFS_PRI_OFFSET(hfsmp
->hfs_physical_block_size
));
1102 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1106 journal_modify_block_start(hfsmp
->jnl
, psVolHdr2Buf
);
1108 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1111 journal_modify_block_end(hfsmp
->jnl
, psVolHdr2Buf
, NULL
, NULL
);
1115 retval
= raw_readwrite_write_mount( hfsmp
->hfs_devvp
, HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp
->hfs_logical_block_size
), hfsmp
->hfs_log_per_phys
), hfsmp
->hfs_physical_block_size
, pvVolHdr2Data
, hfsmp
->hfs_physical_block_size
, NULL
, NULL
);
1117 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1118 pvVolHdr2Data
= NULL
;
1121 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1128 lf_hfs_generic_buf_release(psVolHdr2Buf
); /* just release it */
1129 pvVolHdr2Data
= NULL
;
1133 hfs_lock_mount (hfsmp
);
1135 /* Note: only update the lower 16 bits worth of attributes */
1136 volumeHeader
->attributes
= SWAP_BE32 (vcb
->vcbAtrb
);
1137 volumeHeader
->journalInfoBlock
= SWAP_BE32 (vcb
->vcbJinfoBlock
);
1140 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSJMountVersion
);
1144 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1146 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1147 volumeHeader
->modifyDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbLsMod
));
1148 volumeHeader
->backupDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbVolBkUp
));
1149 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1150 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1151 volumeHeader
->totalBlocks
= SWAP_BE32 (vcb
->totalBlocks
);
1152 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
+ vcb
->reclaimBlocks
);
1153 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1154 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1155 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1156 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1157 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1158 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1160 if (bcmp(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
)) != 0)
1162 bcopy(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
));
1166 if (!altflush
&& !ISSET(options
, HFS_FVH_FLUSH_IF_DIRTY
))
1171 /* Sync Extents over-flow file meta data */
1172 struct filefork
* fp
= VTOF(vcb
->extentsRefNum
);
1173 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1175 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1177 volumeHeader
->extentsFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1178 volumeHeader
->extentsFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1180 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1181 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1182 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1183 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1187 /* Sync Catalog file meta data */
1188 fp
= VTOF(vcb
->catalogRefNum
);
1189 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1191 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1193 volumeHeader
->catalogFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1194 volumeHeader
->catalogFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1196 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1197 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1198 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1199 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1203 /* Sync Allocation file meta data */
1204 fp
= VTOF(vcb
->allocationsRefNum
);
1205 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1207 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1209 volumeHeader
->allocationFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1210 volumeHeader
->allocationFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1212 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1213 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1214 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1215 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1219 /* Sync Attribute file meta data */
1220 if (hfsmp
->hfs_attribute_vp
)
1222 fp
= VTOF(hfsmp
->hfs_attribute_vp
);
1223 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1225 volumeHeader
->attributesFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1226 volumeHeader
->attributesFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1228 if (ISSET(FTOC(fp
)->c_flag
, C_MODIFIED
))
1230 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1233 volumeHeader
->attributesFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1234 volumeHeader
->attributesFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1235 volumeHeader
->attributesFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1238 /* Sync Startup file meta data */
1239 if (hfsmp
->hfs_startup_vp
)
1241 fp
= VTOF(hfsmp
->hfs_startup_vp
);
1242 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1244 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1246 volumeHeader
->startupFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1247 volumeHeader
->startupFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1249 volumeHeader
->startupFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1250 volumeHeader
->startupFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1251 volumeHeader
->startupFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1252 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1261 MarkVCBClean(hfsmp
);
1262 hfs_unlock_mount (hfsmp
);
1264 /* If requested, flush out the alternate volume header */
1267 * The two altVH offsets do not match --- which means that a smaller file
1268 * system exists in a larger partition. Verify that we have the correct
1269 * alternate volume header sector as per the current parititon size.
1270 * The GPT device that we are mounted on top could have changed sizes
1271 * without us knowning.
1273 * We're in a transaction, so it's safe to modify the partition_avh_sector
1274 * field if necessary.
1276 if (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
)
1278 uint64_t sector_count
;
1280 /* Get underlying device block count */
1281 retval
= ioctl(hfsmp
->hfs_devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKCOUNT
, §or_count
);
1284 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval
, vcb
->vcbVN
);
1289 /* Partition size was changed without our knowledge */
1290 if (sector_count
!= (uint64_t)hfsmp
->hfs_logical_block_count
)
1292 hfsmp
->hfs_partition_avh_sector
= (hfsmp
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_ALT_SECTOR(hfsmp
->hfs_logical_block_size
, sector_count
);
1293 /* Note: hfs_fs_avh_sector will remain unchanged */
1294 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_flushvolumeheader: altflush: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
1295 hfsmp
->hfs_partition_avh_sector
, hfsmp
->hfs_fs_avh_sector
);
1300 * First see if we need to write I/O to the "secondary" AVH
1301 * located at FS Size - 1024 bytes, because this one will
1302 * always go into the journal. We put this AVH into the journal
1303 * because even if the filesystem size has shrunk, this LBA should be
1304 * reachable after the partition-size modification has occurred.
1305 * The one where we need to be careful is partitionsize-1024, since the
1306 * partition size should hopefully shrink.
1308 * Most of the time this block will not execute.
1310 if ((hfsmp
->hfs_fs_avh_sector
) && (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
))
1312 if (pvAltHdrData
!= NULL
)
1314 panic("We shouldn't be here!");
1318 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1319 HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
),
1320 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1322 if (psAltHdrBuf
== NULL
) {
1326 pvAltHdrData
= psAltHdrBuf
->pvData
;
1328 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1331 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1337 journal_modify_block_start(hfsmp
->jnl
, psAltHdrBuf
);
1340 bcopy(volumeHeader
, pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
), kMDBSize
);
1344 journal_modify_block_end(hfsmp
->jnl
, psAltHdrBuf
, NULL
, NULL
);
1348 retval
= raw_readwrite_write_mount( hfsmp
->hfs_devvp
, HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
), hfsmp
->hfs_physical_block_size
, pvAltHdrData
, hfsmp
->hfs_physical_block_size
, NULL
, NULL
);
1351 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1354 lf_hfs_generic_buf_release(psAltHdrBuf
);
1355 pvAltHdrData
= NULL
;
1360 * Flush out alternate volume header located at 1024 bytes before
1361 * end of the partition as part of journal transaction. In
1362 * most cases, this will be the only alternate volume header
1363 * that we need to worry about because the file system size is
1364 * same as the partition size, therefore hfs_fs_avh_sector is
1365 * same as hfs_partition_avh_sector. This is the "priority" AVH.
1367 * However, do not always put this I/O into the journal. If we skipped the
1368 * FS-Size AVH write above, then we will put this I/O into the journal as
1369 * that indicates the two were in sync. However, if the FS size is
1370 * not the same as the partition size, we are tracking two. We don't
1371 * put it in the journal in that case, since if the partition
1372 * size changes between uptimes, and we need to replay the journal,
1373 * this I/O could generate an EIO if during replay it is now trying
1374 * to access blocks beyond the device EOF.
1376 if (hfsmp
->hfs_partition_avh_sector
)
1378 if (pvAltHdrData
!= NULL
)
1380 panic("We shouldn't be here!");
1384 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1385 HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
),
1386 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1387 if (psAltHdrBuf
== NULL
) {
1391 pvAltHdrData
= psAltHdrBuf
->pvData
;
1393 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1397 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1401 /* only one AVH, put this I/O in the journal. */
1402 if ((hfsmp
->jnl
) && (hfsmp
->hfs_partition_avh_sector
== hfsmp
->hfs_fs_avh_sector
)) {
1403 journal_modify_block_start(hfsmp
->jnl
, psAltHdrBuf
);
1406 bcopy(volumeHeader
, pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
), kMDBSize
);
1408 /* If journaled and we only have one AVH to track */
1409 if ((hfsmp
->jnl
) && (hfsmp
->hfs_partition_avh_sector
== hfsmp
->hfs_fs_avh_sector
)) {
1410 journal_modify_block_end (hfsmp
->jnl
, psAltHdrBuf
, NULL
, NULL
);
1415 * If we don't have a journal or there are two AVH's at the
1416 * moment, then this one doesn't go in the journal. Note that
1417 * this one may generate I/O errors, since the partition
1418 * can be resized behind our backs at any moment and this I/O
1419 * may now appear to be beyond the device EOF.
1421 retval
= raw_readwrite_write_mount( hfsmp
->hfs_devvp
, HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
), hfsmp
->hfs_physical_block_size
, pvAltHdrData
, hfsmp
->hfs_physical_block_size
, NULL
, NULL
);
1424 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1427 lf_hfs_generic_buf_release(psAltHdrBuf
);
1428 pvAltHdrData
= NULL
;
1429 hfs_flush(hfsmp
, HFS_FLUSH_CACHE
);
1434 /* Finish modifying the block for the primary VH */
1436 journal_modify_block_end(hfsmp
->jnl
, psVolHdrBuf
, NULL
, NULL
);
1440 retval
= raw_readwrite_write_mount( hfsmp
->hfs_devvp
, HFS_PHYSBLK_ROUNDDOWN(priIDSector
, hfsmp
->hfs_log_per_phys
), hfsmp
->hfs_physical_block_size
, pvVolHdrData
, hfsmp
->hfs_physical_block_size
, NULL
, NULL
);
1441 /* When critical data changes, flush the device cache */
1442 if (critical
&& (retval
== 0))
1444 hfs_flush(hfsmp
, HFS_FLUSH_CACHE
);
1447 lf_hfs_generic_buf_release(psVolHdrBuf
);
1448 pvVolHdrData
= NULL
;
1451 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1455 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
1456 hfs_end_transaction(hfsmp
);
1463 lf_hfs_generic_buf_release(psVolHdrBuf
);
1465 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1467 lf_hfs_generic_buf_release(psAltHdrBuf
);
1469 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
1470 hfs_end_transaction(hfsmp
);
1475 /* If a runtime corruption is detected, set the volume inconsistent
1476 * bit in the volume attributes. The volume inconsistent bit is a persistent
1477 * bit which represents that the volume is corrupt and needs repair.
1478 * The volume inconsistent bit can be set from the kernel when it detects
1479 * runtime corruption or from file system repair utilities like fsck_hfs when
1480 * a repair operation fails. The bit should be cleared only from file system
1481 * verify/repair utility like fsck_hfs when a verify/repair succeeds.
1483 void hfs_mark_inconsistent(struct hfsmount
*hfsmp
, hfs_inconsistency_reason_t reason
)
1485 hfs_lock_mount (hfsmp
);
1486 if ((hfsmp
->vcbAtrb
& kHFSVolumeInconsistentMask
) == 0)
1488 hfsmp
->vcbAtrb
|= kHFSVolumeInconsistentMask
;
1489 MarkVCBDirty(hfsmp
);
1491 if ((hfsmp
->hfs_flags
& HFS_READ_ONLY
)==0)
1495 case HFS_INCONSISTENCY_DETECTED
:
1496 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: Runtime corruption detected on %s, fsck will be forced on next mount.\n",hfsmp
->vcbVN
);
1498 case HFS_ROLLBACK_FAILED
:
1499 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: Failed to roll back; volume `%s' might be inconsistent; fsck will be forced on next mount.\n", hfsmp
->vcbVN
);
1501 case HFS_OP_INCOMPLETE
:
1502 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: Failed to complete operation; volume `%s' might be inconsistent; fsck will be forced on next mount.\n",hfsmp
->vcbVN
);
1504 case HFS_FSCK_FORCED
:
1505 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: fsck requested for `%s'; fsck will be forced on next mount.\n",hfsmp
->vcbVN
);
1509 hfs_unlock_mount (hfsmp
);
1513 * Creates a UUID from a unique "name" in the HFS UUID Name space.
1514 * See version 3 UUID.
1517 hfs_getvoluuid(struct hfsmount
*hfsmp
, uuid_t result_uuid
)
1520 if (uuid_is_null(hfsmp
->hfs_full_uuid
)) {
1526 ((uint32_t *)rawUUID
)[0] = hfsmp
->vcbFndrInfo
[6];
1527 ((uint32_t *)rawUUID
)[1] = hfsmp
->vcbFndrInfo
[7];
1529 CC_MD5_Init( &md5c
);
1530 CC_MD5_Update( &md5c
, HFS_UUID_NAMESPACE_ID
, sizeof( uuid_t
) );
1531 CC_MD5_Update( &md5c
, rawUUID
, sizeof (rawUUID
) );
1532 CC_MD5_Final( result
, &md5c
);
1534 result
[6] = 0x30 | ( result
[6] & 0x0F );
1535 result
[8] = 0x80 | ( result
[8] & 0x3F );
1537 uuid_copy(hfsmp
->hfs_full_uuid
, result
);
1539 uuid_copy (result_uuid
, hfsmp
->hfs_full_uuid
);
1544 * Call into the allocator code and perform a full scan of the bitmap file.
1546 * This allows us to TRIM unallocated ranges if needed, and also to build up
1547 * an in-memory summary table of the state of the allocated blocks.
1549 void hfs_scan_blocks (struct hfsmount
*hfsmp
)
1552 * Take the allocation file lock. Journal transactions will block until
1555 int flags
= hfs_systemfile_lock(hfsmp
, SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1558 * We serialize here with the HFS mount lock as we're mounting.
1560 * The mount can only proceed once this thread has acquired the bitmap
1561 * lock, since we absolutely do not want someone else racing in and
1562 * getting the bitmap lock, doing a read/write of the bitmap file,
1563 * then us getting the bitmap lock.
1565 * To prevent this, the mount thread takes the HFS mount mutex, starts us
1566 * up, then immediately msleeps on the scan_var variable in the mount
1567 * point as a condition variable. This serialization is safe since
1568 * if we race in and try to proceed while they're still holding the lock,
1569 * we'll block trying to acquire the global lock. Since the mount thread
1570 * acquires the HFS mutex before starting this function in a new thread,
1571 * any lock acquisition on our part must be linearizably AFTER the mount thread's.
1573 * Note that the HFS mount mutex is always taken last, and always for only
1574 * a short time. In this case, we just take it long enough to mark the
1575 * scan-in-flight bit.
1577 (void) hfs_lock_mount (hfsmp
);
1578 hfsmp
->scan_var
|= HFS_ALLOCATOR_SCAN_INFLIGHT
;
1579 hfs_unlock_mount (hfsmp
);
1581 /* Initialize the summary table */
1582 if (hfs_init_summary (hfsmp
))
1584 LFHFS_LOG(LEVEL_DEBUG
, "hfs_scan_blocks: could not initialize summary table for %s\n", hfsmp
->vcbVN
);
1588 * ScanUnmapBlocks assumes that the bitmap lock is held when you
1589 * call the function. We don't care if there were any errors issuing unmaps.
1591 * It will also attempt to build up the summary table for subsequent
1592 * allocator use, as configured.
1594 (void) ScanUnmapBlocks(hfsmp
);
1596 (void) hfs_lock_mount (hfsmp
);
1597 hfsmp
->scan_var
&= ~HFS_ALLOCATOR_SCAN_INFLIGHT
;
1598 hfsmp
->scan_var
|= HFS_ALLOCATOR_SCAN_COMPLETED
;
1599 hfs_unlock_mount (hfsmp
);
1601 hfs_systemfile_unlock(hfsmp
, flags
);
1605 hfs_GetInfoByID(struct hfsmount
*hfsmp
, cnid_t cnid
, UVFSFileAttributes
*file_attrs
, char pcName
[MAX_UTF8_NAME_LENGTH
])
1607 u_int32_t linkref
= 0;
1608 struct vnode
*psVnode
= NULL
;
1609 struct cat_desc cndesc
;
1610 struct cat_attr cnattr
;
1611 struct cat_fork cnfork
;
1614 /* Check for cnids that should't be exported. */
1615 if ((cnid
< kHFSFirstUserCatalogNodeID
) &&
1616 (cnid
!= kHFSRootFolderID
&& cnid
!= kHFSRootParentID
)) {
1619 /* Don't export our private directories. */
1620 if (cnid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
||
1621 cnid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) {
1625 * Check the hash first
1627 psVnode
= hfs_chash_getvnode(hfsmp
, cnid
, 0, 0, 0);
1629 goto getAttrAndDone
;
1632 bzero(&cndesc
, sizeof(cndesc
));
1633 bzero(&cnattr
, sizeof(cnattr
));
1634 bzero(&cnfork
, sizeof(cnfork
));
1637 * Not in hash, lookup in catalog
1639 if (cnid
== kHFSRootParentID
) {
1640 static char hfs_rootname
[] = "/";
1642 cndesc
.cd_nameptr
= (const u_int8_t
*)&hfs_rootname
[0];
1643 cndesc
.cd_namelen
= 1;
1644 cndesc
.cd_parentcnid
= kHFSRootParentID
;
1645 cndesc
.cd_cnid
= kHFSRootFolderID
;
1646 cndesc
.cd_flags
= CD_ISDIR
;
1648 cnattr
.ca_fileid
= kHFSRootFolderID
;
1649 cnattr
.ca_linkcount
= 1;
1650 cnattr
.ca_entries
= 1;
1651 cnattr
.ca_dircount
= 1;
1652 cnattr
.ca_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1656 const char *nameptr
;
1658 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
1659 error
= cat_idlookup(hfsmp
, cnid
, 0, 0, &cndesc
, &cnattr
, &cnfork
);
1660 hfs_systemfile_unlock(hfsmp
, lockflags
);
1667 * Check for a raw hardlink inode and save its linkref.
1669 pid
= cndesc
.cd_parentcnid
;
1670 nameptr
= (const char *)cndesc
.cd_nameptr
;
1671 if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1672 cndesc
.cd_namelen
> HFS_INODE_PREFIX_LEN
&&
1673 (bcmp(nameptr
, HFS_INODE_PREFIX
, HFS_INODE_PREFIX_LEN
) == 0)) {
1674 linkref
= (uint32_t) strtoul(&nameptr
[HFS_INODE_PREFIX_LEN
], NULL
, 10);
1676 } else if ((pid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) &&
1677 cndesc
.cd_namelen
> HFS_DIRINODE_PREFIX_LEN
&&
1678 (bcmp(nameptr
, HFS_DIRINODE_PREFIX
, HFS_DIRINODE_PREFIX_LEN
) == 0)) {
1679 linkref
= (uint32_t) strtoul(&nameptr
[HFS_DIRINODE_PREFIX_LEN
], NULL
, 10);
1681 } else if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1682 cndesc
.cd_namelen
> HFS_DELETE_PREFIX_LEN
&&
1683 (bcmp(nameptr
, HFS_DELETE_PREFIX
, HFS_DELETE_PREFIX_LEN
) == 0)) {
1684 cat_releasedesc(&cndesc
);
1685 return (ENOENT
); /* open unlinked file */
1690 * Finish initializing cnode descriptor for hardlinks.
1692 * We need a valid name and parent for reverse lookups.
1696 struct cat_desc linkdesc
;
1699 cnattr
.ca_linkref
= linkref
;
1700 bzero (&linkdesc
, sizeof (linkdesc
));
1703 * If the caller supplied the raw inode value, then we don't know exactly
1704 * which hardlink they wanted. It's likely that they acquired the raw inode
1705 * value BEFORE the item became a hardlink, in which case, they probably
1706 * want the oldest link. So request the oldest link from the catalog.
1708 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1709 * side, since we know that we want the last linkID, we can also have this one
1710 * call give us back the name of the last ID, since it's going to have it in-hand...
1712 linkerr
= hfs_lookup_lastlink (hfsmp
, linkref
, &lastid
, &linkdesc
);
1713 if ((linkerr
== 0) && (lastid
!= 0)) {
1715 * Release any lingering buffers attached to our local descriptor.
1716 * Then copy the name and other business into the cndesc
1718 cat_releasedesc (&cndesc
);
1719 bcopy (&linkdesc
, &cndesc
, sizeof(linkdesc
));
1721 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1723 int newvnode_flags
= 0;
1724 error
= hfs_getnewvnode(hfsmp
, NULL
, NULL
, &cndesc
, 0, &cnattr
, &cnfork
, &psVnode
, &newvnode_flags
);
1726 VTOC(psVnode
)->c_flag
|= C_HARDLINK
;
1731 int newvnode_flags
= 0;
1733 void *buf
= hfs_malloc(MAX_UTF8_NAME_LENGTH
);
1738 /* Supply hfs_getnewvnode with a component name. */
1739 struct componentname cn
= {
1740 .cn_nameiop
= LOOKUP
,
1741 .cn_flags
= ISLASTCN
,
1742 .cn_pnlen
= MAXPATHLEN
,
1743 .cn_namelen
= cndesc
.cd_namelen
,
1748 bcopy(cndesc
.cd_nameptr
, cn
.cn_nameptr
, cndesc
.cd_namelen
+ 1);
1749 error
= hfs_getnewvnode(hfsmp
, NULL
, &cn
, &cndesc
, 0, &cnattr
, &cnfork
, &psVnode
, &newvnode_flags
);
1750 if (error
== 0 && (VTOC(psVnode
)->c_flag
& C_HARDLINK
)) {
1751 hfs_savelinkorigin(VTOC(psVnode
), cndesc
.cd_parentcnid
);
1756 cat_releasedesc(&cndesc
);
1759 if (!error
) vnode_GetAttrInternal (psVnode
, file_attrs
);
1760 if (psVnode
!= NULL
) hfs_unlock(VTOC(psVnode
));
1762 if (error
|| psVnode
== NULL
|| psVnode
->sFSParams
.vnfs_cnp
->cn_nameptr
== NULL
){
1763 hfs_vnop_reclaim(psVnode
);
1767 if (cnid
== kHFSRootFolderID
)
1770 strlcpy(pcName
, (char*) psVnode
->sFSParams
.vnfs_cnp
->cn_nameptr
, MAX_UTF8_NAME_LENGTH
);
1773 error
= hfs_vnop_reclaim(psVnode
);
1779 * Look up an HFS object by ID.
1781 * The object is returned with an iocount reference and the cnode locked.
1783 * If the object is a file then it will represent the data fork.
1786 hfs_vget(struct hfsmount
*hfsmp
, cnid_t cnid
, struct vnode
**vpp
, int skiplock
, int allow_deleted
)
1788 struct vnode
*vp
= NULL
;
1789 struct cat_desc cndesc
;
1790 struct cat_attr cnattr
;
1791 struct cat_fork cnfork
;
1793 u_int32_t linkref
= 0;
1797 /* Check for cnids that should't be exported. */
1798 if ((cnid
< kHFSFirstUserCatalogNodeID
) &&
1799 (cnid
!= kHFSRootFolderID
&& cnid
!= kHFSRootParentID
)) {
1802 /* Don't export our private directories. */
1803 if (cnid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
||
1804 cnid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) {
1808 * Check the hash first
1810 vp
= hfs_chash_getvnode(hfsmp
, cnid
, 0, skiplock
, allow_deleted
);
1816 bzero(&cndesc
, sizeof(cndesc
));
1817 bzero(&cnattr
, sizeof(cnattr
));
1818 bzero(&cnfork
, sizeof(cnfork
));
1821 * Not in hash, lookup in catalog
1823 if (cnid
== kHFSRootParentID
) {
1824 static char hfs_rootname
[] = "/";
1826 cndesc
.cd_nameptr
= (const u_int8_t
*)&hfs_rootname
[0];
1827 cndesc
.cd_namelen
= 1;
1828 cndesc
.cd_parentcnid
= kHFSRootParentID
;
1829 cndesc
.cd_cnid
= kHFSRootFolderID
;
1830 cndesc
.cd_flags
= CD_ISDIR
;
1832 cnattr
.ca_fileid
= kHFSRootFolderID
;
1833 cnattr
.ca_linkcount
= 1;
1834 cnattr
.ca_entries
= 1;
1835 cnattr
.ca_dircount
= 1;
1836 cnattr
.ca_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1840 const char *nameptr
;
1842 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
1843 error
= cat_idlookup(hfsmp
, cnid
, 0, 0, &cndesc
, &cnattr
, &cnfork
);
1844 hfs_systemfile_unlock(hfsmp
, lockflags
);
1852 * Check for a raw hardlink inode and save its linkref.
1854 pid
= cndesc
.cd_parentcnid
;
1855 nameptr
= (const char *)cndesc
.cd_nameptr
;
1856 if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1857 cndesc
.cd_namelen
> HFS_INODE_PREFIX_LEN
&&
1858 (bcmp(nameptr
, HFS_INODE_PREFIX
, HFS_INODE_PREFIX_LEN
) == 0)) {
1859 linkref
= (uint32_t) strtoul(&nameptr
[HFS_INODE_PREFIX_LEN
], NULL
, 10);
1861 } else if ((pid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) &&
1862 cndesc
.cd_namelen
> HFS_DIRINODE_PREFIX_LEN
&&
1863 (bcmp(nameptr
, HFS_DIRINODE_PREFIX
, HFS_DIRINODE_PREFIX_LEN
) == 0)) {
1864 linkref
= (uint32_t) strtoul(&nameptr
[HFS_DIRINODE_PREFIX_LEN
], NULL
, 10);
1866 } else if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1867 cndesc
.cd_namelen
> HFS_DELETE_PREFIX_LEN
&&
1868 (bcmp(nameptr
, HFS_DELETE_PREFIX
, HFS_DELETE_PREFIX_LEN
) == 0)) {
1870 cat_releasedesc(&cndesc
);
1871 return (ENOENT
); /* open unlinked file */
1876 * Finish initializing cnode descriptor for hardlinks.
1878 * We need a valid name and parent for reverse lookups.
1882 struct cat_desc linkdesc
;
1885 cnattr
.ca_linkref
= linkref
;
1886 bzero (&linkdesc
, sizeof (linkdesc
));
1889 * If the caller supplied the raw inode value, then we don't know exactly
1890 * which hardlink they wanted. It's likely that they acquired the raw inode
1891 * value BEFORE the item became a hardlink, in which case, they probably
1892 * want the oldest link. So request the oldest link from the catalog.
1894 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1895 * side, since we know that we want the last linkID, we can also have this one
1896 * call give us back the name of the last ID, since it's going to have it in-hand...
1898 linkerr
= hfs_lookup_lastlink (hfsmp
, linkref
, &lastid
, &linkdesc
);
1899 if ((linkerr
== 0) && (lastid
!= 0)) {
1901 * Release any lingering buffers attached to our local descriptor.
1902 * Then copy the name and other business into the cndesc
1904 cat_releasedesc (&cndesc
);
1905 bcopy (&linkdesc
, &cndesc
, sizeof(linkdesc
));
1907 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1911 int newvnode_flags
= 0;
1912 error
= hfs_getnewvnode(hfsmp
, NULL
, NULL
, &cndesc
, 0, &cnattr
, &cnfork
, &vp
, &newvnode_flags
);
1914 VTOC(vp
)->c_flag
|= C_HARDLINK
;
1916 //TBD - this set is for vfs -> since we have the C_HARDLINK
1917 // currently disable this set.
1918 //vnode_setmultipath(vp);
1923 int newvnode_flags
= 0;
1925 void *buf
= hfs_malloc(MAXPATHLEN
);
1927 /* Supply hfs_getnewvnode with a component name. */
1928 struct componentname cn
= {
1929 .cn_nameiop
= LOOKUP
,
1930 .cn_flags
= ISLASTCN
,
1931 .cn_pnlen
= MAXPATHLEN
,
1932 .cn_namelen
= cndesc
.cd_namelen
,
1937 bcopy(cndesc
.cd_nameptr
, cn
.cn_nameptr
, cndesc
.cd_namelen
+ 1);
1938 error
= hfs_getnewvnode(hfsmp
, NULL
, &cn
, &cndesc
, 0, &cnattr
, &cnfork
, &vp
, &newvnode_flags
);
1940 if (error
== 0 && (VTOC(vp
)->c_flag
& C_HARDLINK
)) {
1941 hfs_savelinkorigin(VTOC(vp
), cndesc
.cd_parentcnid
);
1946 cat_releasedesc(&cndesc
);
1949 if (vp
&& skiplock
) {
1950 hfs_unlock(VTOC(vp
));
1956 * Return the root of a filesystem.
1958 int hfs_vfs_root(struct mount
*mp
, struct vnode
**vpp
)
1960 return hfs_vget(VFSTOHFS(mp
), (cnid_t
)kHFSRootFolderID
, vpp
, 1, 0);
1964 * unmount system call
1966 int hfs_unmount(struct mount
*mp
)
1968 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1969 int retval
= E_NONE
;
1971 if (hfsmp
->hfs_flags
& HFS_SUMMARY_TABLE
)
1973 if (hfsmp
->hfs_summary_table
)
1977 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
1979 if (hfsmp
->hfs_allocation_vp
)
1981 err
= hfs_lock (VTOC(hfsmp
->hfs_allocation_vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1983 hfs_free(hfsmp
->hfs_summary_table
);
1984 hfsmp
->hfs_summary_table
= NULL
;
1985 hfsmp
->hfs_flags
&= ~HFS_SUMMARY_TABLE
;
1987 if (err
== 0 && hfsmp
->hfs_allocation_vp
)
1989 hfs_unlock (VTOC(hfsmp
->hfs_allocation_vp
));
1995 * Invalidate our caches and release metadata vnodes
1998 journal_release(hfsmp
->jnl
);
2003 int iFD
= hfsmp
->hfs_devvp
->psFSRecord
->iFD
;
2004 // Remove Buffer cache entries realted to the mount
2005 lf_hfs_generic_buf_cache_clear_by_iFD(iFD
);
2007 vnode_rele(hfsmp
->hfs_devvp
);
2009 hfs_locks_destroy(hfsmp
);
2010 hfs_delete_chash(hfsmp
);
2011 hfs_idhash_destroy(hfsmp
);
2013 hfs_assert(TAILQ_EMPTY(&hfsmp
->hfs_reserved_ranges
[HFS_TENTATIVE_BLOCKS
]) && TAILQ_EMPTY(&hfsmp
->hfs_reserved_ranges
[HFS_LOCKED_BLOCKS
]));
2014 hfs_assert(!hfsmp
->lockedBlocks
);
2020 /* Update volume encoding bitmap (HFS Plus only)
2022 * Mark a legacy text encoding as in-use (as needed)
2023 * in the volume header of this HFS+ filesystem.
2026 hfs_setencodingbits(struct hfsmount
*hfsmp
, u_int32_t encoding
)
2028 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2029 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2035 case kTextEncodingMacUkrainian
:
2036 index
= kIndexMacUkrainian
;
2038 case kTextEncodingMacFarsi
:
2039 index
= kIndexMacFarsi
;
2046 /* Only mark the encoding as in-use if it wasn't already set */
2047 if (index
< 64 && (hfsmp
->encodingsBitmap
& (u_int64_t
)(1ULL << index
)) == 0) {
2048 hfs_lock_mount (hfsmp
);
2049 hfsmp
->encodingsBitmap
|= (u_int64_t
)(1ULL << index
);
2050 MarkVCBDirty(hfsmp
);
2051 hfs_unlock_mount(hfsmp
);
2056 * Update volume stats
2058 * On journal volumes this will cause a volume header flush
2061 hfs_volupdate(struct hfsmount
*hfsmp
, enum volop op
, int inroot
)
2065 hfs_lock_mount (hfsmp
);
2067 MarkVCBDirty(hfsmp
);
2068 hfsmp
->hfs_mtime
= tv
.tv_sec
;
2074 if (hfsmp
->hfs_dircount
!= 0xFFFFFFFF)
2075 ++hfsmp
->hfs_dircount
;
2076 if (inroot
&& hfsmp
->vcbNmRtDirs
!= 0xFFFF)
2077 ++hfsmp
->vcbNmRtDirs
;
2080 if (hfsmp
->hfs_dircount
!= 0)
2081 --hfsmp
->hfs_dircount
;
2082 if (inroot
&& hfsmp
->vcbNmRtDirs
!= 0xFFFF)
2083 --hfsmp
->vcbNmRtDirs
;
2086 if (hfsmp
->hfs_filecount
!= 0xFFFFFFFF)
2087 ++hfsmp
->hfs_filecount
;
2088 if (inroot
&& hfsmp
->vcbNmFls
!= 0xFFFF)
2092 if (hfsmp
->hfs_filecount
!= 0)
2093 --hfsmp
->hfs_filecount
;
2094 if (inroot
&& hfsmp
->vcbNmFls
!= 0xFFFF)
2099 hfs_unlock_mount (hfsmp
);
2100 hfs_flushvolumeheader(hfsmp
, 0);