Tuesday, July 22, 2025

How to check the integrity of an HFS+ volume in macOS

This is how to check if an HFS+ volume (encrypted) is in good condition, using both Disk Utility and the command line (Terminal). The volume is on a USB stick and was already working fine before checking it now. The volume unlocks and mounts automatically because I've connected it before and confirmed to store the decryption password in my keychain.

The hardware is macOS 15.5 chip M1.


1. USING THE GUI (DISK UTILITY)

This is the log doing it with Disk Utility Version 22.7 (2400).

Select the Volume or Disk -> Run First Aid...

Run First Aid on “HFSP_2TB”?

First Aid will check the volume for errors. It will then repair the volume if necessary.

Verifying storage system
Performing fsck_cs -n -x --lv --uuid BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93

Executing fsck_cs (version 559)
Checking volume
disk4s2: Scan for Volume Headers
disk4s2: Scan for Disk Labels
Logical Volume Group BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93
 on 1 device
disk4s2: Scan for Metadata Volume
Logical Volume Group has a 24 MB Metadata Volume with double redundancy
Start scanning metadata for a valid checkpoint
Load and verify Segment Headers
Load and verify Checkpoint Payload
Load and verify Transaction Segment
Incorporate 0 newer non-checkpoint transactions
Load and verify Virtual Address Table
Load and verify Segment Usage Table
Load and verify Metadata Superblock
Load and verify Logical Volumes B-Trees
Logical Volume Group contains 1 Logical Volume
Load and verify CCE0F2AD-7B1E-4C90-983A-D3B6A7F54E21
Load and verify DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
Load and verify Freespace Summary
Load and verify Block Accounting
Load and verify Live Virtual Addresses
Newest transaction commit checkpoint is valid
Load and verify Segment Cleaning
The volume BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93
 appears to be OK
Storage system check exit code is 0.
Checking file system and repairing if necessary and if possible.
Volume was successfully unmounted.
Performing fsck_hfs -fy -x /dev/rdisk5
Executing fsck_hfs (version hfs-683.120.3).
Checking Journaled HFS Plus volume.
Detected a case-sensitive volume.
The volume name is HFSP_2TB
Checking extents overflow file.
Checking catalogue file.
Checking multi-linked files.
Checking catalogue hierarchy.
Checking extended attributes file.
Checking volume bitmap.
Checking volume information.
Trimming unused blocks.
The volume HFSP_2TB appears to be OK.
File system check exit code is 0.
Restoring the original state found as mounted.
Checking for overcommitted space in Logical Volume Group

Operation successful.


2. USING THE SHELL (TERMINAL)

1) Check that if volume is mounted:

% mount | grep -i hfs
/dev/disk5 on /Volumes/HFSP_2TB (hfs, local, nodev, nosuid, journaled, noowners)

2) Check that there are no processes accessing the volume, except Spotlight, like this (so the volume can be unmounted later on):

% sudo lsof +D /Volumes/HFSP_2TB
Password:
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mds       93391 root   20r   DIR   1,29      340    2 /Volumes/HFSP_2TB
mds       93391 root   27r   DIR   1,29     2550   29 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1
mds       93391 root   28r   DIR   1,29      340    2 /Volumes/HFSP_2TB
mds       93391 root   29u   REG   1,29        0   77 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/journalExclusion
mds       93391 root   30r   DIR   1,29      340    2 /Volumes/HFSP_2TB
mds_store 93420 root  txt    REG   1,29    65536   64 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/reverseDirectoryStore
mds_store 93420 root  txt    REG   1,29       16  171 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexIds
mds_store 93420 root  txt    REG   1,29        8  172 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexBigDates
mds_store 93420 root  txt    REG   1,29        2  173 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexGroups
mds_store 93420 root  txt    REG   1,29     2056  178 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexDirectory
mds_store 93420 root  txt    REG   1,29        8  179 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexCompactDirectory
mds_store 93420 root  txt    REG   1,29    66496  180 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.indexArrays
mds_store 93420 root  txt    REG   1,29    65536  182 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/0.directoryStoreFile
mds_store 93420 root  txt    REG   1,29    32768  141 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexIds
mds_store 93420 root  txt    REG   1,29    16384  142 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexBigDates
mds_store 93420 root  txt    REG   1,29     3277  143 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexGroups
mds_store 93420 root  txt    REG   1,29     8224  148 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexDirectory
mds_store 93420 root  txt    REG   1,29     1024  149 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexCompactDirectory
mds_store 93420 root  txt    REG   1,29    16368  129 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/dbStr-6.map.offsets
mds_store 93420 root  txt    REG   1,29    16384  130 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/dbStr-6.map.buckets
mds_store 93420 root  txt    REG   1,29    65536  152 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.directoryStoreFile
mds_store 93420 root  txt    REG   1,29   131072  145 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexTermIds
mds_store 93420 root  txt    REG   1,29   196608  150 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/live.0.indexArrays
mds_store 93420 root    4r   DIR   1,29     2550   29 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1
mds_store 93420 root    8r   DIR   1,29     2550   29 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1
mds_store 93420 root   10u   REG   1,29       28   35 /Volumes/HFSP_2TB/.Spotlight-V100/Store-V2/AA3A9B2C-D1F0-A2B3-4E5F-C6D7E8F9A0B1/indexState

In this example, there is only one volume (partition) on the whole physical drive, and it takes up all the space (formatted with Disk Utility).

3) Check that the mounted volume is found:

% diskutil list /Volumes/HFSP_2TB
/dev/disk5 (external, virtual):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS HFSP_2TB                +2.0 TB     disk5
                                 Logical Volume on disk4s2
                                 DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
                                 Unlocked Encrypted
This will show the 4 UUID associated to the physical drive:
% diskutil coreStorage list  # diskutil cs list
CoreStorage logical volume groups (1 found)
|
+-- Logical Volume Group BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93
    =========================================================
    Name:         SANDISK_2TB
    Status:       Online
    Size:         2000054870016 B (2.0 TB)
    Free Space:   0 B (0 B)
    |
    +-< Physical Volume 00A2C6B1-4D8E-3F09-AB67-ECD39A7F1B25
    |   ----------------------------------------------------
    |   Index:    0
    |   Disk:     disk4s2
    |   Status:   Online
    |   Size:     2000054870016 B (2.0 TB)
    |
    +-> Logical Volume Family CCE0F2AD-7B1E-4C90-983A-D3B6A7F54E21
        ----------------------------------------------------------
        Encryption Type:         AES-XTS
        Encryption Status:       Unlocked
        Conversion Status:       Complete
        High Level Queries:      Fully Secure
        |                        Passphrase Required
        |                        Accepts New Users
        |                        Has Visible Users
        |                        Has Volume Key
        |
        +-> Logical Volume DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
            ---------------------------------------------------
            Disk:                  disk5
            Status:                Online
            Size (Total):          1999702544384 B (2.0 TB)
            Revertible:            No
            LV Name:               HFSP_2TB
            Volume Name:           HFSP_2TB
            Content Hint:          Apple_HFSX

From now on, the exit code of each command has to be checked, before continuing. The good one is value 0. This is because each command requires the previous one to be successful.

4) Get the "Logical Volume" UUID of the mounted filesystem to use it later:

% diskutil info /Volumes/HFSP_2TB | awk -F': *' '/LVG UUID/{print $2}'
BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93

5) Unmount the volume by mount point:

% diskutil unmount /Volumes/HFSP_2TB
Volume HFSP_2TB on disk5 unmounted
% echo $?
0

Or by "Logical Volume" UUID:

% diskutil unmount DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
Volume HFSP_2TB on disk5 unmounted
% echo $?
0

6) Verify the CoreStorage metadata (read‑only) by providing the "Logical Volume Group" UUID:

% sudo fsck_cs -n --lv --uuid BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93
Password:
   Executing fsck_cs (version 559)
** Checking volume
** disk4s2: Scan for Volume Headers
** disk4s2: Scan for Disk Labels
** Logical Volume Group BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93 on 1 device
** disk4s2: Scan for Metadata Volume
** Logical Volume Group has a 24 MB Metadata Volume with double redundancy
** Start scanning metadata for a valid checkpoint
** Load and verify Segment Headers
** Load and verify Checkpoint Payload
** Load and verify Transaction Segment
** Incorporate 0 newer non-checkpoint transactions
** Load and verify Virtual Address Table
** Load and verify Segment Usage Table
** Load and verify Metadata Superblock
** Load and verify Logical Volumes B-Trees
** Logical Volume Group contains 1 Logical Volume
** Load and verify CCE0F2AD-7B1E-4C90-983A-D3B6A7F54E21
** Load and verify DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
** Load and verify Freespace Summary
** Load and verify Block Accounting
** Load and verify Live Virtual Addresses
** Newest transaction commit checkpoint is valid
** Load and verify Segment Cleaning
** The volume BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93 appears to be OK
% echo $?
0

7) Check (and repair if needed) the HFS+ filesystem. You must use the correct raw disk label with the "r" in front of it instead of the buffered one that doesn't have the "r":

First, all the information about the Disk:

% diskutil info DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
   Device Identifier:         disk5
   Device Node:               /dev/disk5
   Whole:                     Yes
   Part of Whole:             disk5
   Device / Media Name:       SanDisk Portable SSD

   Volume Name:               HFSP_2TB
   Mounted:                   No

   Content (IOContent):       Apple_HFSX
   File System Personality:   Case-sensitive Journaled HFS+
   Type (Bundle):             hfs
   Name (User Visible):       Mac OS Extended (Case-sensitive, Journaled)
   Journal:                   Unknown (not mounted)
   Owners:                    Disabled

   OS Can Be Installed:       No
   Booter Disk:               disk4s3
   Media Type:                Generic
   Protocol:                  USB
   SMART Status:              Not Supported
   Volume UUID:               EEF7D19A-6C3E-4820-A875-9DE41C0A7B3D
   Disk / Partition UUID:     DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8

   Disk Size:                 2.0 TB (1999702544384 Bytes) (exactly 3905669032 512-Byte-Units)
   Device Block Size:         512 Bytes

   Volume Total Space:        0 B (0 Bytes) (exactly 0 512-Byte-Units)
   Volume Free Space:         0 B (0 Bytes) (exactly 0 512-Byte-Units)

   Media OS Use Only:         No
   Media Read-Only:           No
   Volume Read-Only:          Not applicable (not mounted)

   Device Location:           External
   Removable Media:           Fixed

   Solid State:               Yes
   Virtual:                   Yes

   This disk is a Core Storage Logical Volume (LV).  Core Storage Information:
   LV UUID:                   DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
   LVF UUID:                  CCE0F2AD-7B1E-4C90-983A-D3B6A7F54E21
   LVG UUID:                  BBD8C71F-3B29-9F22-6D0A-1E8F7C2B5D93
   PV UUID (disk):            00A2C6B1-4D8E-3F09-AB67-ECD39A7F1B25 (disk4s2)
   Fusion Drive:              No
   Encrypted:                 Yes

Get the raw device belonging to the "Logical Volume" UUID (just replace "disk" with "rdisk" and the rest is the same):

% diskutil info DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8 | awk -F': *' '/Device Node/{gsub("/dev/disk","/dev/rdisk",$2); print $2}'
/dev/rdisk5
% echo $?
0

Use it to check and repair the physical block device:

% sudo fsck_hfs -fy /dev/rdisk5
** /dev/rdisk5
   Executing fsck_hfs (version hfs-683.120.3).
** Checking Journaled HFS Plus volume.
** Detected a case-sensitive volume.
   The volume name is HFSP_2TB
** Checking extents overflow file.
** Checking catalog file.
** Checking multi-linked files.
** Checking catalog hierarchy.
** Checking extended attributes file.
** Checking volume bitmap.
** Checking volume information.
** Trimming unused blocks.
** The volume HFSP_2TB appears to be OK.
% echo $?
0

8) Mount the volume again. This works if the auto-unlock feature is enabled, or the volume has been mounted before so its information is stored in the Keychain:

% diskutil mount /dev/disk5
Volume HFSP_2TB on /dev/disk5 mounted
% echo $?
0

Or by "Logical Volume" UUID:

% diskutil mount DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
Volume HFSP_2TB on DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8 mounted
% echo $?
0

In case it's the first time such device is connected to the computer, or its information / password was deleted from the Keychain, it can be unlocked the following way (unlock password is not stored automatically in the keychain):

% diskutil mount /Volumes/HFSP_2TB
Failed to find disk /Volumes/HFSP_2TB
% sudo diskutil coreStorage unlockVolume DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
Password:
Passphrase:
Started CoreStorage operation
Logical Volume successfully unlocked
Logical Volume successfully attached as disk5
Logical Volume successfully mounted as /Volumes/HFSP_2TB
Core Storage disk: disk5
Finished CoreStorage operation
% diskutil mount DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8
Volume HFSP_2TB on DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8 mounted

  • Password: is the admin / root account password of macOS.
  • Passphrase is the password which was used to encrypt the volume, can the the same or different from the user / admin password.


HOW TO VIEW THE VOLUME KEY FOR AUTO-UNLOCK FEATURE

Open the Keychain Access app Version 11.0 (55324.100.7) with the command open -a "Keychain Access" in a Terminal, or from Spotlight. There you can select "Open Passwords" or "Open Keychain Access" (choose this).

Then select in "Default Keychains" the "login" tab. In column "Kind" sort by "encrypted volume password" and there will appear all volumes that are auto-unlocked upon connection (or account login). The name that appears for each element is when was first saved, so if the volume is renamed afterwards still shows the old one, until deleted and plugged-in again. The key name can be renamed from there, but only renames the key name, not the volume name itself (that has to be done from Finder, Disk Utility or even Terminal.

With "Copy Password to Clipboard", the plain text password to unlock the volume is copied to clipboard.

The key can be searched also by its (original) name or volume ID "DD2B3E8C-98D4-5A1F-7C30-B9E4D6A27FC8" (or any other parameter) using the search box in the Keychain Access app.

This kind of keys are stored automatically in the keychain when a device in plugged-in and the user confirms "Remember this password in my keychain", so next time it's plugged it unlocks and mounts automatically, like if it were not encrypted at all:


The saving of the key to keychain can probably be done also from Terminal but may not be so simple.

HOW TO FORMAT IN HFS+ WITH ENCRYPTION

The latest version of macOS to allow formatting a volume in HFS+ with encryption, is macOS 10.15.7, which includes Disk Utility 19.0 (1704):



The next versions of macOS 11.x, like 11.7.8 or 11.7.10, have this feature already removed from Disk Utility 20.1 (1715.2), so HFS/HFS+ is removed in any combination, and APFS is the only one listed with encryption:


All these screenshots were taken from a virtual machine in VMware Workstation 17.6.4 with compatibility to Workstation 16.x. Only one virtual hard disk needs to be added (does not matter the capacity because will not be used at all, just don't pre-allocate). Boot from the ISO of macOS 10.15.7, and as soon as it boots, select the language and the Recovery menu will appear "macOS Utilities". Then choose Disk Utility. Then connect any USB stick to the virtual machine, and it allows to format in HFS+ in all 4 variants (the + is for Extended):

  • Mac OS Extended (Journaled)
  • Mac OS Extended (Journaled, Encrypted)
  • Mac OS Extended (Case-sensitive, Journaled)
  • Mac OS Extended (Case-sensitive, Journaled, Encrypted)

The ISO and DMG files for multiple macOS versions (including 10.15.7) can be downloaded here:

It's important to note that some users have reported corruption in the HFS+ filesystem for various reasons, so it's much safer to user APFS when possible.

SOURCES

All commands were obtained by trial and error and thanks to ChatGPT o3, and also:



No comments:

Post a Comment

Note: Only a member of this blog may post a comment.