Section 12.5. The Volume Header


12.5. The Volume Header

The most critical structure of an HFS+ volume is the 512-byte volume header, which is stored at a 1024-byte offset from the start of the volumeimmediately after the first reserved area. The information contained in the volume header includes locations of various other important data structures. Unlike the volume header, these other structures do not have a predefined, fixed locationthe volume header serves as a starting point for the operating system (or other entities, such as a disk utility) while accessing the volume.

A copy of the volume headerthe alternate volume headeris stored at a 1024-byte offset from the end of the volume, immediately before the last reserved area. Disk and file system repair utilities typically make use of this copy.

12.5.1. Viewing the Volume Header

Let us use hfsdebug to display the volume header of an HFS+ volume, which we will first create using hdiutil. The following hdiutil command line creates a disk image containing a 32MB journaled HFS+ volume, with the volume name being HFSJ. We can then mount the volume using either the hdiutil or open command-line programs.

$ hdiutil create -size 32m -fs HFSJ -volname HFSJ /tmp/hfsj.dmg ... created: /tmp/hfsj.dmg $ hdiutil mount /tmp/hfsj.dmg /dev/disk10              Apple_partition_scheme /dev/disk10s1            Apple_partition_map /dev/disk10s2            Apple_HFS                       /Volumes/HFSJ


As Figure 127 shows, the volume header contains the extents of the HFS+ B-Trees and of other special files.

Figure 127. The contents of an HFS+ volume header

$ hfsdebug -d /dev/rdisk10s2 -v # HFS Plus Volume   Volume size          = 32728 KB/31.96 MB/0.03 GB # HFS Plus Volume Header   signature            = 0x482b (H+)   version              = 0x4   lastMountedVersion   = 0x4846534a (HFSJ)   attributes           = 00000000000000000010000000000000                        . kHFSVolumeJournaled (volume has a journal)   journalInfoBlock     = 0x2   createDate           = Sun Oct  9 19:24:50 2005   modifyDate           = Sun Oct  9 19:28:36 2005   backupDate           = Fri Jan  1 00:00:00 1904   checkedDate          = Sun Oct  9 19:24:50 2005   fileCount            = 3   folderCount          = 3 /* not including the root folder */   blockSize            = 4096   totalBlocks          = 8182   freeBlocks           = 6002   nextAllocation       = 2807   rsrcClumpSize        = 65536   dataClumpSize        = 65536   nextCatalogID        = 22   writeCount           = 3   encodingsBitmap      = 00000000000000000000000000000000                          00000000000000000000000000000001                            . MacRoman   # Finder Info   ...   # Allocation Bitmap File   ...   # Extents Overflow File   logicalSize          = 258048 bytes   totalBlocks          = 63   clumpSize            = 258048 bytes   extents              =   startBlock   blockCount      % of file                                 0x803         0x3f       100.00 %                          63 allocation blocks in 1 extents total.                          63.00 allocation blocks per extent on an average.   # Catalog File   ...   # Attributes File   logicalSize          = 0 bytes   # Startup File   logicalSize          = 0 bytes

Note in Figure 127 that the volume header's signature field contains the two characters H+. If this were a case-sensitive volume, this field would contain HX. Similarly, the version field would contain the value 5 (instead of 4) for a case-sensitive volume.

While mounting an HFS+ volume, an HFS+ implementation is required to identify itself by setting the lastMountedVersion field in the volume header. This way, an implementation can detect whether there might be a problem because of an earlier mount (e.g., if a journaled volume was mounted without journaling). Examples of values contained in the lastMountedVersion field include 8.10 (mounted on Mac OS 8.1 through 9.2.2), 10.0 (mounted nonjournaled), HFSJ (mounted journaled), fsck (mounted by fsck), and registered creator codes (mounted by a third party represented by the creator code).

The hfsdebug output in Figure 127 includes several dates. HFS+ dates are stored as 32-bit unsigned integers containing the number of seconds since midnight, January 1, 1904, GMT.[12] The volume creation date, however, is stored as local time instead of GMT. Since Unix-style dates are represented as the number of seconds since midnight, January 1, 1970, UTC, one must convert HFS+ dates to Unix-style dates before calling functions such as gmtime() and localtime().

[12] The date integer would overflow after 6:28:15 GMT on February 6, 2040.

Note that the backup date shown in Figure 127 is January 1, 1904. This is because the corresponding date integer contains a zerothat is, it has not been set, say, by a backup utility.


The HFS+ volume header's information in Figure 127 indicates that there are three files and three folders[13] (in addition to the root folder) on the newly created volume. Let us account for these files and folders, while noting that some are created not along with the file system but when the volume is mounted in the Desktop environment. (See the sidebar "Disk Arbitration.")

[13] We will treat the terms folder and directory as synonymous in the context of HFS+.

On a volume without user home directories (typically a nonboot volume), the per-user trash folders, which are used for storing files that have been dragged to the trash, are named .TRashes/<uid>, with <uid> being the numerical user ID of a user.

% id uid=501(amit) gid=501(amit) groups=501(amit) ... % sudo ls -l /Volumes/HFSJ/.Trashes total 0 drwx------  2 amit amit     68 19 Apr 00:58 501


On a boot volume, the per-user trash folders are in the respective home directories (~/.trash).


Thus, two folders are accounted for: .trashes and .trashes/501. These two folders will not exist if you mount our newly created volume manuallysay, using the mount_hfs program from the command line.

Disk Arbitration

As we saw in Chapter 11, the Disk Arbitration daemon (diskarbitrationd) is in charge of mounting volumes as disks, disk images, and removable media devices appear.

Volumes are mounted by diskarbitrationd under the /Volumes directory. Each such volume appears in this directory by either its actual name or a modification of its name. Such modification may be required for two reasons. First, if an HFS+ volume's name contains a / character, diskarbitrationd TRanslates it to a : character, since /, although a valid HFS+ pathname character, can be only a path separator in BSD pathnames. Note that regardless of which /Volumes subdirectory a volume is mounted on, the volume name that appears on the Desktop, along with the volume's icon, is unchanged.

Secondly, it is possible for two or more volumes to have the same name. Suppose you mount four volumes, each named HFSDisk. Even though their Desktop icons will all have the label HFSDisk, they will appear under /Volumes with automatically assigned suffixesfor example, as HFSDisk, HFSDisk 1, HFSDisk 2, and HFSDisk 3.


The third folder is the invisible private metadata folder, which is used internally by the file system and is created during volume creation. We discuss this private folder when we discuss hard links (Section 12.8.6). Note that the . (current directory) and .. (parent directory) directory entries do not reside physically on disk on an HFS+ volumethey are simulated by the HFS+ implementation.

We can verify the number and names of the folders on this volume by using hfsdebug to print the folder thread records in the volume's Catalog B-Tree.

% hfsdebug -b catalog -l folderthread -d /dev/rdisk10s2 # Folder Thread Record   parentID             = 1   nodeName             = HFSJ # Folder Thread Record   parentID             = 2   nodeName             = %00%00%00%00HFS+ Private Data # Folder Thread Record   parentID             = 2   nodeName             = .Trashes # Folder Thread Record   parentID             = 17   nodeName             = 501


Two of the three files on this volume are the invisible journal files: /.journal and /.journal_info_block. The third file is /.DS_Store,[14] which, again, will not exist if you manually mount the newly created volume in our example. We can verify the names of these files by using hfsdebug to print the file thread records in the Catalog B-Tree.

[14] This is a file used by the Finder for caching information about a directory's contents.

$ hfsdebug -b catalog -l filethread -d /dev/rdisk10s2 # File Thread Record   parentID             = 2   nodeName             = .journal # File Thread Record   parentID             = 2   nodeName             = .journal_info_block # File Thread Record   parentID             = 2   nodeName             = .DS_Store


We will discuss file and folder thread records in greater detail in Section 12.7.2.


The volume header also includes an array (the finderInfo field) containing eight 32-bit values, whose meanings are listed in Table 121.

Table 121. Contents of the finderInfo Array in the HFS+ Volume Header

Element at Index

Description

0

If the volume contains a bootable system (typically the one specified by finderInfo[3] or finderInfo[5]), this entry contains its directory ID, and 0 otherwise.

1

If the volume is bootable, this entry contains the parent directory ID of the startup application (such as the Finder); ignored on the PowerPC version of Mac OS X.

2

This entry may contain the ID of a directory that should be opened in the Finder as the volume is mounted.

3

If the volume contains a bootable Mac OS 9 (or 8) system folder, this entry contains its directory ID, and 0 otherwise.

4

This entry is reserved.

5

If the volume contains a bootable Mac OS X system, this entry contains the directory ID of the "system" folder (by default, the folder containing the bootloaderthat is, the BootX or boot.efi files), and 0 otherwise.

6

This is the upper half of a unique 64-bit volume identifier.

7

This is the lower half of the volume identifier.


Since several elements of the volume header's finderInfo array are related to booting, it would be more interesting to look at the volume header on a boot volume. When no volume or device is explicitly specified, hfsdebug operates on the root volume (Figure 128), which normally is also the boot volume.

Figure 128. Finder information contained in the volume header of a boot volume

$ sudo hfsdebug -v ... # Finder Info        # Bootable system blessed folder ID          finderInfo[0] = 0xcf5 (Macintosh HD:/System/Library/CoreServices)        # Parent folder ID of the startup application          finderInfo[1] = 0        # Open folder ID          finderInfo[2] = 0        # Mac OS 9 blessed folder ID          finderInfo[3] = 0xd6533 (Macintosh HD:/System Folder)        # Reserved          finderInfo[4] = 0        # Mac OS X blessed folder ID          finderInfo[5] = 0xcf5 (Macintosh HD:/System/Library/CoreServices)        # VSDB volume identifier (64-bit)          finderInfo[6] = 0x79a955b7          finderInfo[7] = 0xe0610f64        # File System Boot UUID                   UUID = B229E7FA-E0BA-345A-891C-80321D53EE4B ...

As Figure 128 shows, the volume contains both a bootable Mac OS X system and a bootable Mac OS 9 system, with finderInfo[5] and finderInfo[3] containing the respective system folder IDs. In the case of Mac OS X, the "system" folder is the one containing BootXthat is, /System/Library/CoreServices. The Boot UUID string shown is not part of finderInfoit is constructed by hfsdebug (and by BootX during bootstrapping)from the 64-bit volume identifier contained in the last two elements of finderInfo.

As listed in Table 121, if finderInfo[2] contains a folder ID, the Finder will open a window displaying that directory when the volume is mounted. Let us verify this. We can use hdiutil to create an image with a designated "auto-open" folder.

$ mkdir /tmp/auto-open $ mkdir /tmp/auto-open/directory $ echo Hello > /tmp/auto-open/directory/ReadMe.txt $ hdiutil makehybrid -hfs -hfs-openfolder /tmp/auto-open/directory \         -o /tmp/auto-open.dmg /tmp/auto-open Creating hybrid image... ... $ hdiutil mount /tmp/auto-open.dmg ... /dev/disk10s2      Apple_HFS              /Volumes/auto-open


As the volume is mounted, a Finder window should open displaying the folder named directory on the volume. Moreover, finderInfo[2] should be equal to the catalog node ID of directory.

$ hfsdebug -V /Volumes/auto-open -v ...        # Open folder ID        finderInfo[2] = 0x10 (auto-open:/directory) ... $ ls -di /Volumes/auto-open/directory 16 /Volumes/auto-open/directory


12.5.2. Viewing a Volume Control Block

When an HFS+ volume is mounted, an in-kernel block of memory called a volume control block (VCB) holds most of the volume header's information, along with other, dynamic information about the volume. The VCB is represented by the hfsmount structure in the kernel. Given a mounted HFS+ volume, hfsdebug can retrieve the corresponding hfsmount structure's contents from kernel memory.

$ sudo hfsdebug -m   Volume name                             = Macintosh HD (volfs_id  = 234881028)   block device number                     = { major=14, minor=4 }   HFS+ flags                              = 00000000000000000000000010001100                                             + HFS_WRITEABLE_MEDIA                                             + HFS_CLEANED_ORPHANS                                             + HFS_METADATA_ZONE   default owner                           = { uid=99, gid=99 } ...   free allocation blocks                  = 0x86fe4f   start block for next allocation search  = 0x2065a66   next unused catalog node ID             = 3251700   file system write count                 = 61643383   free block reserve                      = 64000   blocks on loan for delayed allocations  = 0 ...


We will revisit the hfsmount structure later in this chapter.




Mac OS X Internals. A Systems Approach
Mac OS X Internals: A Systems Approach
ISBN: 0321278542
EAN: 2147483647
Year: 2006
Pages: 161
Authors: Amit Singh

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net