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
);
844 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: hfs_CollectBtreeStats encountered failure %d \n", retval
);
848 // save off a snapshot of the mtime from the previous mount
850 hfsmp
->hfs_last_mounted_mtime
= hfsmp
->hfs_mtime
;
854 LFHFS_LOG(LEVEL_DEBUG
, "hfs_mountfs: encountered failure %d \n", retval
);
858 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_mountfs: mounted %s on device %s\n", (hfsmp
->vcbVN
[0] ? (const char*) hfsmp
->vcbVN
: "unknown"), "unknown device");
860 hfs_flushvolumeheader(hfsmp
, 0);
871 hfs_locks_destroy(hfsmp
);
872 hfs_delete_chash(hfsmp
);
873 hfs_idhash_destroy (hfsmp
);
882 * Destroy all locks, mutexes and spinlocks in hfsmp on unmount or failed mount
885 hfs_locks_destroy(struct hfsmount
*hfsmp
)
888 lf_lck_mtx_destroy(&hfsmp
->hfs_mutex
);
889 lf_lck_mtx_destroy(&hfsmp
->sync_mutex
);
890 lf_lck_rw_destroy(&hfsmp
->hfs_global_lock
);
891 lf_lck_spin_destroy(&hfsmp
->vcbFreeExtLock
);
898 * Flush any dirty in-memory mount data to the on-disk
901 * Note: the on-disk volume signature is intentionally
902 * not flushed since the on-disk "H+" and "HX" signatures
903 * are always stored in-memory as "H+".
906 hfs_flushvolumeheader(struct hfsmount
*hfsmp
, hfs_flush_volume_header_options_t options
)
910 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
911 bool critical
= false;
912 daddr64_t avh_sector
;
913 bool altflush
= ISSET(options
, HFS_FVH_WRITE_ALT
);
915 void *pvVolHdrData
= NULL
;
916 GenericLFBuf
*psVolHdrBuf
= NULL
;
917 void *pvVolHdr2Data
= NULL
;
918 GenericLFBuf
*psVolHdr2Buf
= NULL
;
919 void *pvAltHdrData
= NULL
;
920 GenericLFBuf
*psAltHdrBuf
= NULL
;
923 if (ISSET(options
, HFS_FVH_FLUSH_IF_DIRTY
) && !hfs_header_needs_flushing(hfsmp
)) {
927 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
) {
931 if (options
& HFS_FVH_MARK_UNMOUNT
) {
932 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
934 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
937 daddr64_t priIDSector
= (daddr64_t
)((vcb
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_PRI_SECTOR(hfsmp
->hfs_logical_block_size
));
939 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
940 if (hfs_start_transaction(hfsmp
) != 0) {
945 psVolHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
946 HFS_PHYSBLK_ROUNDDOWN(priIDSector
, hfsmp
->hfs_log_per_phys
),
947 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
948 if (psVolHdrBuf
== NULL
) {
952 pvVolHdrData
= psVolHdrBuf
->pvData
;
954 retval
= lf_hfs_generic_buf_read(psVolHdrBuf
);
956 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
960 HFSPlusVolumeHeader
* volumeHeader
= (HFSPlusVolumeHeader
*)(pvVolHdrData
+ HFS_PRI_OFFSET(hfsmp
->hfs_physical_block_size
));
963 * Sanity check what we just read. If it's bad, try the alternate instead.
965 u_int16_t signature
= SWAP_BE16 (volumeHeader
->signature
);
966 u_int16_t hfsversion
= SWAP_BE16 (volumeHeader
->version
);
968 if ((signature
!= kHFSPlusSigWord
&& signature
!= kHFSXSigWord
) ||
969 (hfsversion
< kHFSPlusVersion
) || (hfsversion
> 100) ||
970 (SWAP_BE32 (volumeHeader
->blockSize
) != vcb
->blockSize
))
972 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
));
973 hfs_mark_inconsistent(hfsmp
, HFS_INCONSISTENCY_DETECTED
);
975 /* Almost always we read AVH relative to the partition size */
976 avh_sector
= hfsmp
->hfs_partition_avh_sector
;
978 if (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
)
981 * The two altVH offsets do not match --- which means that a smaller file
982 * system exists in a larger partition. Verify that we have the correct
983 * alternate volume header sector as per the current parititon size.
984 * The GPT device that we are mounted on top could have changed sizes
985 * without us knowing.
987 * We're in a transaction, so it's safe to modify the partition_avh_sector
988 * field if necessary.
991 uint64_t sector_count
= 0;
993 /* Get underlying device block count */
994 retval
= ioctl(hfsmp
->hfs_devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKCOUNT
, §or_count
);
997 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval
, vcb
->vcbVN
);
1002 /* Partition size was changed without our knowledge */
1003 if (sector_count
!= (uint64_t)hfsmp
->hfs_logical_block_count
)
1005 hfsmp
->hfs_partition_avh_sector
= (hfsmp
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_ALT_SECTOR(hfsmp
->hfs_logical_block_size
, sector_count
);
1006 /* Note: hfs_fs_avh_sector will remain unchanged */
1007 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
);
1010 * We just updated the offset for AVH relative to
1011 * the partition size, so the content of that AVH
1012 * will be invalid. But since we are also maintaining
1013 * a valid AVH relative to the file system size, we
1014 * can read it since primary VH and partition AVH
1017 avh_sector
= hfsmp
->hfs_fs_avh_sector
;
1021 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
);
1025 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1026 HFS_PHYSBLK_ROUNDDOWN(avh_sector
, hfsmp
->hfs_log_per_phys
),
1027 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1028 if (psAltHdrBuf
== NULL
) {
1032 pvAltHdrData
= psAltHdrBuf
->pvData
;
1034 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1038 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1042 HFSPlusVolumeHeader
* altVH
= (HFSPlusVolumeHeader
*)(pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
));
1043 signature
= SWAP_BE16(altVH
->signature
);
1044 hfsversion
= SWAP_BE16(altVH
->version
);
1046 if ((signature
!= kHFSPlusSigWord
&& signature
!= kHFSXSigWord
) ||
1047 (hfsversion
< kHFSPlusVersion
) || (kHFSPlusVersion
> 100) ||
1048 (SWAP_BE32(altVH
->blockSize
) != vcb
->blockSize
))
1050 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
));
1055 /* The alternate is plausible, so use it. */
1056 bcopy(altVH
, volumeHeader
, kMDBSize
);
1057 lf_hfs_generic_buf_release(psAltHdrBuf
);
1058 pvAltHdrData
= NULL
;
1062 /* No alternate VH, nothing more we can do. */
1070 journal_modify_block_start(hfsmp
->jnl
, psVolHdrBuf
);
1074 * For embedded HFS+ volumes, update create date if it changed
1075 * (ie from a setattrlist call)
1077 if ((vcb
->hfsPlusIOPosOffset
!= 0) && (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
))
1079 HFSMasterDirectoryBlock
*mdb
;
1081 psVolHdr2Buf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1082 HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp
->hfs_logical_block_size
), hfsmp
->hfs_log_per_phys
),
1083 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1084 if (psVolHdr2Buf
== NULL
) {
1088 void *pvVolHdr2Data
= psVolHdr2Buf
->pvData
;
1090 retval
= lf_hfs_generic_buf_read(psVolHdr2Buf
);
1094 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1095 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1099 mdb
= (HFSMasterDirectoryBlock
*)(pvVolHdr2Data
+ HFS_PRI_OFFSET(hfsmp
->hfs_physical_block_size
));
1101 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1105 journal_modify_block_start(hfsmp
->jnl
, psVolHdr2Buf
);
1107 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1110 journal_modify_block_end(hfsmp
->jnl
, psVolHdr2Buf
, NULL
, NULL
);
1114 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
);
1116 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1117 pvVolHdr2Data
= NULL
;
1120 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1127 lf_hfs_generic_buf_release(psVolHdr2Buf
); /* just release it */
1128 pvVolHdr2Data
= NULL
;
1132 hfs_lock_mount (hfsmp
);
1134 /* Note: only update the lower 16 bits worth of attributes */
1135 volumeHeader
->attributes
= SWAP_BE32 (vcb
->vcbAtrb
);
1136 volumeHeader
->journalInfoBlock
= SWAP_BE32 (vcb
->vcbJinfoBlock
);
1139 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSJMountVersion
);
1143 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1145 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1146 volumeHeader
->modifyDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbLsMod
));
1147 volumeHeader
->backupDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbVolBkUp
));
1148 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1149 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1150 volumeHeader
->totalBlocks
= SWAP_BE32 (vcb
->totalBlocks
);
1151 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
+ vcb
->reclaimBlocks
);
1152 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1153 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1154 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1155 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1156 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1157 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1159 if (bcmp(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
)) != 0)
1161 bcopy(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
));
1165 if (!altflush
&& !ISSET(options
, HFS_FVH_FLUSH_IF_DIRTY
))
1170 /* Sync Extents over-flow file meta data */
1171 struct filefork
* fp
= VTOF(vcb
->extentsRefNum
);
1172 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1174 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1176 volumeHeader
->extentsFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1177 volumeHeader
->extentsFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1179 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1180 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1181 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1182 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1186 /* Sync Catalog file meta data */
1187 fp
= VTOF(vcb
->catalogRefNum
);
1188 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1190 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1192 volumeHeader
->catalogFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1193 volumeHeader
->catalogFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1195 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1196 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1197 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1198 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1202 /* Sync Allocation file meta data */
1203 fp
= VTOF(vcb
->allocationsRefNum
);
1204 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1206 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1208 volumeHeader
->allocationFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1209 volumeHeader
->allocationFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1211 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1212 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1213 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1214 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1218 /* Sync Attribute file meta data */
1219 if (hfsmp
->hfs_attribute_vp
)
1221 fp
= VTOF(hfsmp
->hfs_attribute_vp
);
1222 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1224 volumeHeader
->attributesFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1225 volumeHeader
->attributesFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1227 if (ISSET(FTOC(fp
)->c_flag
, C_MODIFIED
))
1229 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1232 volumeHeader
->attributesFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1233 volumeHeader
->attributesFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1234 volumeHeader
->attributesFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1237 /* Sync Startup file meta data */
1238 if (hfsmp
->hfs_startup_vp
)
1240 fp
= VTOF(hfsmp
->hfs_startup_vp
);
1241 if (FTOC(fp
)->c_flag
& C_MODIFIED
)
1243 for (int iExtentCounter
= 0; iExtentCounter
< kHFSPlusExtentDensity
; iExtentCounter
++)
1245 volumeHeader
->startupFile
.extents
[iExtentCounter
].startBlock
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].startBlock
);
1246 volumeHeader
->startupFile
.extents
[iExtentCounter
].blockCount
= SWAP_BE32 (fp
->ff_extents
[iExtentCounter
].blockCount
);
1248 volumeHeader
->startupFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1249 volumeHeader
->startupFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1250 volumeHeader
->startupFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1251 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1260 MarkVCBClean(hfsmp
);
1261 hfs_unlock_mount (hfsmp
);
1263 /* If requested, flush out the alternate volume header */
1266 * The two altVH offsets do not match --- which means that a smaller file
1267 * system exists in a larger partition. Verify that we have the correct
1268 * alternate volume header sector as per the current parititon size.
1269 * The GPT device that we are mounted on top could have changed sizes
1270 * without us knowning.
1272 * We're in a transaction, so it's safe to modify the partition_avh_sector
1273 * field if necessary.
1275 if (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
)
1277 uint64_t sector_count
;
1279 /* Get underlying device block count */
1280 retval
= ioctl(hfsmp
->hfs_devvp
->psFSRecord
->iFD
, DKIOCGETBLOCKCOUNT
, §or_count
);
1283 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval
, vcb
->vcbVN
);
1288 /* Partition size was changed without our knowledge */
1289 if (sector_count
!= (uint64_t)hfsmp
->hfs_logical_block_count
)
1291 hfsmp
->hfs_partition_avh_sector
= (hfsmp
->hfsPlusIOPosOffset
/ hfsmp
->hfs_logical_block_size
) + HFS_ALT_SECTOR(hfsmp
->hfs_logical_block_size
, sector_count
);
1292 /* Note: hfs_fs_avh_sector will remain unchanged */
1293 LFHFS_LOG(LEVEL_DEFAULT
, "hfs_flushvolumeheader: altflush: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
1294 hfsmp
->hfs_partition_avh_sector
, hfsmp
->hfs_fs_avh_sector
);
1299 * First see if we need to write I/O to the "secondary" AVH
1300 * located at FS Size - 1024 bytes, because this one will
1301 * always go into the journal. We put this AVH into the journal
1302 * because even if the filesystem size has shrunk, this LBA should be
1303 * reachable after the partition-size modification has occurred.
1304 * The one where we need to be careful is partitionsize-1024, since the
1305 * partition size should hopefully shrink.
1307 * Most of the time this block will not execute.
1309 if ((hfsmp
->hfs_fs_avh_sector
) && (hfsmp
->hfs_partition_avh_sector
!= hfsmp
->hfs_fs_avh_sector
))
1311 if (pvAltHdrData
!= NULL
)
1313 panic("We shouldn't be here!");
1317 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1318 HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
),
1319 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1321 if (psAltHdrBuf
== NULL
) {
1325 pvAltHdrData
= psAltHdrBuf
->pvData
;
1327 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1330 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1336 journal_modify_block_start(hfsmp
->jnl
, psAltHdrBuf
);
1339 bcopy(volumeHeader
, pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
), kMDBSize
);
1343 journal_modify_block_end(hfsmp
->jnl
, psAltHdrBuf
, NULL
, NULL
);
1347 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
);
1350 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1353 lf_hfs_generic_buf_release(psAltHdrBuf
);
1354 pvAltHdrData
= NULL
;
1359 * Flush out alternate volume header located at 1024 bytes before
1360 * end of the partition as part of journal transaction. In
1361 * most cases, this will be the only alternate volume header
1362 * that we need to worry about because the file system size is
1363 * same as the partition size, therefore hfs_fs_avh_sector is
1364 * same as hfs_partition_avh_sector. This is the "priority" AVH.
1366 * However, do not always put this I/O into the journal. If we skipped the
1367 * FS-Size AVH write above, then we will put this I/O into the journal as
1368 * that indicates the two were in sync. However, if the FS size is
1369 * not the same as the partition size, we are tracking two. We don't
1370 * put it in the journal in that case, since if the partition
1371 * size changes between uptimes, and we need to replay the journal,
1372 * this I/O could generate an EIO if during replay it is now trying
1373 * to access blocks beyond the device EOF.
1375 if (hfsmp
->hfs_partition_avh_sector
)
1377 if (pvAltHdrData
!= NULL
)
1379 panic("We shouldn't be here!");
1383 psAltHdrBuf
= lf_hfs_generic_buf_allocate(hfsmp
->hfs_devvp
,
1384 HFS_PHYSBLK_ROUNDDOWN(hfsmp
->hfs_fs_avh_sector
, hfsmp
->hfs_log_per_phys
),
1385 hfsmp
->hfs_physical_block_size
, GEN_BUF_PHY_BLOCK
);
1386 if (psAltHdrBuf
== NULL
) {
1390 pvAltHdrData
= psAltHdrBuf
->pvData
;
1392 retval
= lf_hfs_generic_buf_read(psAltHdrBuf
);
1396 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1400 /* only one AVH, put this I/O in the journal. */
1401 if ((hfsmp
->jnl
) && (hfsmp
->hfs_partition_avh_sector
== hfsmp
->hfs_fs_avh_sector
)) {
1402 journal_modify_block_start(hfsmp
->jnl
, psAltHdrBuf
);
1405 bcopy(volumeHeader
, pvAltHdrData
+ HFS_ALT_OFFSET(hfsmp
->hfs_physical_block_size
), kMDBSize
);
1407 /* If journaled and we only have one AVH to track */
1408 if ((hfsmp
->jnl
) && (hfsmp
->hfs_partition_avh_sector
== hfsmp
->hfs_fs_avh_sector
)) {
1409 journal_modify_block_end (hfsmp
->jnl
, psAltHdrBuf
, NULL
, NULL
);
1414 * If we don't have a journal or there are two AVH's at the
1415 * moment, then this one doesn't go in the journal. Note that
1416 * this one may generate I/O errors, since the partition
1417 * can be resized behind our backs at any moment and this I/O
1418 * may now appear to be beyond the device EOF.
1420 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
);
1423 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1426 lf_hfs_generic_buf_release(psAltHdrBuf
);
1427 pvAltHdrData
= NULL
;
1428 hfs_flush(hfsmp
, HFS_FLUSH_CACHE
);
1433 /* Finish modifying the block for the primary VH */
1435 journal_modify_block_end(hfsmp
->jnl
, psVolHdrBuf
, NULL
, NULL
);
1439 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
);
1440 /* When critical data changes, flush the device cache */
1441 if (critical
&& (retval
== 0))
1443 hfs_flush(hfsmp
, HFS_FLUSH_CACHE
);
1446 lf_hfs_generic_buf_release(psVolHdrBuf
);
1447 pvVolHdrData
= NULL
;
1450 LFHFS_LOG(LEVEL_ERROR
, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval
, vcb
->vcbVN
);
1454 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
1455 hfs_end_transaction(hfsmp
);
1462 lf_hfs_generic_buf_release(psVolHdrBuf
);
1464 lf_hfs_generic_buf_release(psVolHdr2Buf
);
1466 lf_hfs_generic_buf_release(psAltHdrBuf
);
1468 if (!(options
& HFS_FVH_SKIP_TRANSACTION
)) {
1469 hfs_end_transaction(hfsmp
);
1474 /* If a runtime corruption is detected, set the volume inconsistent
1475 * bit in the volume attributes. The volume inconsistent bit is a persistent
1476 * bit which represents that the volume is corrupt and needs repair.
1477 * The volume inconsistent bit can be set from the kernel when it detects
1478 * runtime corruption or from file system repair utilities like fsck_hfs when
1479 * a repair operation fails. The bit should be cleared only from file system
1480 * verify/repair utility like fsck_hfs when a verify/repair succeeds.
1482 void hfs_mark_inconsistent(struct hfsmount
*hfsmp
, hfs_inconsistency_reason_t reason
)
1484 hfs_lock_mount (hfsmp
);
1485 if ((hfsmp
->vcbAtrb
& kHFSVolumeInconsistentMask
) == 0)
1487 hfsmp
->vcbAtrb
|= kHFSVolumeInconsistentMask
;
1488 MarkVCBDirty(hfsmp
);
1490 if ((hfsmp
->hfs_flags
& HFS_READ_ONLY
)==0)
1494 case HFS_INCONSISTENCY_DETECTED
:
1495 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: Runtime corruption detected on %s, fsck will be forced on next mount.\n",hfsmp
->vcbVN
);
1497 case HFS_ROLLBACK_FAILED
:
1498 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
);
1500 case HFS_OP_INCOMPLETE
:
1501 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
);
1503 case HFS_FSCK_FORCED
:
1504 LFHFS_LOG(LEVEL_ERROR
, "hfs_mark_inconsistent: fsck requested for `%s'; fsck will be forced on next mount.\n",hfsmp
->vcbVN
);
1508 hfs_unlock_mount (hfsmp
);
1512 * Creates a UUID from a unique "name" in the HFS UUID Name space.
1513 * See version 3 UUID.
1516 hfs_getvoluuid(struct hfsmount
*hfsmp
, uuid_t result_uuid
)
1519 if (uuid_is_null(hfsmp
->hfs_full_uuid
)) {
1525 ((uint32_t *)rawUUID
)[0] = hfsmp
->vcbFndrInfo
[6];
1526 ((uint32_t *)rawUUID
)[1] = hfsmp
->vcbFndrInfo
[7];
1528 CC_MD5_Init( &md5c
);
1529 CC_MD5_Update( &md5c
, HFS_UUID_NAMESPACE_ID
, sizeof( uuid_t
) );
1530 CC_MD5_Update( &md5c
, rawUUID
, sizeof (rawUUID
) );
1531 CC_MD5_Final( result
, &md5c
);
1533 result
[6] = 0x30 | ( result
[6] & 0x0F );
1534 result
[8] = 0x80 | ( result
[8] & 0x3F );
1536 uuid_copy(hfsmp
->hfs_full_uuid
, result
);
1538 uuid_copy (result_uuid
, hfsmp
->hfs_full_uuid
);
1543 * Call into the allocator code and perform a full scan of the bitmap file.
1545 * This allows us to TRIM unallocated ranges if needed, and also to build up
1546 * an in-memory summary table of the state of the allocated blocks.
1548 void hfs_scan_blocks (struct hfsmount
*hfsmp
)
1551 * Take the allocation file lock. Journal transactions will block until
1554 int flags
= hfs_systemfile_lock(hfsmp
, SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1557 * We serialize here with the HFS mount lock as we're mounting.
1559 * The mount can only proceed once this thread has acquired the bitmap
1560 * lock, since we absolutely do not want someone else racing in and
1561 * getting the bitmap lock, doing a read/write of the bitmap file,
1562 * then us getting the bitmap lock.
1564 * To prevent this, the mount thread takes the HFS mount mutex, starts us
1565 * up, then immediately msleeps on the scan_var variable in the mount
1566 * point as a condition variable. This serialization is safe since
1567 * if we race in and try to proceed while they're still holding the lock,
1568 * we'll block trying to acquire the global lock. Since the mount thread
1569 * acquires the HFS mutex before starting this function in a new thread,
1570 * any lock acquisition on our part must be linearizably AFTER the mount thread's.
1572 * Note that the HFS mount mutex is always taken last, and always for only
1573 * a short time. In this case, we just take it long enough to mark the
1574 * scan-in-flight bit.
1576 (void) hfs_lock_mount (hfsmp
);
1577 hfsmp
->scan_var
|= HFS_ALLOCATOR_SCAN_INFLIGHT
;
1578 hfs_unlock_mount (hfsmp
);
1580 /* Initialize the summary table */
1581 if (hfs_init_summary (hfsmp
))
1583 LFHFS_LOG(LEVEL_DEBUG
, "hfs_scan_blocks: could not initialize summary table for %s\n", hfsmp
->vcbVN
);
1587 * ScanUnmapBlocks assumes that the bitmap lock is held when you
1588 * call the function. We don't care if there were any errors issuing unmaps.
1590 * It will also attempt to build up the summary table for subsequent
1591 * allocator use, as configured.
1593 (void) ScanUnmapBlocks(hfsmp
);
1595 (void) hfs_lock_mount (hfsmp
);
1596 hfsmp
->scan_var
&= ~HFS_ALLOCATOR_SCAN_INFLIGHT
;
1597 hfsmp
->scan_var
|= HFS_ALLOCATOR_SCAN_COMPLETED
;
1598 hfs_unlock_mount (hfsmp
);
1600 hfs_systemfile_unlock(hfsmp
, flags
);
1604 hfs_GetInfoByID(struct hfsmount
*hfsmp
, cnid_t cnid
, UVFSFileAttributes
*file_attrs
, char pcName
[MAX_UTF8_NAME_LENGTH
])
1606 u_int32_t linkref
= 0;
1607 struct vnode
*psVnode
= NULL
;
1608 struct cat_desc cndesc
;
1609 struct cat_attr cnattr
;
1610 struct cat_fork cnfork
;
1613 /* Check for cnids that should't be exported. */
1614 if ((cnid
< kHFSFirstUserCatalogNodeID
) &&
1615 (cnid
!= kHFSRootFolderID
&& cnid
!= kHFSRootParentID
)) {
1618 /* Don't export our private directories. */
1619 if (cnid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
||
1620 cnid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) {
1624 * Check the hash first
1626 psVnode
= hfs_chash_getvnode(hfsmp
, cnid
, 0, 0, 0);
1628 goto getAttrAndDone
;
1631 bzero(&cndesc
, sizeof(cndesc
));
1632 bzero(&cnattr
, sizeof(cnattr
));
1633 bzero(&cnfork
, sizeof(cnfork
));
1636 * Not in hash, lookup in catalog
1638 if (cnid
== kHFSRootParentID
) {
1639 static char hfs_rootname
[] = "/";
1641 cndesc
.cd_nameptr
= (const u_int8_t
*)&hfs_rootname
[0];
1642 cndesc
.cd_namelen
= 1;
1643 cndesc
.cd_parentcnid
= kHFSRootParentID
;
1644 cndesc
.cd_cnid
= kHFSRootFolderID
;
1645 cndesc
.cd_flags
= CD_ISDIR
;
1647 cnattr
.ca_fileid
= kHFSRootFolderID
;
1648 cnattr
.ca_linkcount
= 1;
1649 cnattr
.ca_entries
= 1;
1650 cnattr
.ca_dircount
= 1;
1651 cnattr
.ca_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1655 const char *nameptr
;
1657 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
1658 error
= cat_idlookup(hfsmp
, cnid
, 0, 0, &cndesc
, &cnattr
, &cnfork
);
1659 hfs_systemfile_unlock(hfsmp
, lockflags
);
1666 * Check for a raw hardlink inode and save its linkref.
1668 pid
= cndesc
.cd_parentcnid
;
1669 nameptr
= (const char *)cndesc
.cd_nameptr
;
1670 if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1671 cndesc
.cd_namelen
> HFS_INODE_PREFIX_LEN
&&
1672 (bcmp(nameptr
, HFS_INODE_PREFIX
, HFS_INODE_PREFIX_LEN
) == 0)) {
1673 linkref
= (uint32_t) strtoul(&nameptr
[HFS_INODE_PREFIX_LEN
], NULL
, 10);
1675 } else if ((pid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) &&
1676 cndesc
.cd_namelen
> HFS_DIRINODE_PREFIX_LEN
&&
1677 (bcmp(nameptr
, HFS_DIRINODE_PREFIX
, HFS_DIRINODE_PREFIX_LEN
) == 0)) {
1678 linkref
= (uint32_t) strtoul(&nameptr
[HFS_DIRINODE_PREFIX_LEN
], NULL
, 10);
1680 } else if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1681 cndesc
.cd_namelen
> HFS_DELETE_PREFIX_LEN
&&
1682 (bcmp(nameptr
, HFS_DELETE_PREFIX
, HFS_DELETE_PREFIX_LEN
) == 0)) {
1683 cat_releasedesc(&cndesc
);
1684 return (ENOENT
); /* open unlinked file */
1689 * Finish initializing cnode descriptor for hardlinks.
1691 * We need a valid name and parent for reverse lookups.
1695 struct cat_desc linkdesc
;
1698 cnattr
.ca_linkref
= linkref
;
1699 bzero (&linkdesc
, sizeof (linkdesc
));
1702 * If the caller supplied the raw inode value, then we don't know exactly
1703 * which hardlink they wanted. It's likely that they acquired the raw inode
1704 * value BEFORE the item became a hardlink, in which case, they probably
1705 * want the oldest link. So request the oldest link from the catalog.
1707 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1708 * side, since we know that we want the last linkID, we can also have this one
1709 * call give us back the name of the last ID, since it's going to have it in-hand...
1711 linkerr
= hfs_lookup_lastlink (hfsmp
, linkref
, &lastid
, &linkdesc
);
1712 if ((linkerr
== 0) && (lastid
!= 0)) {
1714 * Release any lingering buffers attached to our local descriptor.
1715 * Then copy the name and other business into the cndesc
1717 cat_releasedesc (&cndesc
);
1718 bcopy (&linkdesc
, &cndesc
, sizeof(linkdesc
));
1720 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1722 int newvnode_flags
= 0;
1723 error
= hfs_getnewvnode(hfsmp
, NULL
, NULL
, &cndesc
, 0, &cnattr
, &cnfork
, &psVnode
, &newvnode_flags
);
1725 VTOC(psVnode
)->c_flag
|= C_HARDLINK
;
1730 int newvnode_flags
= 0;
1732 void *buf
= hfs_malloc(MAX_UTF8_NAME_LENGTH
);
1737 /* Supply hfs_getnewvnode with a component name. */
1738 struct componentname cn
= {
1739 .cn_nameiop
= LOOKUP
,
1740 .cn_flags
= ISLASTCN
,
1741 .cn_pnlen
= MAXPATHLEN
,
1742 .cn_namelen
= cndesc
.cd_namelen
,
1747 bcopy(cndesc
.cd_nameptr
, cn
.cn_nameptr
, cndesc
.cd_namelen
+ 1);
1748 error
= hfs_getnewvnode(hfsmp
, NULL
, &cn
, &cndesc
, 0, &cnattr
, &cnfork
, &psVnode
, &newvnode_flags
);
1749 if (error
== 0 && (VTOC(psVnode
)->c_flag
& C_HARDLINK
)) {
1750 hfs_savelinkorigin(VTOC(psVnode
), cndesc
.cd_parentcnid
);
1755 cat_releasedesc(&cndesc
);
1758 if (!error
) vnode_GetAttrInternal (psVnode
, file_attrs
);
1759 if (psVnode
!= NULL
) hfs_unlock(VTOC(psVnode
));
1761 if (error
|| psVnode
== NULL
|| psVnode
->sFSParams
.vnfs_cnp
->cn_nameptr
== NULL
){
1762 hfs_vnop_reclaim(psVnode
);
1766 if (cnid
== kHFSRootFolderID
)
1769 strlcpy(pcName
, (char*) psVnode
->sFSParams
.vnfs_cnp
->cn_nameptr
, MAX_UTF8_NAME_LENGTH
);
1772 error
= hfs_vnop_reclaim(psVnode
);
1778 * Look up an HFS object by ID.
1780 * The object is returned with an iocount reference and the cnode locked.
1782 * If the object is a file then it will represent the data fork.
1785 hfs_vget(struct hfsmount
*hfsmp
, cnid_t cnid
, struct vnode
**vpp
, int skiplock
, int allow_deleted
)
1787 struct vnode
*vp
= NULL
;
1788 struct cat_desc cndesc
;
1789 struct cat_attr cnattr
;
1790 struct cat_fork cnfork
;
1792 u_int32_t linkref
= 0;
1796 /* Check for cnids that should't be exported. */
1797 if ((cnid
< kHFSFirstUserCatalogNodeID
) &&
1798 (cnid
!= kHFSRootFolderID
&& cnid
!= kHFSRootParentID
)) {
1801 /* Don't export our private directories. */
1802 if (cnid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
||
1803 cnid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) {
1807 * Check the hash first
1809 vp
= hfs_chash_getvnode(hfsmp
, cnid
, 0, skiplock
, allow_deleted
);
1815 bzero(&cndesc
, sizeof(cndesc
));
1816 bzero(&cnattr
, sizeof(cnattr
));
1817 bzero(&cnfork
, sizeof(cnfork
));
1820 * Not in hash, lookup in catalog
1822 if (cnid
== kHFSRootParentID
) {
1823 static char hfs_rootname
[] = "/";
1825 cndesc
.cd_nameptr
= (const u_int8_t
*)&hfs_rootname
[0];
1826 cndesc
.cd_namelen
= 1;
1827 cndesc
.cd_parentcnid
= kHFSRootParentID
;
1828 cndesc
.cd_cnid
= kHFSRootFolderID
;
1829 cndesc
.cd_flags
= CD_ISDIR
;
1831 cnattr
.ca_fileid
= kHFSRootFolderID
;
1832 cnattr
.ca_linkcount
= 1;
1833 cnattr
.ca_entries
= 1;
1834 cnattr
.ca_dircount
= 1;
1835 cnattr
.ca_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1839 const char *nameptr
;
1841 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
1842 error
= cat_idlookup(hfsmp
, cnid
, 0, 0, &cndesc
, &cnattr
, &cnfork
);
1843 hfs_systemfile_unlock(hfsmp
, lockflags
);
1851 * Check for a raw hardlink inode and save its linkref.
1853 pid
= cndesc
.cd_parentcnid
;
1854 nameptr
= (const char *)cndesc
.cd_nameptr
;
1855 if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1856 cndesc
.cd_namelen
> HFS_INODE_PREFIX_LEN
&&
1857 (bcmp(nameptr
, HFS_INODE_PREFIX
, HFS_INODE_PREFIX_LEN
) == 0)) {
1858 linkref
= (uint32_t) strtoul(&nameptr
[HFS_INODE_PREFIX_LEN
], NULL
, 10);
1860 } else if ((pid
== hfsmp
->hfs_private_desc
[DIR_HARDLINKS
].cd_cnid
) &&
1861 cndesc
.cd_namelen
> HFS_DIRINODE_PREFIX_LEN
&&
1862 (bcmp(nameptr
, HFS_DIRINODE_PREFIX
, HFS_DIRINODE_PREFIX_LEN
) == 0)) {
1863 linkref
= (uint32_t) strtoul(&nameptr
[HFS_DIRINODE_PREFIX_LEN
], NULL
, 10);
1865 } else if ((pid
== hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
1866 cndesc
.cd_namelen
> HFS_DELETE_PREFIX_LEN
&&
1867 (bcmp(nameptr
, HFS_DELETE_PREFIX
, HFS_DELETE_PREFIX_LEN
) == 0)) {
1869 cat_releasedesc(&cndesc
);
1870 return (ENOENT
); /* open unlinked file */
1875 * Finish initializing cnode descriptor for hardlinks.
1877 * We need a valid name and parent for reverse lookups.
1881 struct cat_desc linkdesc
;
1884 cnattr
.ca_linkref
= linkref
;
1885 bzero (&linkdesc
, sizeof (linkdesc
));
1888 * If the caller supplied the raw inode value, then we don't know exactly
1889 * which hardlink they wanted. It's likely that they acquired the raw inode
1890 * value BEFORE the item became a hardlink, in which case, they probably
1891 * want the oldest link. So request the oldest link from the catalog.
1893 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1894 * side, since we know that we want the last linkID, we can also have this one
1895 * call give us back the name of the last ID, since it's going to have it in-hand...
1897 linkerr
= hfs_lookup_lastlink (hfsmp
, linkref
, &lastid
, &linkdesc
);
1898 if ((linkerr
== 0) && (lastid
!= 0)) {
1900 * Release any lingering buffers attached to our local descriptor.
1901 * Then copy the name and other business into the cndesc
1903 cat_releasedesc (&cndesc
);
1904 bcopy (&linkdesc
, &cndesc
, sizeof(linkdesc
));
1906 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1910 int newvnode_flags
= 0;
1911 error
= hfs_getnewvnode(hfsmp
, NULL
, NULL
, &cndesc
, 0, &cnattr
, &cnfork
, &vp
, &newvnode_flags
);
1913 VTOC(vp
)->c_flag
|= C_HARDLINK
;
1915 //TBD - this set is for vfs -> since we have the C_HARDLINK
1916 // currently disable this set.
1917 //vnode_setmultipath(vp);
1922 int newvnode_flags
= 0;
1924 void *buf
= hfs_malloc(MAXPATHLEN
);
1926 /* Supply hfs_getnewvnode with a component name. */
1927 struct componentname cn
= {
1928 .cn_nameiop
= LOOKUP
,
1929 .cn_flags
= ISLASTCN
,
1930 .cn_pnlen
= MAXPATHLEN
,
1931 .cn_namelen
= cndesc
.cd_namelen
,
1936 bcopy(cndesc
.cd_nameptr
, cn
.cn_nameptr
, cndesc
.cd_namelen
+ 1);
1937 error
= hfs_getnewvnode(hfsmp
, NULL
, &cn
, &cndesc
, 0, &cnattr
, &cnfork
, &vp
, &newvnode_flags
);
1939 if (error
== 0 && (VTOC(vp
)->c_flag
& C_HARDLINK
)) {
1940 hfs_savelinkorigin(VTOC(vp
), cndesc
.cd_parentcnid
);
1945 cat_releasedesc(&cndesc
);
1948 if (vp
&& skiplock
) {
1949 hfs_unlock(VTOC(vp
));
1955 * Return the root of a filesystem.
1957 int hfs_vfs_root(struct mount
*mp
, struct vnode
**vpp
)
1959 return hfs_vget(VFSTOHFS(mp
), (cnid_t
)kHFSRootFolderID
, vpp
, 1, 0);
1963 * unmount system call
1965 int hfs_unmount(struct mount
*mp
)
1967 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1968 int retval
= E_NONE
;
1970 if (hfsmp
->hfs_flags
& HFS_SUMMARY_TABLE
)
1972 if (hfsmp
->hfs_summary_table
)
1976 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
1978 if (hfsmp
->hfs_allocation_vp
)
1980 err
= hfs_lock (VTOC(hfsmp
->hfs_allocation_vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1982 hfs_free(hfsmp
->hfs_summary_table
);
1983 hfsmp
->hfs_summary_table
= NULL
;
1984 hfsmp
->hfs_flags
&= ~HFS_SUMMARY_TABLE
;
1986 if (err
== 0 && hfsmp
->hfs_allocation_vp
)
1988 hfs_unlock (VTOC(hfsmp
->hfs_allocation_vp
));
1994 * Invalidate our caches and release metadata vnodes
1997 journal_release(hfsmp
->jnl
);
2002 int iFD
= hfsmp
->hfs_devvp
->psFSRecord
->iFD
;
2003 // Remove Buffer cache entries realted to the mount
2004 lf_hfs_generic_buf_cache_clear_by_iFD(iFD
);
2006 vnode_rele(hfsmp
->hfs_devvp
);
2008 hfs_locks_destroy(hfsmp
);
2009 hfs_delete_chash(hfsmp
);
2010 hfs_idhash_destroy(hfsmp
);
2012 hfs_assert(TAILQ_EMPTY(&hfsmp
->hfs_reserved_ranges
[HFS_TENTATIVE_BLOCKS
]) && TAILQ_EMPTY(&hfsmp
->hfs_reserved_ranges
[HFS_LOCKED_BLOCKS
]));
2013 hfs_assert(!hfsmp
->lockedBlocks
);
2019 /* Update volume encoding bitmap (HFS Plus only)
2021 * Mark a legacy text encoding as in-use (as needed)
2022 * in the volume header of this HFS+ filesystem.
2025 hfs_setencodingbits(struct hfsmount
*hfsmp
, u_int32_t encoding
)
2027 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2028 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2034 case kTextEncodingMacUkrainian
:
2035 index
= kIndexMacUkrainian
;
2037 case kTextEncodingMacFarsi
:
2038 index
= kIndexMacFarsi
;
2045 /* Only mark the encoding as in-use if it wasn't already set */
2046 if (index
< 64 && (hfsmp
->encodingsBitmap
& (u_int64_t
)(1ULL << index
)) == 0) {
2047 hfs_lock_mount (hfsmp
);
2048 hfsmp
->encodingsBitmap
|= (u_int64_t
)(1ULL << index
);
2049 MarkVCBDirty(hfsmp
);
2050 hfs_unlock_mount(hfsmp
);
2055 * Update volume stats
2057 * On journal volumes this will cause a volume header flush
2060 hfs_volupdate(struct hfsmount
*hfsmp
, enum volop op
, int inroot
)
2064 hfs_lock_mount (hfsmp
);
2066 MarkVCBDirty(hfsmp
);
2067 hfsmp
->hfs_mtime
= tv
.tv_sec
;
2073 if (hfsmp
->hfs_dircount
!= 0xFFFFFFFF)
2074 ++hfsmp
->hfs_dircount
;
2075 if (inroot
&& hfsmp
->vcbNmRtDirs
!= 0xFFFF)
2076 ++hfsmp
->vcbNmRtDirs
;
2079 if (hfsmp
->hfs_dircount
!= 0)
2080 --hfsmp
->hfs_dircount
;
2081 if (inroot
&& hfsmp
->vcbNmRtDirs
!= 0xFFFF)
2082 --hfsmp
->vcbNmRtDirs
;
2085 if (hfsmp
->hfs_filecount
!= 0xFFFFFFFF)
2086 ++hfsmp
->hfs_filecount
;
2087 if (inroot
&& hfsmp
->vcbNmFls
!= 0xFFFF)
2091 if (hfsmp
->hfs_filecount
!= 0)
2092 --hfsmp
->hfs_filecount
;
2093 if (inroot
&& hfsmp
->vcbNmFls
!= 0xFFFF)
2098 hfs_unlock_mount (hfsmp
);
2099 hfs_flushvolumeheader(hfsmp
, 0);