<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mac OS X Internals: The Blog</title>
	<atom:link href="http://www.osxbook.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.osxbook.com/blog</link>
	<description>A Systems Approach</description>
	<lastBuildDate>Wed, 09 Sep 2009 21:57:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Is Your Machine Good Enough for Snow Leopard K64?</title>
		<link>http://www.osxbook.com/blog/2009/08/31/is-your-machine-good-enough-for-snow-leopard-k64/</link>
		<comments>http://www.osxbook.com/blog/2009/08/31/is-your-machine-good-enough-for-snow-leopard-k64/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 01:45:27 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Mac OS X]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=483</guid>
		<description><![CDATA[&#8220;K64&#8243; is what Apple refers to as the 64-bit version of the kernel beginning with Snow Leopard. As an end user, you really should not worry about the bitness of the kernel. If your Apple computer is not booting into K64 by default, you don&#8217;t need it&#8212;unless, of course, you know that you need it. [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;K64&#8243; is what Apple refers to as the 64-bit version of the kernel beginning with Snow Leopard. As an end user, you really <em>should not</em> worry about the bitness of the kernel. If your Apple computer is not booting into K64 by default, you don&#8217;t need it&mdash;unless, of course, you <em>know</em> that you need it. (Say, because you are a kernel developer or an otherwise system-level developer and want to test something against a 64-bit kernel.) In particular, the 32-bit kernel, which is the default on most existing x86-based Apple computers, runs 64-bit <em>applications</em> just fine. Therefore, as long as you have a 64-bit processor, your Snow Leopard installation <em>is</em> 64-bit from the typical end-user standpoint.</p>
<p>An easy way to tell if you are running a K64 kernel is to use the <code>uname</code> command-line program. The &quot;x86_64&quot; in the excerpt below means that we are running a 64-bit kernel. If the output showed &quot;i386&quot; instead, that would mean a 32-bit kernel.</p>
<p><code style="font-size: 80%;"></p>
<pre>
$ <strong>uname -a</strong>
Darwin... root:xnu-1456.1.25~1/RELEASE_X86_64 x86_64
</pre>
<p></code></p>
<p>If you are averse to using command-line programs (Do you really care about a K64 kernel in that case?), you could instead launch the System Profiler application, either directly, or by clicking on &quot;More Info&#8230;&quot; in the &quot;About This Mac&quot; panel. In System Profiler, you can click on the &quot;Software&quot; section in the sidebar. There will be something about the presence or absence of 64-bit Kernel and Extensions. You could also launch the Activity Monitor application and look for <code>kernel_task</code>. The &quot;Kind&quot; column will say if the kernel task (and consequently the kernel) is 64-bit.</p>
<p>As alluded to earlier, a 64-bit processor is required to run a K64 kernel. To boot into K64, you could do one of several things:</p>
<ul>
<li>Press the <code>6</code> and the <code>4</code> keys simultaneously at power-on time. This indicates to the EFI boot loader (<code>boot.efi</code>) that you wish to boot a 64-bit kernel.</li>
<li>Set the <code>boot-args</code> firmware variable, say, through the <code>nvram</code> command-line program. To boot K64, the specific command-line would be:<br /> <code style="font-size: 80%;">
<pre>$ <strong>sudo nvram boot-args=&quot;arch=x86_64&quot;</strong></pre>
<p></code></li>
<li>Edit <code>/Library/Preferences/SystemConfiguration/com.apple.Boot.plist</code> and add <code>arch=x86_64</code> to the value of the <code>Kernel Flags</code> key. By default, this value is an empty string.<br />
<code style="font-size: 80%;"></p>
<pre>
$ <strong>cat /Library/Preferences/SystemConfiguration/com.apple.Boot.plist</strong>
...
&lt;dict&gt;
	&lt;key&gt;Kernel&lt;/key&gt;
	&lt;string&gt;mach_kernel&lt;/string&gt;
	&lt;key&gt;Kernel Flags&lt;/key&gt;
	&lt;string&gt;<span style="background-color: #00ff00;">arch=x86_64</span>&lt;/string&gt;
&lt;/dict>
...
</pre>
<p></code>
</li>
</ul>
<p>Another way is to use the <code>-setkernelbootarchitecture</code> argument of the <code>systemsetup(8)</code> command-line program.</p>
<p>Additionally, you could tell the kernel to boot verbosely if you are interested in catching a 64-bit boot early on. Note that one of the early kernel messages is <em>&quot;64 bit mode enabled&quot;</em>. This does <strong>not</strong> mean K64&mdash;it just means the kernel has identified the processor to be 64-bit and is going to use certain 64-bit features. In the case of a K64 boot, the message to look for is <em>&quot;Kernel is LP64&quot;</em>.</p>
<p>Not so fast though.</p>
<p>Unfortunately, a 64-bit processor alone doesn&#8217;t suffice. Out of the box, <code>boot.efi</code> will not boot K64 even if you have a 64-bit processor and explicitly request K64 if at least one of the following is true.</p>
<ol>
<li>The machine has 32-bit EFI.</li>
<li>The machine&#8217;s model is prohibited from booting K64 through a hardcoded list within the boot loader. (A cursory look suggests that the list excludes &quot;non-Pro&quot; machines.)</li>
</ol>
<p>Both of these &quot;limitations&quot; are technically artificial, albeit to different degrees.</p>
<p>The first limitation actually does have merit and is arguably not all that artificial. Although a 32-bit EFI <em>could</em> launch a 64-bit kernel, the kernel, when running, would not be able to use firmware services. In particular, you wouldn&#8217;t have NVRAM. For kernel developers merely wanting to run a 64-bit kernel for testing and debugging, this may not be an issue, but it&#8217;s understandable why the limitation is in place.</p>
<p>The second limitation is annoying. As a developer, if you <em>knowingly</em> wish to boot into K64 to test something, you can&#8217;t on certain machines even though they are technically perfectly capable. I ran into this on a Unibody MacBook, which has 64-bit EFI but is not a &quot;Pro&quot; machine. Also, it&#8217;s ironic that you can, in fact, boot Snow Leopard into K64 on the very same computer when you run it as a guest operating system in a virtual machine.</p>
<p>If you really need to boot into K64 on such a machine with 64-bit EFI, you can&mdash;<strong>at your own peril</strong>&mdash;&quot;fix&quot; things within <code>boot.efi</code> by setting the appropriate bits in the hardcoded list of models. To ensure that we&#8217;re talking about the same multiarchitecture version of <code>boot.efi</code>, compare the SHA-1 checksum of that file.</p>
<p><code style="font-size: 80%;"></p>
<pre>
$ <strong>shasum boot.efi</strong>
2fb9fc10e5b4bb06f62c38b01bd9836a433897f8    boot.efi
</pre>
<p></code></p>
<p>Then, change the 1 byte at the corresponding model-specific position in the following table to the corresponding new value. Rather than overwriting the original <code>boot.efi</code>, we will copy the original to a new file, say, <code>boot-k64.efi</code>, and edit the latter.</p>
<table>
<tr>
<th>Model (with 64-bit EFI)</th>
<th>Byte Position in boot.efi</th>
<th>Old Value</th>
<th>New Value</th>
</tr>
<tr>
<td>Mac mini</td>
<td><code>0x266D8</code></td>
<td><code>0x00</code></td>
<td><code>0x04</code></td>
</tr>
<tr>
<td>MacBook</td>
<td><code>0x266E8</code></td>
<td><code>0x00</code></td>
<td><code>0x04</code></td>
</tr>
<tr>
<td>MacBook Air</td>
<td><code>0x266F8</code></td>
<td><code>0x00</code></td>
<td><code>0x04</code</td>
</tr>
<tr>
<td>iMac</td>
<td><code>0x26718</code></td>
<td><code>0x08</code></td>
<td><code>0x0c</code></td>
</tr>
</table>
<p>For the specific case of the MacBook, <strong>which is the only one I've actually tried</strong>, the before and after bytes will look like the following:</p>
<table>
<tr>
<td><code><strong>0x266E0:</strong></code></td>
<td><code>
<pre>38 47 01 00  00 00 00 00  00 00 00 00  00 00 00 00</pre>
<p></code></td>
</tr>
<tr>
<td><code><strong>0x266E0:</strong></code></td>
<td><code>
<pre>38 47 01 00  00 00 00 00  <span style="background: #00ff00;">04</span> 00 00 00  00 00 00 00</pre>
<p></code></td>
</tr>
</table>
<p>We'll place the <code>boot-k64.efi</code> file somewhere on the root volume&mdash;<code>/System/Library/CoreServices/</code> is fine. Then, we need to reset volume bootability through the <code>bless</code> command-line program. Optionally, we can also set the ownership and user immutable flag on the file to &quot;proper&quot; values.</p>
<p><code style="font-size: 80%;"></p>
<pre>
$ <strong>sudo cp boot-k64.efi /System/Library/CoreServices/</strong>
$ <strong>cd /System/Library/CoreServices/</strong>
$ <strong>sudo chown root:wheel boot-k64.efi</strong>
$ <strong>sudo chflags uchg boot-k64.efi</strong>
$ <strong>sudo bless --folder /System/Library/CoreServices \
  --file /System/Library/CoreServices/boot-k64.efi</strong>
</pre>
<p></code></p>
<p>Your mileage may vary depending on whether your installation has 64-bit versions of all necessary drivers for the model of your specific machine. Since I have not tried any other &quot;excluded&quot; machine besides a 64-bit MacBook, I don't know about other models. (Unavailability or instability of certain 64-bit drivers <em>could</em> be a plausible reason for these models to be excluded in the first place.)</p>
<p>If you do render your system unbootable, you can simply run <code>bless</code> again to restore volume bootability as it was before. That is, you can tell <code>bless</code> to use the original <code>boot.efi</code>. Of course, to do that, you'll need to either boot from a different volume (a system install disc would be fine), or be able to access and write to the unbootable volume from another computer.</p>
<p><code style="font-size: 80%;"></p>
<pre>
$ <strong>sudo bless --folder /Volumes/BrokenMac/System/Library/CoreServices \
  --file /Volumes/BrokenMac/System/Library/CoreServices/boot.efi</strong>
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/08/31/is-your-machine-good-enough-for-snow-leopard-k64/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Crafting a Tiny Mach-O Executable</title>
		<link>http://www.osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/</link>
		<comments>http://www.osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 00:34:43 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=452</guid>
		<description><![CDATA[The other day I came across this web page in which the author describes his experiment to create a tiny ELF executable that will run on Linux. The result: a 45-byte ELF executable that executes and returns a value. The executable is functionally equivalent to the one generated from compiling the following C program.


  [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I came across <a href="http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html" title="A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux">this web page</a> in which the author describes his experiment to create a tiny ELF executable that will run on Linux. The result: a 45-byte ELF executable that executes and returns a value. The executable is functionally equivalent to the one generated from compiling the following C program.</p>
<p><code></p>
<pre style="font-size: 85%;">
  /* tiny.c */
  int main(void) { return 42; }
</pre>
<p></code></p>
<p>Apparently recent Linux kernels do stricter checks on ELF executables, because of which the aforementioned 45-byte executable no longer works. A slightly larger, 64-byte version still works at the time of this writing.</p>
<p>Anyway, as far as tiny executables go, ELF on Linux is taken care of. It would be interesting to repeat a similar experiment for Mach-O executables on Mac OS X.</p>
<p>Let us first see how large the executable generated from the C program is on Mac OS X.<br />
<code></p>
<pre style="font-size: 80%;">
$ <strong>cat tiny.c</strong>
main() { return 42; }
$ <strong>sw_vers</strong>
...
ProductVersion: 10.5.6
...
$ <strong>gcc -Oz -o tiny tiny.c</strong>
$ <strong>strip tiny</strong>
$ <strong>ls -las tiny</strong>
32 -rwxr-xr-x  1 singh  wheel  <span style="background-color: #00ff00;">12348</span> Mar 15 17:26 tiny
</code>
</pre>
<p>The following assembly language program can be compiled to generate a 165-byte Mach-O executable that runs on Mac OS X and returns the wisely chosen value 42.</p>
<p><code></p>
<pre style="font-size: 80%;">
; tiny.asm for Mac OS X (Mach-O Object File Format)
; nasm -f bin -o tiny tiny.asm

BITS 32
        org   0x1000

        db    0xce, 0xfa, 0xed, 0xfe       ; magic
        dd    7                            ; cputype (CPU_TYPE_X86)
        dd    3                            ; cpusubtype (CPU_SUBTYPE_I386_ALL)
        dd    2                            ; filetype (MH_EXECUTE)
        dd    2                            ; ncmds
        dd    _start - _cmds               ; cmdsize
        dd    0                            ; flags
_cmds:
        dd    1                            ; cmd (LC_SEGMENT)
        dd    44                           ; cmdsize
        db    "__TEXT"                     ; segname
        db    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; segname
        dd    0x1000                       ; vmaddr
        dd    0x1000                       ; vmsize
        dd    0                            ; fileoff
        dd    filesize                     ; filesize
        dd    7                            ; maxprot

        dd    5                            ; cmd (LC_UNIXTHREAD)
        dd    80                           ; cmdsize
        dd    1                            ; flvaor (i386_THREAD_STATE)
        dd    16                           ; count (i386_THREAD_STATE_COUNT)
        dd    0, 0, 0, 0, 0, 0, 0, 0       ; state
        dd    0, 0, _start, 0, 0, 0, 0, 0  ; state
_start:
        xor   eax,eax
        inc   eax
	push  byte 42
        sub   esp, 4
        int   0x80                         ; _exit(42)

filesize equ  $ - $$
</pre>
<p></code></p>
<p>We can compile and run this program as follows, verifying that its return value is indeed 42.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>nasm -f bin -o tiny tiny.asm</strong>
$ <strong>ls -las tiny</strong>
8 -rw-r--r--  1 singh  admin  <span style="background-color: #00ff00;">165</span> Mar 15 12:21 tiny
$ <strong>chmod 755 tiny</strong>
$ <strong>./tiny</strong>
$ <strong>echo $?</strong>
42
</pre>
<p></code></p>
<p>Some points to note:</p>
<ul style="list-style: square;">
<li>The executable&mdash;Mach-O header, load commands, the text segment&mdash;is manually crafted in assembly using the <code>nasm</code> 80x86 assembler. The C compiler toolchain is not involved.</li>
<li>The executable is unusual for Mac OS X in that the dynamc link editor (<code>dyld</code>) is not involved in running it. No dynamic libraries are involved either.</li>
<li>The program makes a &quot;direct&quot; system call through the <code>int 0x80</code> interface. This is a big no-no on Mac OS X&mdash;production code should not be bypassing the C library for making system calls, but then hopefully you won't be writing production code using such techniques. A specific caveat is that system call <em>implementation</em> may do things differently&mdash;in terms of arguments, return values, and such&mdash;from the user-callable interface. The implementation may also change across system revisions, so such code may break with a system update.</li>
<li>The <code>int 0x80</code> system call path is a legacy path on Mac OS X. It may be removed from Mac OS X some day, in which case the program would need to be modified to use newer alternatives such as <code>sysenter</code>.</li>
<li>The executable is <em>not</em> a &quot;correct&quot; Mach-O file, even though the kernel can parse and run it in our case. The reason it's incorrect is because Mach-O load commands have been deliberately made to overlap each other to save some bytes. The <code>otool</code> object-file introspection command will be quite unhappy with this executable. In the following output, inconsistencies are shown in red.</li>
</ul>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>otool -l tiny</strong>
tiny:
Load command 0
      cmd LC_SEGMENT
  cmdsize <span style="color: red;">44 Inconsistent size</span>
  segname __TEXT
   vmaddr 0x00001000
   vmsize 0x00001000
  fileoff 0
 filesize 165
  maxprot 0x00000007
 initprot 0x00000005
   nsects <span style="color: red;">80</span>
    flags 0x1
Section
  <span style="color: red;">sectname
   segname  (does not match segment)
      addr 0x00000000
      size 0x00000000
    offset 0
     align 2^4248 (16777216)</span>
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
<span style="color: red;">section structure command extends past end of load commands
Section
  sectname
   segname  (does not match segment)
      addr 0x00000000
      size 0x00000000
    offset 0
     align 2^0 (1)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0</span>
</pre>
<p></code></p>
<p>At the cost of roughly 80 additional bytes, we can create a &quot;more correct&quot; Mach-O executable that <code>otool</code> will be happy with.</p>
<p><code></p>
<pre style="font-size: 80%;">
; nicertiny.asm for Mac OS X (Mach-O Object File Format)
; nasm -f bin -o nicertiny nicertiny.asm

BITS 32
        org   0x1000

        db    0xce, 0xfa, 0xed, 0xfe       ; magic
        dd    7                            ; cputype (CPU_TYPE_X86)
        dd    3                            ; cpusubtype (CPU_SUBTYPE_I386_ALL)
        dd    2                            ; filetype (MH_EXECUTE)
        dd    2                            ; ncmds
        dd    _start - _cmds               ; cmdsize
        dd    0                            ; flags
_cmds:
        dd    1                            ; cmd (LC_SEGMENT)
        dd    124                          ; cmdsize
        db    "__TEXT"                     ; segname
        db    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; segname
        dd    0x1000                       ; vmaddr
        dd    0x1000                       ; vmsize
        dd    0                            ; fileoff
        dd    filesize                     ; filesize
        dd    7                            ; maxprot
        dd    5                            ; initprot
        dd    1                            ; nsects
        dd    0                            ; flags
        db    "__text"                     ; sectname
        db    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; sectname
        db    "__TEXT"                     ; segname
        db    0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; segname
        dd    _start                       ; addr
        dd    _end - _start                ; size;
        dd    _start - 0x1000              ; offset
        dd    2                            ; align
        dd    0                            ; reloff
        dd    0                            ; nreloc
        dd    0                            ; flags
        dd    0                            ; reserved1
        dd    0                            ; reserved2

        dd    5                            ; cmd (LC_UNIXTHREAD)
        dd    80                           ; cmdsize
        dd    1                            ; flavor (i386_THREAD_STATE)
        dd    16                           ; count (i386_THREAD_STATE_COUNT)
        dd    0, 0, 0, 0, 0, 0, 0, 0       ; state
        dd    0, 0, _start, 0, 0, 0, 0, 0  ; state
_start:
        xor   eax, eax
        inc   eax
        push  dword 42
        sub   esp, 4
        int   0x80                         ; _exit(42)
_end:
filesize equ  $ - $$
</code>
</pre>
<p>Let us compile and run this version, and see what <code>otool</code> has to say.</p>
<p><code></p>
<pre style="font-size: 80%;">
$ <strong>nasm -f bin -o nicertiny nicertiny.asm</strong>
$ <strong>ls -las nicertiny</strong>
8 -rw-r--r--  1 singh  admin  <span style="background-color: #00ff00;">248</span> Mar 15 14:49 nicertiny
$ <strong>chmod 755 nicertiny</strong>
$ <strong>./nicertiny</strong>
$ <strong>echo $?</strong>
42
$ <strong>otool -l nicertiny</strong>
nicertiny:
Load command 0
      cmd LC_SEGMENT
  cmdsize 124
  segname __TEXT
   vmaddr 0x00001000
   vmsize 0x00001000
  fileoff 0
 filesize 248
  maxprot 0x00000007
 initprot 0x00000005
   nsects 1
    flags 0x0
Section
  sectname __text
   segname __TEXT
      addr 0x000010e8
      size 0x00000010
    offset 232
     align 2^2 (4)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0
Load command 1
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
	    eax 0x00000000 ebx    0x00000000 ecx 0x00000000 edx 0x00000000
	    edi 0x00000000 esi    0x00000000 ebp 0x00000000 esp 0x00000000
	    ss  0x00000000 eflags 0x00000000 eip 0x000010e8 cs  0x00000000
	    ds  0x00000000 es     0x00000000 fs  0x00000000 gs  0x00000000
</code>
</pre>
<p>It would be a nice exercise for the reader to try to shrink <code>tiny.asm</code> and <code>nicertiny.asm</code> even further, while retaining the high-level behavior of the corresponding executables. There are plenty of zeros lurking in there.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A TPM for Everyone</title>
		<link>http://www.osxbook.com/blog/2009/03/08/a-tpm-for-everyone/</link>
		<comments>http://www.osxbook.com/blog/2009/03/08/a-tpm-for-everyone/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 06:23:33 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Mac OS X]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=445</guid>
		<description><![CDATA[Suppose you have a Macintosh without a TPM. This, of course, is highly likely because only the first few x86-based Macintosh models had TPMs.  Now suppose you really want to experiment with Trusted Computing or features of the TPM in general. Your needs could be development-related or they could be purely academic. Well, you [...]]]></description>
			<content:encoded><![CDATA[<p>Suppose you have a Macintosh without a TPM. This, of course, is highly likely because only the first few x86-based Macintosh models had TPMs.  Now suppose you really want to experiment with Trusted Computing or features of the TPM in general. Your needs could be development-related or they could be purely academic. Well, you can do the <a href="http://osxbook.com/software/tpm-emulator/" title="A TPM for Everyone">next best thing to having a real TPM&#8230;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/03/08/a-tpm-for-everyone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why MacFUSE Installation Recommends a Reboot</title>
		<link>http://www.osxbook.com/blog/2009/03/02/why-macfuse-installation-recommends-a-reboot/</link>
		<comments>http://www.osxbook.com/blog/2009/03/02/why-macfuse-installation-recommends-a-reboot/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 06:01:09 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[MacFUSE]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=412</guid>
		<description><![CDATA[I often hear users&#8212;and even developers, for that matter&#8212;grumbling about the fact that they are &#34;required&#34; to reboot their systems after installing or upgrading MacFUSE. I&#8217;ve even heard explanations that because MacFUSE &#34;does something with the kernel,&#34; a reboot is necessary. Well, this whole rebooting-required thing is a myth. Lets clear up some misconceptions.
When you [...]]]></description>
			<content:encoded><![CDATA[<p>I often hear users&mdash;and even developers, for that matter&mdash;grumbling about the fact that they are &quot;required&quot; to reboot their systems after installing or upgrading MacFUSE. I&#8217;ve even heard explanations that because MacFUSE <em>&quot;does something with the kernel,&quot;</em> a reboot is necessary. Well, this whole rebooting-required thing is a myth. Lets clear up some misconceptions.</p>
<p>When you install the official MacFUSE package, you see the following rebooting-related notice.</p>
<p><center><br />
<img src="/images/blog/macfuse_installer.png" /><br />
</center></p>
<p>To begin with, it is <em>recommended</em> (not <em>required</em>) that you restart your system. Unlike in the case of Mac OS X software installations that do necessitate a restart, you can simply close the Installer window after you are done installing MacFUSE.</p>
<p>Now, why is it even recommended that you restart? Let us get some context.</p>
<p>If you are installing MacFUSE for the first time (that is, you are not upgrading a MacFUSE installation), restarting is entirely unnecessary.</p>
<p>If you are upgrading a MacFUSE installation, restarting is a heavy-handed way for users to avoid the confusing situation described below&mdash;it is still not <em>required</em> to restart if you know how to avoid the confusing situation and are willing to deal with the extra steps needed.</p>
<p>MacFUSE consists of both kernel-resident and user-space-resident software components. The MacFUSE kernel extension is both dynamically loadable <em>and</em> dynamically unloadable. That is, you can simply unload it if it is not in use and reload a new version.</p>
<p>There is one important thing to know: the kernel-space and user-space components of MacFUSE are in lockstep. You cannot use an older user-space MacFUSE component with a newer MacFUSE kernel extension and vice versa. The aforementioned confusing situation arises when you upgrade MacFUSE <em>while</em> you have a MacFUSE-based file system mounted. The busy kernel extension cannot be unloaded, and the upgraded user-space components will refuse to work with the old kernel extension.</p>
<p>The user-space MacFUSE components actually ensure that the loaded kernel extension is the matching one. In fact, if you upgrade an installation while the MacFUSE kernel extension is loaded, the user-space components will try to unload the old extension and then try to load the new extension. This works, except in the case when the already loaded kernel extension is &quot;busy,&quot; which would be the case if you do have a mounted MacFUSE-based file system.</p>
<p>If you first ensure that no MacFUSE-based file systems are mounted, you can upgrade MacFUSE, <em>not restart</em>, and once upgraded, start using the new MacFUSE. The <code>lsvfs</code> command-line tool can be used to determine if a MacFUSE-based file system is mounted.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>lsvfs</strong>
Filesystem                        Refs Flags
-------------------------------- ----- ---------------
ufs                                  0 local
nfs                                  1
fdesc                                1
cd9660                               0 local
unionfs                              0
hfs                                  2 local, dovolfs
devfs                                1
autofs                               2
msdos                                0 local
<span style="background-color: #00ff00;">fusefs                               0</span>
</pre>
<p></code></p>
<p>If there is no entry for <code>fusefs</code> or if the corresponding value in the <code>Refs</code> column is 0, you shouldn&#8217;t have to do anything. If the value is non-zero, you need to unmount that many MacFUSE-based volumes.</p>
<p>To sum up, a restart is <em>recommended</em> so that end users don&#8217;t have to understand these details. Even then, the only time a restart will actually matter is the case when you <em>upgrade</em> MacFUSE <em>while</em> a MacFUSE-based file system is mounted and <em>then</em> you attempt to mount yet another MacFUSE-based file system using the upgraded version of MacFUSE.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/03/02/why-macfuse-installation-recommends-a-reboot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Retrieving x86 Processor Information</title>
		<link>http://www.osxbook.com/blog/2009/03/02/retrieving-x86-processor-information/</link>
		<comments>http://www.osxbook.com/blog/2009/03/02/retrieving-x86-processor-information/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 05:20:55 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=401</guid>
		<description><![CDATA[The other day I needed to know within one of my experimental programs if the host x86 processor supports certain features. In many cases, the operating system provides interfaces that can answer such questions. Sometimes, the interfaces may not have the answer, or you may wish to avoid them for other reasons. (Say, you don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I needed to know within one of my experimental programs if the host x86 processor supports certain features. In many cases, the operating system provides interfaces that can answer such questions. Sometimes, the interfaces may not have the answer, or you may wish to avoid them for other reasons. (Say, you don&#8217;t wish to depend on anything operating-system-specific.) Of course, one can turn to the x86 processor&#8217;s venerable <code>CPUID</code> instruction. I took some code from the xnu kernel and made it into a user-space program that displays processor information. For academic needs, it is always good to have a program at hand that does things from first principles.</p>
<p>Here is the <a href="/book/bonus/misc/cpuinfo_x86/cpuinfo_x86.c" title="Source for cpuinfo_x86">source for <code>cpuinfo_x86</code></a>.</p>
<p>The following is an example of the program in action. You must compile it as a 32-bit program. Besides Mac OS X, the program should also work on Linux, FreeBSD, and perhaps some other operating systems.</p>
<p><code></p>
<pre style="font-size:80%; background-color:#F4F4F4;">
$ <strong>gcc -march=i386 -m32 -o cpuinfo_x86 cpuinfo_x86.c</strong>
$ <strong>./cpuinfo_x86</strong>
# Identification
Vendor                : GenuineIntel
Brand String          : Intel(R) Xeon(R) CPU           X5550  @ 2.67GHz
Model Number          : 26 (Nehalem)
Family Code           : 6
Extended Model        : 1
Extended Family       : 0
Stepping ID           : 5
Signature             : 67237

# Address Bits
Physical Addressing   : 40
Virtual Addressing    : 48

# Multi-Core Information
Logical Processors (Threads) per Physical Processor : 16
Cores per Physical Package                          : 8

# Caches
## L1 Instruction Cache
Size                  : 32K
Line Size             : 64B
Sharing               : shared between 2 processor threads
Sets                  : 128
Partitions            : 1
Associativity         : 4

## L1 Data Cache
Size                  : 32K
Line Size             : 64B
Sharing               : shared between 2 processor threads
Sets                  : 64
Partitions            : 1
Associativity         : 8

## L2 Unified Cache
Size                  : 256K
Line Size             : 64B
Sharing               : shared between 2 processor threads
Sets                  : 512
Partitions            : 1
Associativity         : 8

## L3 Unified Cache
Size                  : 8M
Line Size             : 64B
Sharing               : shared between 16 processor threads
Sets                  : 8192
Partitions            : 1
Associativity         : 16

# Translation Lookaside Buffers
Instruction TLBs      : 7 large, 0 small
Data TLBs             : 32 large, 64 small

# Features
ACPI                  : Thermal Monitor and Software Controlled Clock
APIC                  : On-Chip APIC Hardware
CLFSH                 : CLFLUSH Instruction
CMOV                  : Conditional Move Instruction
CX16                  : CMPXCHG16B Instruction
CX8                   : CMPXCHG8 Instruction
DCA                   : Direct Cache Access
DE                    : Debugging Extension
DS                    : Debug Store
DS-CPL                : CPL Qualified Debug Store
DTES64                : 64-Bit Debug Store
EST                   : Enhanced Intel SpeedStep Technology
FPU                   : Floating-Point Unit On-Chip
FXSR                  : FXSAVE and FXSTOR Instructions
HTT                   : HyperThreading
MCA                   : Machine-Check Architecture
MCE                   : Machine-Check Exception
MMX                   : MMX Technology
MONITOR               : MONITOR/MWAIT Instructions
MSR                   : Model Specific Registers
MTRR                  : Memory Type Range Registers
PAE                   : Physical Address Extension
PAT                   : Page Attribute Table
PBE                   : Pending Break Enable
PDCM                  : Perfmon and Debug Capability
PGE                   : Page Global Enable
POPCNT                : POPCNT Instruction
PSE                   : Page Size Extension
PSE-36                : 36-Bit Page Size Extension
SEP                   : Fast System Call
SS                    : Self-Snoop
SSE                   : Streaming SIMD Extensions
SSE2                  : Streaming SIMD Extensions 2
SSE3                  : Streaming SIMD Extensions 3
SSSE3                 : Supplemental Streaming SIMD Extensions 3
SSE4.1                : Streaming SIMD Extensions 4.1
SSE4.2                : Streaming SIMD Extensions 4.2
TM                    : Thermal Monitor
TM2                   : Thermal Monitor 2
TSC                   : Time Stamp Counter
VME                   : Virtual Mode Extension
VMX                   : Virtual Machine Extensions
xTPR                  : xTPR Update Control

# Extended Features
EM64T                 : Intel Extended Memory 64 Technology
XD                    : Execution Disable
</pre>
<p></code></p>
<p>Despite the detailed information <code>cpuinfo_x86</code> shows, it is still does not retrieve all possible information you can get through <code>CPUID</code>. Moreover, because I wrote it for the x86 version of Mac OS X, the program assumes that you have a relatively recent x86 processor and will likely not behave too well on old processors. Writing an exhaustive and legacy-aware <code>CPUID</code> program is a more rigorous programming exercise.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/03/02/retrieving-x86-processor-information/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Displaying the Physical Memory Map</title>
		<link>http://www.osxbook.com/blog/2009/02/25/displaying-the-physical-memory-map/</link>
		<comments>http://www.osxbook.com/blog/2009/02/25/displaying-the-physical-memory-map/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 22:40:39 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Mac OS X]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=381</guid>
		<description><![CDATA[The Apple Kernel Debug Kit comes with a kernel gdb macros file (kgmacros) that contains numerous macros useful during low-level development and analysis. One of the macros is showbootermemorymap, which dumps the physical memory map from EFI. The information in this map is very useful for certain types of development.
Since I am often mobile&#8212;without ready [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://developer.apple.com/hardwaredrivers/download/kerneldebugkits.html" title="Kernel Debug Kits Downloads">Apple Kernel Debug Kit</a> comes with a kernel gdb macros file (<code>kgmacros</code>) that contains numerous macros useful during low-level development and analysis. One of the macros is <code>showbootermemorymap</code>, which dumps the physical memory map from EFI. The information in this map is very useful for certain types of development.</p>
<p>Since I am often mobile&mdash;without ready access to a two-machine debugging set up&mdash;I can&#8217;t use <em>real</em> kernel debugging much of the time. For introspection-only kernel &quot;debugging&quot;, one can use the <code>darwin-kernel</code> gdb target on Mac OS X. It does require that you have a <code>/dev/kmem</code> device available. <code>/dev/kmem</code> is not enabled by default on Mac OS X, but you can enable it at boot time by including <code>kmem=1</code> in the kernel&#8217;s boot arguments.</p>
<p><code></p>
<pre style="font-size: 85%; background-color: #F4F4F4;">
$ <strong>sudo nvram boot-args="-v kmem=1 ..."</strong>
$ <strong>sudo reboot</strong>
/* system reboots */
$ <strong>cd /path/to/kernel/debug/kit/for/current/system/</strong>
$ <strong>sudo gdb ./mach_kernel</strong>
...
(gdb) <strong>source kgmacros</strong>
Loading Kernel GDB Macros package.  Type "help kgm" for more info.
(gdb) <strong>target darwin-kernel</strong>
(gdb) <strong>attach</strong>
Connected.
(gdb) <strong>showbootermemorymap</strong>
Type       Physical Start   Number of Pages
available  0000000000000000 000000000000008f
ACPI_NVS   000000000008f000 0000000000000001
available  0000000000090000 0000000000000010
...
RT_data    0000000000a8c000 000000000000002b
RT_data    0000000000ab7000 0000000000000001
(gdb)
</pre>
<p></code></p>
<p>A more convenient alternative is to simply use DTrace to print this information. The following is a DTrace script that mimics the behavior of the <code>showbootermemorymap</code> kernel debug macro.</p>
<p><code></p>
<pre style="font-size:80%; background-color:#F4F4F4;">
#! /usr/sbin/dtrace -s

/*
 * showbootermemorymap - DTrace script that prints out the physical memory
 *                       map from EFI. Mimics the output format of the
 *                       kernel debugging macro of the same name.
 *
 * Amit Singh
 * http://osxbook.com
 */

#pragma D option quiet

BEGIN
{
    self-&gt;inited = 1;

    self-&gt;kgm_boot_args = ((struct boot_args*)(`PE_state).bootArgs);
    self-&gt;kgm_msize = self-&gt;kgm_boot_args-&gt;MemoryMapDescriptorSize;
    self-&gt;kgm_mcount = self-&gt;kgm_boot_args-&gt;MemoryMapSize / self-&gt;kgm_msize;

    printf("Type       Physical Start   Number of Pages\n");

    self-&gt;kgm_i = 0;
}

fbt:::entry
/self-&gt;inited &#038;&#038; self-&gt;kgm_i &lt; self-&gt;kgm_mcount/
{
    this-&gt;kgm_mptr = (struct EfiMemoryRange*)
    ((unsigned long)self-&gt;kgm_boot_args-&gt;MemoryMap +
                    self-&gt;kgm_i * self-&gt;kgm_msize);

    self-&gt;kgm_i++;

    printf("%s", (this-&gt;kgm_mptr-&gt;Type == 0)  ? "reserved  " :
                 (this-&gt;kgm_mptr-&gt;Type == 1)  ? "LoaderCode" :
                 (this-&gt;kgm_mptr-&gt;Type == 2)  ? "LoaderData" :
                 (this-&gt;kgm_mptr-&gt;Type == 3)  ? "BS_code   " :
                 (this-&gt;kgm_mptr-&gt;Type == 4)  ? "BS_data   " :
                 (this-&gt;kgm_mptr-&gt;Type == 5)  ? "RT_code   " :
                 (this-&gt;kgm_mptr-&gt;Type == 6)  ? "RT_data   " :
                 (this-&gt;kgm_mptr-&gt;Type == 7)  ? "available " :
                 (this-&gt;kgm_mptr-&gt;Type == 8)  ? "Unusable  " :
                 (this-&gt;kgm_mptr-&gt;Type == 9)  ? "ACPI_recl " :
                 (this-&gt;kgm_mptr-&gt;Type == 10) ? "ACPI_NVS  " :
                 (this-&gt;kgm_mptr-&gt;Type == 11) ? "MemMapIO  " :
                 (this-&gt;kgm_mptr-&gt;Type == 12) ? "MemPortIO " :
                 (this-&gt;kgm_mptr-&gt;Type == 13) ? "PAL_code  " :
                                                "UNKNOWN   ");
    printf(" %016llx %016llx\n",
           this-&gt;kgm_mptr-&gt;PhysicalStart, this-&gt;kgm_mptr-&gt;NumberOfPages);
}

fbt:::return
/self-&gt;inited &#038;&#038; self-&gt;kgm_i &gt;= self-&gt;kgm_mcount/
{
    exit(0);
}
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/02/25/displaying-the-physical-memory-map/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XBinary: Extended Binary Format Support for Mac OS X</title>
		<link>http://www.osxbook.com/blog/2009/01/20/xbinary-extended-binary-format-support-for-mac-os-x/</link>
		<comments>http://www.osxbook.com/blog/2009/01/20/xbinary-extended-binary-format-support-for-mac-os-x/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 06:17:51 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=377</guid>
		<description><![CDATA[XBinary is software that lets you add kernel-level support for executing arbitrary binary formats on Mac OS X. To read more about it and to download it, visit the XBinary page.
]]></description>
			<content:encoded><![CDATA[<p>XBinary is software that lets you add kernel-level support for executing arbitrary binary formats on Mac OS X. To read more about it and to download it, visit the <a href="http://osxbook.com/software/xbinary/" title="XBinary">XBinary page</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2009/01/20/xbinary-extended-binary-format-support-for-mac-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AncientFS on Linux and FreeBSD</title>
		<link>http://www.osxbook.com/blog/2008/12/22/ancientfs-on-linux-and-freebsd/</link>
		<comments>http://www.osxbook.com/blog/2008/12/22/ancientfs-on-linux-and-freebsd/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 12:41:37 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=363</guid>
		<description><![CDATA[By popular demand, I&#8217;ve &#34;ported&#34; AncientFS to Linux and FreeBSD. It was reasonably straightforward. Largely on purpose, AncientFS depends on the cross-platform interfaces of MacFUSE for the most part.


Most people don&#8217;t realize that MacFUSE is much more than a &#34;Mac OS X implementation of the FUSE API.&#34; Of course, the name &#34;MacFUSE&#34; doesn&#8217;t help much [...]]]></description>
			<content:encoded><![CDATA[<p>By popular demand, I&#8217;ve &quot;ported&quot; <a href="http://osxbook.com/software/ancientfs/" title="AncientFS">AncientFS</a> to Linux and FreeBSD. It was reasonably straightforward. Largely on purpose, AncientFS depends on the cross-platform interfaces of MacFUSE for the most part.</p>
<div style="background-color: #EAEAF4;">
<p>
Most people don&#8217;t realize that MacFUSE is much more than a &quot;Mac OS X implementation of the FUSE API.&quot; Of course, the name &quot;Mac<strong>FUSE</strong>&quot; doesn&#8217;t help much in that regard.
</p>
</div>
<p>You should now be able to build the AncientFS source tree on Mac OS X, Linux, and FreeBSD. You must have the FUSE implementation for your platform installed to build and use AncientFS. Then, it should take a single <code>make</code> command to build.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>svn co http://macfuse.googlecode.com/svn/trunk/filesystems/unixfs</strong>
$ <strong>cd unixfs/ancientfs</strong>
$ <strong>make</strong> # GNU make required. Use gmake on FreeBSD.
...
</pre>
<p></code></p>
<p>If it doesn&#8217;t build out-of-the-box on your system, you might want to tweak platform-specific settings in <code>unixfs/ancientfs/Makefile</code> first. The default settings assume that <code>fuse</code> is installed under <code>/usr</code> on Linux and under <code>/usr/local</code> on FreeBSD.</p>
<p>Because <code>libfuse</code> wants to use <code>sem_init()</code>, you will need to ensure on FreeBSD that the POSIX semaphore implementation is either statically compiled into the kernel (<em>not</em> the default on recent FreeBSD systems) or the <code>sem</code> kernel module is loaded. See <code>sem(4)</code> for details.</p>
<p>I&#8217;m traveling and don&#8217;t have good/much access to Linux or FreeBSD machines. Therefore, I haven&#8217;t been able to test this much. I do know that it builds and mounts some things on at least Linux 2.6.18 (Ubuntu) and FreeBSD 7.1-BETA2.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/22/ancientfs-on-linux-and-freebsd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extended Notes on AncientFS</title>
		<link>http://www.osxbook.com/blog/2008/12/17/extended-notes-on-ancientfs/</link>
		<comments>http://www.osxbook.com/blog/2008/12/17/extended-notes-on-ancientfs/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 12:17:01 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacFUSE]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=269</guid>
		<description><![CDATA[Here are some extended notes on understanding, compiling, and using AncientFS, the file system I talked about in the previous blog post.
]]></description>
			<content:encoded><![CDATA[<p>Here are <a href="http://osxbook.com/software/ancientfs/" title="AncientFS: Ancient Unix File Systems on Mac OS X">some extended notes</a> on understanding, compiling, and using AncientFS, the file system I talked about in the <a href="http://www.osxbook.com/blog/2008/12/16/more-user-space-file-system-goodies/" title="More User-Space File System Goodies">previous blog post</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/17/extended-notes-on-ancientfs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More User-Space File System Goodies</title>
		<link>http://www.osxbook.com/blog/2008/12/16/more-user-space-file-system-goodies/</link>
		<comments>http://www.osxbook.com/blog/2008/12/16/more-user-space-file-system-goodies/#comments</comments>
		<pubDate>Tue, 16 Dec 2008 20:46:09 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacFUSE]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=284</guid>
		<description><![CDATA[There has been much buzz about new features and functionality in MacFUSE 2.0. Besides the MacFUSE 2.0 release, there are still more new and interesting things to be discussed in the realm of user-space file systems. As I described and briefly demonstrated during my recent talk at the Googleplex, I wrote several new user-space file [...]]]></description>
			<content:encoded><![CDATA[<p>There has been much buzz about <a href="http://code.google.com/p/macfuse/wiki/CHANGELOG" title="MacFUSE 2.0 Changes">new features and functionality</a> in MacFUSE 2.0. Besides the MacFUSE 2.0 release, there are still more new and interesting things to be discussed in the realm of user-space file systems. As I described and briefly demonstrated during my recent talk at the Googleplex, I wrote several new user-space file systems to &quot;celebrate&quot; two years of MacFUSE.</p>
<p>Now that the talk&#8217;s video is available. I&#8217;ve written some notes on the new file systems themselves. There is a lot of new information <em>and</em> new code for those interested in file systems, Mac OS X, and operating systems in general. Much of it is academically and practically useful, and some could have significant potential down the road. You could also think of it as a new year gift to the Mac OS X and open-source communities.</p>
<p>This is a meta note on how you can go about discovering and understanding the <em>what</em>, <em>how</em>, and <em>why</em> of everything I&#8217;m talking about.</p>
<h3>1. MacFUSE State of the Union Talk (2008) Video</h3>
<p>If you were not at the talk, <a href="http://www.youtube.com/watch?v=cY8lBOSO3ak" title="MacFUSE State of the Union Talk (2008) Video">watching the video</a> would provide useful context and should help greatly in understanding what follows.</p>
<h3>2. AncientFS</h3>
<p>Next, you could look at AncientFS, which I introduced, among other things, during the talk. AncientFS lets you mount ancient (and in some cases, current-day) &quot;data containers&quot; as regular volumes on Mac OS X. It supports the following formats.</p>
<ul style="list-style: square;">
<li><strong>v1tap</strong>&mdash;DECtape <code>tap</code> tape archive; UNIX V1</li>
<li><strong>v2tap</strong>&mdash;DECtape <code>tap</code> tape archive; UNIX V2</li>
<li><strong>v3tap</strong>&mdash;DECtape <code>tap</code> tape archive; UNIX V3</li>
<li><strong>ntap</strong>&mdash;DECtape/magtape <code>tap</code> tape archive; 1970 epoch</li>
<li><strong>tp</strong>&mdash;DECtape/magtape <code>tp</code> tape archive</li>
<li><strong>itp</strong>&mdash;UNIX <code>itp</code> tape archive</li>
<li><strong>dtp</strong>&mdash;UNIX <code>dtp</code> tape archive</li>
<li><strong>dump</strong>&mdash;Incremental file system dump (512-byte blocks, V7/bsd)</li>
<li><strong>dump1kI</strong>&mdash;Incremental file system dump (1024-byte blocks, V7/bsd)</li>
<li><strong>dump-vn</strong>&mdash;Incremental file system dump (512-byte blocks, bsd-vn)</li>
<li><strong>dump1k-vn</strong>&mdash;Incremental file system dump (1024-byte blocks, bsd-vn)</li>
<li><strong>v1ar</strong>&mdash;Very old (<code>0177555</code>) archive (<code>.a</code>) from First Edition UNIX</li>
<li><strong>v2ar</strong>&mdash;Very old (<code>0177555</code>) archive (<code>.a</code>) from Second Edition UNIX</li>
<li><strong>v3ar</strong>&mdash;Very old (<code>0177555</code>) archive (<code>.a</code>) from Third Edition UNIX</li>
<li><strong>ar</strong>&mdash;Current (<code>!&lt;arch&gt;\n</code>), old (<code>0177545</code>), or very old (<code>0177555</code>) archive (<code>.a</code>); use (v1|v2|v3)ar for UNIX V1/V2/V3 archives</li>
<li><strong>bcpio</strong>&mdash;Binary cpio archive (old); may be byte-swapped</li>
<li><strong>cpio_odc</strong>&mdash;ASCII (odc) cpio archive</li>
<li><strong>cpio_newc</strong>&mdash;New ASCII (newc) cpio archive</li>
<li><strong>cpio_newcrc</strong>&mdash;New ASCII (newc) cpio archive with checksum</li>
<li><strong>tar</strong>&mdash;ustar, pre-POSIX ustar, or V7 tar archive</li>
<li><strong>v1</strong>&mdash;First Edition UNIX file system</li>
<li><strong>v2</strong>&mdash;Second Edition UNIX file system</li>
<li><strong>v3</strong>&mdash;Third Edition UNIX file system</li>
<li><strong>v4</strong>&mdash;Fourth Edition UNIX file system</li>
<li><strong>v5</strong>&mdash;Fifth Edition UNIX file system</li>
<li><strong>v6</strong>&mdash;Sixth Edition UNIX file system</li>
<li><strong>v7</strong>&mdash;Seventh Edition UNIX file system</li>
<li><strong>v10</strong>&mdash;Tenth Edition UNIX file system</li>
<li><strong>32v</strong>&mdash;UNIX/32V file system</li>
<li><strong>bsd</strong>&mdash;BSD file system (V7-style with fixed-length file names; e.g. 2.9BSD or 4.0BSD)</li>
<li><strong>bsd-vn</strong>&mdash;BSD file system (pre fast-file-system &#8220;UFS&#8221; with variable-length file names; e.g. 2.11BSD for PDP-11)</li>
</ul>
<p>To learn more about AncientFS and how to use it, please read the <a href="http://osxbook.com/software/ancientfs/" title="AncientFS: Ancient Unix File Systems on Mac OS X">AncientFS article</a>. Enjoy seeing ancient data seamlessly in the modern namespaces of Mac OS X!</p>
<h3>3. The UnixFS Layer</h3>
<p>AncientFS also led to UnixFS, a general-purpose abstraction layer that proved useful in getting several other &quot;alien&quot; file systems up and running on Mac OS X. It is particularly useful for &quot;Unix-style&quot; file systems, where you need concepts such as on-disk and in-memory superblocks and inodes. As I mentioned during the talk, I used UnixFS in conjunction with ad-hoc &quot;Linux emulation&quot; to bring support for the UFS, System V, and Minix file system families on Mac OS X. That amounts to a large number of new file systems, but it was easier than it sounds because the idea was to take existing Linux kernel implementations of these file system families and make them work <em>in user space</em> on Mac OS X!</p>
<p>UnixFS is currently rather &quot;beta&quot; and not a formal API by any means. Since it is a programming interface and doesn&#8217;t do anything by itself, it will be of interest only to developers at this point. In future, it may also evolve into a &quot;LinuxFS&quot; layer that could make it even easier and faster to <em>systematically</em> make Linux kernel-based file systems work on other platforms with very few code changes. For now, you can browse some <a href="http://code.google.com/p/macfuse/source/browse/#svn/trunk/filesystems/unixfs/common/" title="UnixFS Source Code">bits of code</a>.</p>
<p>You <em>can</em>, however, use the aforementioned UnixFS-based file system families: UFS, System V, and Minix. To do so, check out the relevant part of the MacFUSE source tree and compile one or more (or all) of the UnixFS-based file systems&mdash;it is quite straightforward: a single <code>make</code> in the <code>filesystems/unixfs/</code> subdirectory in the MacFUSE source tree should build all of them. (You must have MacFUSE installed, of course.)</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>svn co http://macfuse.googlecode.com/svn/trunk/filesystems/unixfs</strong>
$ <strong>cd unixfs</strong>
$ <strong>ls -F</strong>
Makefile	common/		sysvfs/
ancientfs/	minixfs/	ufs/
$ <strong>make</strong>
...
$
</pre>
<p></code></p>
<h3>4. The UFS Family</h3>
<p><a href="http://code.google.com/p/macfuse/source/browse/#svn/trunk/filesystems/unixfs/ufs/" title="UFS Source Code">This is a user-space implementation</a> (read-only) of the UFS file system family. Most of the UFS-specific code comes from the Linux kernel and is largely unchanged. Specific UFS flavors supported are as follows.</p>
<ul style="list-style: square;">
<li><code>old</code>&mdash;the oldest UFS format</li>
<li><code>sun</code>&mdash;used in SunOS/Solaris</li>
<li><code>sunx86</code>&mdash;used in the x86 versions of SunOS/Solaris</li>
<li><code>hp</code>&mdash;used in HP-UX</li>
<li><code>nextstep</code>&mdash;used in NEXTSTEP</li>
<li><code>nextstep-cd</code>&mdash;used in NEXTSTEP CDROMs</li>
<li><code>openstep</code>&mdash;used in OPENSTEP</li>
<li><code>44bsd</code>&mdash;used in FreeBSD, NetBSD, OpenBSD, and Mac OS X</li>
<li><code>ufs2</code>&mdash;used in FreeBSD 5.x</li>
</ul>
<h3>5. The System V Family</h3>
<p><a href="http://code.google.com/p/macfuse/source/browse/#svn/trunk/filesystems/unixfs/sysvfs/" title="SysVFS Source Code">This is a user-space implementation</a> (read-only) of the System V file system family. Most of the sysvfs-specific code comes from the Linux kernel and is largely unchanged. Specific sysvfs flavors supported are as follows.</p>
<ul style="list-style: square;">
<li><code>svr2</code>&mdash;used in SVR2</li>
<li><code>svr4</code>&mdash;used in SVR4</li>
<li><code>xenix</code>&mdash;used in Xenix</li>
<li><code>coherent</code>&mdash;used in Coherent Unix</li>
</ul>
<h3>6. The Minix Family</h3>
<p><a href="http://code.google.com/p/macfuse/source/browse/#svn/trunk/filesystems/unixfs/minixfs/" title="MinixFS Source Code">This is a user-space implementation</a> (read-only) of the Minix file system family. Most of the minixfs-specific code comes from the Linux kernel and is largely unchanged.</p>
<p style="border-top: 1px solid #C0C0C0; padding-top: 1em;">
The following image summarizes the new file system capabilities Mac OS X gets as a result of these exercises.
</p>
<p>
<center><br />
<img src="http://osxbook.com/images/blog/manynewfs.png"/><br />
</center>
</p>
<h3>7. The &quot;One More Thing&quot; Thing</h3>
<p>Although it isn&#8217;t directly file system related, the last thing I demonstrated during the talk was the ability to run ancient Unix (PDP-11) binaries seamlessly on Mac OS X. PDP-11 aside, the techniques used to do so are generally useful for research and experimentation because unlike Linux, Mac OS X does <em>not</em> allow developers to extend the set of binary formats that can be &quot;natively&quot; executed by the kernel. The demo shows the Fifth Edition Unix kernel being compiled on Mac OS X using the original C compiler toolchain from a Fifth Edition disk image mounted using AncientFS. Additionally, there&#8217;s an &quot;authentic&quot; reproduction of the following ominous error message by running the original <code>mv</code> executable from Sixth Edition Unix.</p>
<p><code></p>
<pre>
	values of &beta; will give rise to dom!
</pre>
<p></code></p>
<p>For more details, please watch the last section of the talk video. This is very preliminary work for which no source code or binaries are available yet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/16/more-user-space-file-system-goodies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Note on Automounting MacFUSE File Systems</title>
		<link>http://www.osxbook.com/blog/2008/12/11/a-note-on-automounting-macfuse-file-systems/</link>
		<comments>http://www.osxbook.com/blog/2008/12/11/a-note-on-automounting-macfuse-file-systems/#comments</comments>
		<pubDate>Thu, 11 Dec 2008 10:50:20 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacFUSE]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=260</guid>
		<description><![CDATA[Mac OS X, like many other Unix-like operating systems, includes the &#8220;autofs&#8221; file system layer that make automatic on-demand mounting of remote resources possible. See the man page for automount(8) for more details.
Such automatic mounting is orthogonal to and possible with MacFUSE. (NB: You will need MacFUSE 2.0 or above for this to work properly [...]]]></description>
			<content:encoded><![CDATA[<p>Mac OS X, like many other Unix-like operating systems, includes the &#8220;autofs&#8221; file system layer that make automatic on-demand mounting of remote resources possible. See the man page for <code>automount(8)</code> for more details.</p>
<p>Such automatic mounting is orthogonal to and possible with MacFUSE. (<strong>NB:</strong> You will need MacFUSE 2.0 or above for this to work properly since older versions of MacFUSE filter out the &#8220;automounted&#8221; mount-time argument.) Consider <a href="http://code.google.com/p/macfuse/wiki/MACFUSE_FS_SSHFS" title="sshfs"><code>sshfs</code></a>, a user-space SFTP file system implementation that works with MacFUSE. The following is a quick-and-dirty example of how you could set up an autofs mount for <code>sshfs</code>. (There are other ways to set up autofs mounts.)</p>
<p>Create an <code>/etc/fstab</code> file (or add to an existing one) with the following entry. We will create what&#8217;s called a &#8220;static map&#8221; in autofs parlance.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>cat /etc/fstab</strong>
dummy:<span style="background-color: #00ff00;">user</span>@<span style="background-color: #00ff00;">host</span>:/<span style="background-color: #00ff00;">remotedir</span> /Network/<span style="background-color: #00ff00;">name</span> sshfs volname=<span style="background-color: #00ff00;">volname</span>,allow_other 0 0
</pre>
<p></code></p>
<p>You will have to customize the green highlighted components. <code>user</code>, <code>host</code>, and <code>remotedir</code> are the SFTP user name, the SFTP server host name, and the remote directory on the SFTP server, respectively. You can choose some reasonable value for <code>name</code> and <code>volname</code>. The local mount point will be <code>/Network/name</code>.</p>
<p>Next, to keep things simple, configure key-based authentication to the SFTP server so you can log in without having to type your password.</p>
<p>The keyword &#8220;sshfs&#8221; in the <code>/etc/fstab</code> entry is the type of the file system. Given a file system type <code>foo</code>, the automounter will expect a <code>mount_foo</code> file-system-specific mounting program to exist. In our case, we don&#8217;t have a separate mounting program for <code>sshfs</code>. However, because of the format of the entry and how the automounter passes arguments to the mounting program, it will work if you simply copy the command-line <code>sshfs</code> program  to <code>/sbin/mount_sshfs</code>. Alternatively, you can create a symbolic link as follows.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>which sshfs</strong>
$ /usr/local/bin/sshfs
$ sudo ln -s /usr/local/bin/sshfs /sbin/mount_sshfs
</pre>
<p></code></p>
<p>That should be it. Run the <code>automount</code> program to update the state of things. The <code>-c</code> argument tells the automount daemon to flush any cached information.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo automount -c</strong>
</pre>
<p></code></p>
<p>If everything went well, the new mount should appear in the output of the <code>mount</code> command. In the following example, we used <code>SSH</code> as the name component of the mount point.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>mount</strong>
...
map -static on /Network/SSH (autofs, automounted)
</pre>
<p></code></p>
<p>Now, if you simply access <code>/Network/SSH</code>, the SFTP file system should be automatically mounted.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>ls /Network/SSH</strong>
Applications		Volumes			work
Desktop DB		bin			private
...
</pre>
<p></code></p>
<p>If there is an error in mounting (say, the remote host is not reachable), you will not be permitted to access the <code>/Network/SSH</code> directory.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>ls /Network/SSH</strong>
ls: SSH: Operation not permitted
</pre>
<p></code></p>
<p>You can specify a timeout period after which an automounted file system will be unmounted if it has not been accessed within that period. Either use the <code>-t</code> argument of <code>automount</code> or see the <code>/etc/autofs.conf</code> file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/11/a-note-on-automounting-macfuse-file-systems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VeryBigFS: All You Can Read</title>
		<link>http://www.osxbook.com/blog/2008/12/10/verybigfs-all-you-can-read/</link>
		<comments>http://www.osxbook.com/blog/2008/12/10/verybigfs-all-you-can-read/#comments</comments>
		<pubDate>Wed, 10 Dec 2008 14:44:51 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[MacFUSE]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=244</guid>
		<description><![CDATA[VeryBigFS is a trivial MacFUSE file system&#8212;about 60 lines of C code&#8212;that creates a huge volume with a huge file in it. &#8220;Huge&#8221; would be 512TB in this case.
This is useful if you want to see how a program will deal with unusually large files. Since it is extremely unlikely for the majority of us [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/macfuse/source/browse/trunk/filesystems/verybigfs/verybigfs.c" title="VeryBigFS Source Code">VeryBigFS</a> is a trivial MacFUSE file system&mdash;about 60 lines of C code&mdash;that creates a <em>huge</em> volume with a <em>huge</em> file in it. &#8220;Huge&#8221; would be 512TB in this case.</p>
<p>This is useful if you want to see how a program will deal with unusually large files. Since it is extremely unlikely for the majority of us to be able to <em>actually</em> create files that are 512TB in size any time in the near future, faking is the way to go. Assuming you have MacFUSE installed, here is how you can try this file system.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>ls</strong>
Makefile	verybigfs.c
$ <strong>make</strong>
...
$ <strong>mkdir "/Volumes/Very Big HD"</strong>
$ <strong>./verybigfs "/Volumes/Very Big HD"</strong>
$ <strong>ls -lh</strong>
...
-r--r--r--  1 singh  wheel   512T Nov 28 05:38 copyme.txt
</pre>
<p></code></p>
<p style="background-color: #e0e0f4;">
As an aside, note that HFS+ does not support sparse files. In fact, if you create a large scratch file on HFS+, it will be zero filled &#8220;soon&#8221;. This can take a long time depending upon the file size, the hardware, and the resources available. Mac OS X provides a way for a privileged process to set a file&#8217;s size without zero filling: it&#8217;s the <code>F_SETSIZE</code> command of the <code>fcntl()</code> system call.
</p>
<p>Here is what the Finder tells you about the file <code>copyme.txt</code> inside the volume.</p>
<p><center><br />
<img src="/images/blog/verybigfs.png" title="VeryBigFS in the Finder"/><br />
</center></p>
<p>Note that although the tantalizingly named file is fictitious in that it doesn&#8217;t occupy any real disk space, you <em>will</em> read 512TB of zero-filled data if you choose to do so.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>od -Xv copyme.txt</strong>
...
1357500          00000000        00000000        00000000        00000000
1357520          00000000        00000000        00000000        00000000
1357540          00000000        00000000        00000000        00000000
1357560          00000000        00000000        00000000        00000000
1357600          00000000        00000000        00000000        00000000
...
# A very, very, very long undetermined length of time...
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/10/verybigfs-all-you-can-read/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MacFUSE 2.0 is Here!</title>
		<link>http://www.osxbook.com/blog/2008/12/08/macfuse-20-is-here/</link>
		<comments>http://www.osxbook.com/blog/2008/12/08/macfuse-20-is-here/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 23:42:48 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacFUSE]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=275</guid>
		<description><![CDATA[It was a little over two years ago that I gave serious thought to making user-space file systems a reality on Mac OS X. The result of that work, MacFUSE, was introduced at the Macworld conference in January 2007. Since then, MacFUSE has come a long way. It&#8217;s been used in projects big and small [...]]]></description>
			<content:encoded><![CDATA[<p>It was a little over two years ago that I gave serious thought to making user-space file systems a reality on Mac OS X. The result of that work, <a href="http://code.google.com/p/macfuse/" title="MacFUSE Project Page">MacFUSE</a>, was introduced at the Macworld conference in January 2007. Since then, MacFUSE has come a long way. It&#8217;s been used in projects big and small and has made numerous existing (on other platforms) and new file systems possible on Mac OS X.</p>
<div style="background-color: #EAEAF4; padding: 1em;">
MacFUSE is a native file system for Mac OS X&mdash;&#8221;native&#8221; means that it lives in the kernel, like HFS+ and AFP. However, MacFUSE doesn&#8217;t ultimately provide the file system content itself&mdash;it communicates with a standard Mac OS X application to read or write the actual file system content. Thus, MacFUSE is a file system that lets you write file systems. To do so, a developer would use one of the APIs provided by MacFUSE. MacFUSE 2.0 provides multiple APIs including, but not limited to, the FUSE API from Linux.
</div>
<p><a href="http://code.google.com/p/macfuse/downloads/list" title="Download MacFUSE">MacFUSE 2.0</a> is a major update to MacFUSE. We&#8217;ll be discussing what&#8217;s new in MacFUSE 2.0 in <a href="http://google-opensource.blogspot.com/2008/12/open-source-developers-google-speaker.html" title="MacFUSE State of the Union Talk">a talk at Google&#8217;s Mountain View headquarters</a> today. For those who can&#8217;t be at the talk, there are two versions of the &#8220;what&#8217;s new&#8221; description.</p>
<p>The Apple-style version is easy to state: <em>&#8220;improvements and bug-fixes.&#8221;</em></p>
<p>Alternatively, you can read the <a href="http://code.google.com/p/macfuse/wiki/CHANGELOG" title="MacFUSE CHANGELOG">CHANGELOG</a> in its entirety at the project&#8217;s web site.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/08/macfuse-20-is-here/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MacFUSE Talk at Google</title>
		<link>http://www.osxbook.com/blog/2008/12/02/macfuse-talk-at-google/</link>
		<comments>http://www.osxbook.com/blog/2008/12/02/macfuse-talk-at-google/#comments</comments>
		<pubDate>Tue, 02 Dec 2008 21:08:13 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[MacFUSE]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=266</guid>
		<description><![CDATA[Next Monday (December 8, 2008), there will be an open-to-all talk on MacFUSE at Google&#8217;s Mountain View headquarters. Here is a more detailed announcement.
]]></description>
			<content:encoded><![CDATA[<p>Next Monday (December 8, 2008), there will be an open-to-all talk on MacFUSE at Google&#8217;s Mountain View headquarters. <a href="http://google-opensource.blogspot.com/2008/12/open-source-developers-google-speaker.html" title="MacFUSE Tech Talk at Google">Here</a> is a more detailed announcement.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/12/02/macfuse-talk-at-google/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Note on Pathname Processing in HFSDebug</title>
		<link>http://www.osxbook.com/blog/2008/11/24/a-note-on-pathname-processing-in-hfsdebug/</link>
		<comments>http://www.osxbook.com/blog/2008/11/24/a-note-on-pathname-processing-in-hfsdebug/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 12:18:43 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=193</guid>
		<description><![CDATA[A couple of weeks ago, I released HFSDebug 4. I&#8217;ve updated it to make HFSDebug&#8217;s pathname processing a little more sophisticated. Depending on how (and how seriously) you use HFSDebug, knowing the details could be useful.
When you specify a file system object to HFSDebug using a pathname, how HFSDebug will treat the pathname usually depends [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of weeks ago, I released <a href="http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/" title="HFSDebug 4 and New HFS+ Features">HFSDebug 4</a>. I&#8217;ve updated it to make HFSDebug&#8217;s pathname processing a little more sophisticated. Depending on how (and how seriously) you use HFSDebug, knowing the details could be useful.</p>
<p>When you specify a file system object to HFSDebug using a pathname, how HFSDebug will treat the pathname usually depends on other arguments, or the lack of other arguments.</p>
<h3>Something to Read and Forget: The &#8220;Legacy&#8221; Mode</h3>
<p>A typical invocation is quite simple: you simply give HFSDebug a path. If the path exists on an HFS+ volume, HFSDebug will use the underlying volume as the one to operate upon.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug /mach_kernel</strong>
...
</pre>
<p></code></p>
<p>In this case, HFSDebug will begin by doing a <code>stat(2)</code> call on the path. <em>(As you will see shortly, this and the entire &#8220;legacy mode&#8221; is optional&mdash;you can make HFSDebug do even this part &#8220;from scratch&#8221; and not use <code>stat(2)</code> or other file system calls on the volume.)</em> Since the goal is to make it possible to examine file system&#8217;s <em>internal</em> structure as opposed to what the user &#8220;sees&#8221; through layers of interfaces, it matters whether the object in question is a file hard link, directory hard link, symbolic link, etc. Specifically, we need to get at the link <em>reference</em> that the pathname represents&mdash;not the <em>target</em> it resolves to. For symbolic links, we can use <code>lstat(2)</code> to give us the node ID of the reference. For file and directory hard links, we have to use something else.</p>
<p>How do we know if something is a hard link? HFSDebug examines the <code>st_nlink</code> (link count) and <code>st_mode</code> fields of the resultant <code>stat</code> structure.</p>
<p>In the case of regular files, a link count of 2 or higher means the object is a &#8220;known&#8221; hard link.</p>
<p>In the case of directories, what &#8220;link count&#8221; means is quite context-sensitive on HFS+. The <code>stat</code> structure&#8217;s <code>st_nlink</code> for a directory normally represents the directory&#8217;s <em>item count</em>. The directory itself (the <code>"." </code> entry) and its parent (the <code>".."</code> entry) together add 2 to the count. Thus, if you have a directory with, say, 4 files and 4 subdirectories in it, a <code>stat(2)</code> call would report an <code>st_nlink</code> value of 10. However, if the <em>folder count</em> bit is enabled on the mount, the meaning of <code>st_nlink</code> changes: it then represents a count of only the subdirectories. In the aforementioned example, the link count would be 6 instead of 10. The folder count bit is currently only enabled for case-sensitive (HFSX) volumes. Besides the <code>stat</code> structure&#8217;s <code>st_nlink</code> field, HFS+ can separately provide the <em>children count</em> and the <em>real hard link count</em> for directories. The <code>getattrlist(2)</code> call can be used to retrieve these: they are the <code>ATTR_DIR_ENTRYCOUNT</code> and <code>ATTR_DIR_LINKCOUNT</code> directory attributes, respectively. Once we do know a directory&#8217;s &#8220;real&#8221; hard link count, again, a value of 2 or higher means it is a &#8220;known&#8221; hard link.</p>
<p>By a &#8220;known&#8221; file or directory hard link, I mean that we know that it <em>currently is</em> a hard link. That means the object we are looking at is a link reference and the &#8220;visible&#8221; node ID isn&#8217;t that of the reference but is that of its target. (See my <a href="http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/" title="HFSDebug 4 and New HFS+ Features">previous post</a> for more information.) In this case, HFSDebug will retrieve the object&#8217;s parent folder&#8217;s node ID and use it in conjunction with the object&#8217;s name to do a &#8220;from scratch&#8221; lookup of the object&#8217;s node ID. (This is a traditional <code>{ parent_nodeid, name } ==> nodeid</code> lookup.)</p>
<p>However, things are <em>not</em> simpler if the link count of the object is 1. That&#8217;s because it could have <em>had</em> a higher link count in the past and the other links were deleted. Again, as I described <a href="http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/" title="HFSDebug 4 and New HFS+ Features">earlier</a>, the on-disk object continues to be a reference to the real content that lives in a special hidden HFS+ folder. If that&#8217;s the case though, the hidden folder will have a file or a folder whose name is formed from the object&#8217;s visible node ID: <code>iNode%d</code> or <code>dir_%d</code> for files and folders, respectively. If no such file or folder exists, as HFSDebug can look up from scratch, the object is not a current <em>or past</em> hard link.</p>
<p>If this sounds unnecessarily complex, well, some of it is. Until version 4, HFSDebug did not have the ability to process complete pathnames from scratch. With version 4, you can do things like the following on both mounted and unmounted volumes alike.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug -d /dev/disk0s2 /mach_kernel</strong>
...
</pre>
<p></code></p>
<h3>Simpler, Better</h3>
<p>In the new mode, HFSDebug will no longer do a <code>stat(2)</code>/<code>lstat(2)</code> or involve the file system otherwise. Obviously, if it has to support unmounted volumes, that&#8217;s how it has to be. It will take the pathname and process it component-by-component, which is easier to conceptualize than the &#8220;legacy&#8221; mode I described above. (Well, to be fair to the legacy mode, it became uglier with the advent of directory hard links.)</p>
<p>The following are examples of how HFSDebug will handle things based on some of its arguments.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug /foo/bar/baz</strong>
# legacy mode; will use stat(2)/lstat(2) to kick things off
...
$ <strong>sudo hfsdebug -d /dev/diskN /foo/bar/baz</strong>
# new mode; volume can be mounted or unmounted
...
$ <strong>sudo hfsdebug -P /foo/bar/baz</strong>
# new mode; uses root volume, which is obviously mounted
...
$ <strong>sudo hfsdebug -d /dev/diskN -P /foo/bar/baz</strong>
# new mode; volume can be mounted or unmounted
</pre>
<p></code></p>
<div style="background-color: #eaeaf4; border: 1px solid #c0c0ff; padding: 1em;">
If you are wondering why I haven&#8217;t removed the legacy mode altogether, it&#8217;s because I want to keep it around for some time so that I can compare things while testing.
</div>
<p>Just remember that you can use the <code>-P</code> argument (note that it&#8217;s the capital <code>P</code>) to specify a path and HFSDebug will use the new mode on both mounted and unmounted volumes. The path must be absolute.</p>
<h3>Some Rules</h3>
<p>Now, if HFSDebug is not involving the file system at all, it better be able to handle arbitrarily convoluted pathnames. Using things like <code>realpath(3)</code> is not an option since <code>realpath(3)</code> would want to call <code>stat(2)</code>/<code>lstat(2)</code>. Say, we could have a path like the following.</p>
<p><code>/foo////././bar///../baz/../blah/..//////.././dir/are/you/../crazy/</code></p>
<p>Besides, there could be components in the path that are symbolic or hard links. Symbolic links could point to targets that have equally crazy pathnames. It&#8217;s not just a matter of canonicalizing the dots and the slashes. We have several requirements as illustrated by the following examples. (Some of these are simply HFSDebug conventions.)</p>
<ul style="list-style: square;">
<li>We must ensure that all intermediate components resolve to directories. They can be actual directories, valid symbolic links to directories, or directory hard links. <a href="http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/">Remember</a> that in the case of symbolic or hard links, the on-disk object will be a &#8220;file&#8221;&mdash;HFSDebug will need to resolve them from scratch too.</li>
<li>If there is a &#8220;..&#8221;, we must not blindly go &#8220;up&#8221; one level: we must ensure that what we are going back from <em>is</em> a directory. <code>realpath(3)</code> actually doesn&#8217;t care about this: it will canonicalize <code>/path/to/file.txt/../file.txt</code> to <code>/path/to/file.txt</code>.</li>
<li>Although we do want to resolve intermediate components that are links, we must not resolve the terminal component if it happens to be a hard link or a symbolic link. That&#8217;s because our goal is to look at what&#8217;s on disk for the given path. Besides, in the case of a link, the details shown by HFSDebug <em>will</em> include the full pathname to the link&#8217;s target. If we wanted further details on the target, we could run HFSDebug on it.</li>
<li>If the path has a terminal slash, HFSDebug will ensure that the component is a directory. If it happens to be a directory hard link or a symbolic link, HFSDebug <em>will</em> resolve it in this case. Consider an example: suppose there is a symbolic link <code>/tmp/somesymlink</code>. The following is what HFSDebug will do depending on the arguments and what the link points to.</li>
</ul>
<p><code></p>
<pre style="font-size: 85%;">
# somesymlink points to a file
#
$ <strong>sudo hfsdebug -P /tmp/somesymlink</strong>
... # will show details of the link itself
$ <strong>sudo hfsdebug -P /tmp/somesymlink/</strong>
... # will complain that the link target is not a directory

# somesymlink points to a directory
#
$ <strong>sudo hfsdebug -P /tmp/somesymlink</strong>
... # will show details of the link itself
$ <strong>sudo hfsdebug -P /tmp/somesymlink/</strong>
... # will show details of the directory somesymlink points to

# somesymlink points to a non-existent target
#
$ <strong>sudo hfsdebug -P /tmp/somesymlink</strong>
... # will show details of the link itself
$ <strong>sudo hfsdebug -P /tmp/somesymlink/</strong>
... # will complain that path /tmp/somesymlink/ was not found on the volume
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/11/24/a-note-on-pathname-processing-in-hfsdebug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HFSDebug 4.0 and New HFS+ Features</title>
		<link>http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/</link>
		<comments>http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 03:00:07 +0000</pubDate>
		<dc:creator>amit</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Operating Systems]]></category>

		<guid isPermaLink="false">http://www.osxbook.com/blog/?p=106</guid>
		<description><![CDATA[I wrote HFSDebug in early 2004. I initially made it available as a software tool to help understand fragmentation in HFS+ volumes, although it could also be used to analyze several implementation details of HFS+. Eventually, I extended HFSDebug to be able to analyze all on-disk aspects of HFS+, along with the ability to compute [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote <a href="http://osxbook.com/software/hfsdebug/" title="HFSDebug">HFSDebug</a> in early 2004. I initially made it available as a software tool to help understand <a href="http://osxbook.com//software/hfsdebug/fragmentation.html" title="Fragmentation in HFS Plus Volumes">fragmentation in HFS+ volumes</a>, although it could also be used to analyze several implementation details of HFS+. Eventually, I extended HFSDebug to be able to analyze <em>all</em> on-disk aspects of HFS+, along with the ability to compute more types of volume statistics and to even retrieve some in-memory details of mounted HFS+ volumes.</p>
<p>HFSDebug has been an extremely useful tool for me. I&#8217;ve used it to help explain the workings of HFS+ in the <a href="http://osxbook.com" title="Mac OS X Internals: The Book">Mac OS X Internals</a> book, to understand occasional mysterious behavior in HFS+ volumes, to <a href="http://www.osxbook.com/blog/2008/07/23/extending-hfsdebug/" title="Extending HFSDebug">search for file system objects</a>, to generate interesting file system statistics (top N largest files, top N fragmented files, resource forks vs data forks, <a href="http://www.osxbook.com/software/hfsdebug/#FREESPACE" title="Determining Free Space Fragmentation with HFSDebug">contiguous free space</a>, and so on), and to create interesting demos. (For example, to show HFS+ mechanisms such as <em>Hot File Clustering</em> and <em>On-the-Fly Defragmentation</em> at work.)</p>
<p>HFS+ is the preferred and default volume format on Mac OS X. Even with exciting new developments such as ZFS support in Mac OS X, I don&#8217;t expect HFS+ to become obsolete any time soon. Today&#8217;s Macintosh computers, iPods, iPhones, and AppleTV&#8217;s all use HFS+.</p>
<p>With most major releases of Mac OS X, HFS+ has gained new capabilities. Features such as metadata journaling, on-the-fly file defragmentation, hot file clustering, extended attributes, access control lists, hard link chains (tracking hard links), and directory hard links have come to HFS+ in recent years. There have been &#8220;<a href="http://arstechnica.com/journals/apple.ars/2008/10/27/new-snow-leopard-build-released-with-partial-cocoa-finder">news</a> <a href="http://www.appleinsider.com/articles/08/10/25/new_snow_leopard_seed_leak_confirms_cocoa_finder_more.html">reports</a>&#8221; of <em>compression</em> being an upcoming feature in HFS+.</p>
<p>The most interesting technical things about HFS+ are not its features, but how several of the newer features are implemented. With the goal of retaining backward compatibility, new features have often been retrofitted, or <em>shoehorned</em>, if you will, into HFS+. Knowing such implementation details evokes different reactions in different people, ranging from <em>&#8220;That&#8217;s a nifty way to implement this!&#8221;</em> to <em>&#8220;Gross!&#8221;</em> This is something you can decide for yourself with the help of HFSDebug, which can show you <em>exactly</em> how the file system works.</p>
<h3>New Features in HFSDebug</h3>
<p>Now, every time a new feature is added to HFS+, HFSDebug likely (but not always) needs to be updated, say, to recognize and parse a new type of on-disk object such as a directory hard link. I&#8217;m releasing a <a href="http://osxbook.com/software/hfsdebug/#DOWNLOAD" title="Download HFSDebug">new version of HFSDebug</a> that has the following improvements.</p>
<ul style="list-style: square;">
<li>Ability to show details of directory hard links.</li>
<li>Ability to show details of hard link chains.</li>
<li>New <a href="http://osxbook.com/software/hfsdebug/#FILTERS" title="HFSDebug Filters">built-in filters</a>: <code>atime</code> (find files by access time), <code>dirhardlink</code> (list directory hard links), <code>hardlink</code> (list file hard links), and <code>sxid</code> (list setuid/setgid files).</li>
<li>Ability to do component-wise path lookup from scratch, allowing you to analyze individual file system objects by <em>path</em> even on unmounted HFS+ volume.</li>
<li>Support for Snow Leopard.</li>
<li>Numerous subtle improvements and some bugfixes.</li>
</ul>
<div style="background-color: #eaeaf4; border: 1px solid #c0c0ff; padding: 1em;">
<h3 style="border-bottom: 1px solid #808080;">Still a PowerPC binary!?</h3>
<p>
It may be surprising (or troubling) to some of you that there is still no x86 version of HFSDebug: it&#8217;s available only as a PowerPC executable. Well, there <em>is</em> some logic to this madness. You see, I wrote HFSDebug in the &#8220;Panther&#8221; (10.3) days. Mac OS X was PowerPC-only then. It was also big endian. That matters because HFS+ uses big endian for its on-disk structures.
</p>
<p>
HFSDebug is a complex program. It essentially reads raw data from an HFS+ disk (say, a partition on a real disk or a disk image) and recreates a read-only HFS+ file system in memory. To simplify matters, I decided to skip structure-by-structure, field-by-field endianness conversion&mdash;after all, I <em>was</em> only targeting the big-endian-only Mac OS X. By contrast, the xnu kernel&#8217;s HFS+ implementation <em>does</em> do byte swapping on x86. So does the <code>fsck_hfs</code> program.
</p>
<p>
As long as Rosetta exists, HFSDebug can get away with being a PowerPC executable, allowing me to defer the grunt work of swapping bytes to a later date.
</p>
</div>
<p>Let us take the new HFSDebug features for a spin.</p>
<h3>Hard Link Chains</h3>
<p>Although support for file hard links has been there in HFS+ before Leopard, the new chaining feature in Leopard can keep track of hard link chains, which are doubly linked list of file IDs connecting hard links together. Hard links to a file on HFS+ are conceptually similar to those on Unix systems: They represent multiple directory entries referring to common file content. Implementation-wise, HFS+ hard links use a special <em>hard-link file</em> for each directory entry. The common file content is stored in a special file: the <em>indirect-node file</em>. All indirect-node files are stored in the <em>private metadata folder</em>, a special directory (<code><nobr>/\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data</nobr></code>) that&#8217;s both normally invisible to the user and has a name that&#8217;s &#8220;hard&#8221; to type. It&#8217;s much easier to understand this through HFSDebug.</p>
<p>We begin by creating a file called <code>file1</code>. Before we create a hard link to this file, we examine its details using HFSDebug. That way, we can tell if anything about the file changes after link creation.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>mkdir /tmp/test/</strong>
$ <strong>cd /tmp/test</strong>
$ <strong>echo "This is file1" > file1</strong>
$ <strong>sudo hfsdebug file1</strong>
...
  path                 = Leopard HD:/private/tmp/test/file1
# Catalog File Record
  type                 = file
<span style="background-color: #00f000;">  file ID              = 1927091</span>
  flags                = 0000000000000010
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 501 (singh)
  groupID              = 0 (wheel)</span>
  adminFlags           = 00000000
<span style="background-color: #00f000;">  ownerFlags           = 00000000</span>
  fileMode             = -rw-r--r--
  linkCount            = 1
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
<span style="background-color: #00f000;">  fdType               = 0
  fdCreator            = 0
  fdFlags              = 0000000000000000</span>
...
</pre>
<p></code></p>
<p>Let us now make a hard link to this file.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>ln file1 file2</strong>
</pre>
<p></code></p>
<p>Let us see if anything has changed about <code>file1</code> now that we made a hard link <em>to</em> it.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug file1</strong>
...
  path                 = Leopard HD:/private/tmp/test/file1
# Catalog File Record
  type                 = file (hard link)
  indirect node file   = Leopard HD:/%0000%0000%0000%0000HFS+ Private Data/iNode1927091
<span style="background-color: #00f000;">  file ID              = 1927094</span>
  flags                = 0000000000100010
                       . File has a thread record in the catalog.
<span style="background-color: #00f000;">                       . File has hardlink chain.</span>
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 1927095 (previous link ID)
  groupID              = 0 (next link ID)</span>
  adminFlags           = 00000000
<span style="background-color: #00f000;">  ownerFlags           = 00000010
                       . UF_IMMUTABLE (file may not be changed)</span>
  fileMode             = -r--r--r--
<span style="background-color: #00f000;">  iNodeNum             = 1927091 (link reference number)</span>
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
<span style="background-color: #00f000;">  fdType               = 0x686c6e6b (hlnk)
  fdCreator            = 0x6866732b (hfs+)
  fdFlags              = 0000000100000000
                       . kHasBeenInited</span>
...
  # Data Fork
  logicalSize          = 0 bytes
  # Resource Fork
  logicalSize          = 0 bytes
</pre>
<p></code></p>
<p>We see that a <em>lot</em> has changed! The on-disk nature of <code>file1</code> has completely transformed. The original <code>content</code> has actually &#8220;moved&#8221; to an indirect-node file. What was <code>file1</code> before has been replaced with a new directory entry altogether: one that has a new file ID <em>within the file system</em>. The new directory entry is also a file, but with several special properties. Its &#8220;type&#8221; and &#8220;creator&#8221; (as stored in the Finder Info) are <code>hlnk</code> and <code>hfs+</code>, respectively. It has been marked immutable. It has no content in either its data fork or its resource fork. Moreover, the owner and group ID on-disk fields have been repurposed to act as the previous and next links, respectively, in the hard link chain. We see that the previous link ID is 1927095. Let us use HFSDebug to show us information for that ID.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug -c 1927095</strong>
...
  path                 = Leopard HD:/private/tmp/test/file2
# Catalog File Record
  type                 = file (hard link)
  indirect node file   = Leopard HD:/%0000%0000%0000%0000HFS+ Private Data/iNode1927091
<span style="background-color: #00f000;">  file ID              = 1927095</span>
  flags                = 0000000000100010
                       . File has a thread record in the catalog.
<span style="background-color: #00f000;">                       . File has hardlink chain.</span>
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 0 (previous link ID)
  groupID              = 1927094 (next link ID)</span>
  adminFlags           = 00000000
<span style="background-color: #00f000;">  ownerFlags           = 00000010
                       . UF_IMMUTABLE (file may not be changed)</span>
  fileMode             = -r--r--r--
<span style="background-color: #00f000;">  iNodeNum             = 1927091 (link reference number)</span>
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
<span style="background-color: #00f000;">  fdType               = 0x686c6e6b (hlnk)
  fdCreator            = 0x6866732b (hfs+)
  fdFlags              = 0000000100000000
                       . kHasBeenInited</span>
...
  # Data Fork
  logicalSize          = 0 bytes
  # Resource Fork
  logicalSize          = 0 bytes
</pre>
<p></code></p>
<p>We see that ID 1927095 corresponds to the other reference we just created: <code>file2</code>. The properties of this reference are similar to those of the other reference <code>file1</code>. They do differ in their file IDs. (They are indeed two separate on-disk file system objects.) They also differ in their previous and next links in the hard link chain. (We can confirm that <code>file1</code> and <code>file2</code> are connected together.)</p>
<p>The file&#8217;s content is in the indirect node file, which also now is the on-disk object with the original file ID (1927091). Let us use HFSDebug to look at that file.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug -c 1927091</strong>
...
  path                 = Leopard HD:/%0000%0000%0000%0000HFS+ Private Data/iNode1927091
# Catalog File Record
  type                 = file
<span style="background-color: #00f000;">  file ID              = 1927095
  flags                = 0000000000100010
                       . File has a thread record in the catalog.
                       . File has hardlink chain.
  reserved1            = 1927095 (first link ID)</span>
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 501 (singh)
  groupID              = 0 (wheel)</span>
  adminFlags           = 00000000
  ownerFlags           = 00000000
...
  # Finder Info
<span style="background-color: #00f000;">  fdType               = 0x686c6e6b (hlnk)
  fdCreator            = 0x6866732b (hfs+)
  fdFlags              = 0000000100000000
                       . kHasBeenInited</span>
...
  # Data Fork
  logicalSize          = 14 bytes
  totalBlocks          = 1
  fork temperature     = no HFC record in B-Tree
  clumpSize            = 0
  extents              =   startBlock   blockCount      % of file
                             0xbb04b7          0x1       100.00 %
                         1 allocation blocks in 1 extents total.
                         1.00 allocation blocks per extent on an average.
  # Resource Fork
  logicalSize          = 0 bytes
</pre>
<p></code></p>
<p>As we see, the indirect-node file acts as the container for several of the original file&#8217;s properties. In particular, it has the original file&#8217;s content, the owner ID, and the group ID. A reserved field (<code>reserved1</code>) even contains the ID of the head of the hard link chain.</p>
<p>Of course, these are implementation details. HFS+ will show you the expected hard link semantics when you look at these files through the usual file system interfaces.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>ls -las file1 file2</strong>
1927091 8 -rw-r--r--  2 singh  wheel  14 Nov  3 21:55 file1
1927091 8 -rw-r--r--  2 singh  wheel  14 Nov  3 21:55 file2
$ <strong>cat file1 file2</strong>
This is file1
This is file1
</pre>
<p></code></p>
<p>We see that both <code>file1</code> and <code>file2</code> show up with identical metadata, including the same &#8220;inode&#8221; number as you would expect. They also &#8220;have&#8221; the same content.</p>
<p>Note that if you now delete one of the hard links, say, <code>file2</code>, things <em>will not</em> revert back to how they were to begin with. You will have <code>file1</code> as the only hard-link file along with the indirect-node file.</p>
<p>Let us look at directory hard links next.</p>
<h3>Directory Hard Links</h3>
<p>It&#8217;s not straightforward to create a directory hard link on Mac OS X. Well, that shouldn&#8217;t be surprising: directory hard links aren&#8217;t meant for third party developers, let alone users. They are essentially an implementation detail needed to make the Time Machine feature of Leopard work. Since we <em>are</em> talking about implementation details here, we will have to create a directory hard link or two&mdash;for experimentation, of course.</p>
<p>Leopard at the time of this writing requires the following conditions to be met for a directory hard link&#8217;s creation to be allowed. In the following list, &#8220;source&#8221; refers to the existing directory that will be pointed at by the new directory hard link &#8220;destination&#8221; that&#8217;s being created.</p>
<ul style="list-style: square;">
<li>The file system must be journaled HFS+.</li>
<li>The parent directories of the source and destination must be different.</li>
<li>The source&#8217;s parent must not be the root directory.</li>
<li>The destination must not be in the root directory.</li>
<li>The destination must not be a descendent of the source.</li>
<li>The destination must not have any ancestor that&#8217;s a directory hard link.</li>
</ul>
<p>If you meet all these conditions, you could create a directory hard link on an HFS+ volume under Mac OS X 10.5 and above. It&#8217;s then a matter of writing a program that uses the <code>link()</code> system call.</p>
<p><code></p>
<pre style="font-size: 85%;">
/* dirlink.c */

#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;

int
main(int argc, char** argv)
{
    int ret = -1;
    if (argc == 3) {
        ret = link(argv[1], argv[2]);
        if (ret) {
            perror("link");
        }
    }
    return ret;
}
</pre>
<p></code></p>
<p>In our <code>/tmp/test/</code> testing directory, we&#8217;ll create a directory <code>dir1</code> and a subdirectory <code>subdir</code>. It&#8217;s in <code>subdir</code> that we&#8217;ll create a hard link <code>dir2</code> to <code>dir1</code>. This is because <code>dir1</code> and <code>dir2</code> can&#8217;t have the same parent.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>gcc -Wall -o dirlink dirlink.c</strong>
$ <strong>mkdir dir1</strong>
$ <strong>mkdir subdir</strong>
</pre>
<p></code></p>
<p>Before we create the directory hard link, let us use HFSDebug to peek at the current on-disk details of <code>dir1</code>.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug dir1</strong>
...
  path                 = Leopard HD:/private/tmp/test/dir1
# Catalog Folder Record
<span style="background-color: #00f000;">  type                 = folder
  folder ID            = 1927398</span>
  flags                = 0000000000000000
  valence              = 0
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 501 (singh)
  groupID              = 0 (wheel)</span>
  adminFlags           = 00000000
  ownerFlags           = 00000000
<span style="background-color: #00f000;">  fileMode             = drwxr-xr-x</span>
  linkCount            = 1
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
  frRect               = (top = 0, left = 0), (bottom = 0, right = 0)
  frFlags              = 0000000000000000
  frLocation           = (v = 0, h = 0)
  opaque               = 0
  # Opaque Finder Info
  scrollPosition       = (v = 0, h = 0)
  reserved1            = 0
  Opaque Finder Flags  = 0000000000000000
  reserved2            = 0
  putAwayFolderID      = 0
</pre>
<p></code></p>
<p>Let us create the link and confirm that our expectations of directory hard link semantics are met.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>./dirlink dir1 subdir/dir2</strong>
$ <strong>ls -lasdi dir1 subdir/dir2</strong>
1927398 0 drwxr-xr-x  2 singh  wheel  68 Nov  3 22:59 dir1
1927398 0 drwxr-xr-x  2 singh  wheel  68 Nov  3 22:59 subdir/dir2
$ <strong>echo Hello > dir1/file</strong>
$ <strong>cat subdir/dir2/file</strong>
Hello
</pre>
<p></code></p>
<p>Everything looks in order. Let us now use HFSDebug to see what <em>actually</em> happened inside the file system. We looked at <code>dir1</code>&#8217;s on-disk details earlier. We can now see what changed after we created a directory hard link to <code>dir1</code>.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug dir1</strong>
...
  path                 = Leopard HD:/private/tmp/test/dir1
# Catalog File Record
<span style="background-color: #00f000;">  type                 = file (alias, directory hard link)
  indirect folder      = Leopard HD:/.HFS+ Private Directory Data%000d/dir_1927398
  file ID              = 1927407
  flags                = 0000000000100010
                       . File has a thread record in the catalog.
                       . File has hardlink chain.</span>
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 1927408 (previous link ID)
  groupID              = 0 (next link ID)
  adminFlags           = 00000000
  ownerFlags           = 00000010
                       . UF_IMMUTABLE (file may not be changed)
  fileMode             = -r--r--r--
  iNodeNum             = 1927398 (link reference number)</span>
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
<span style="background-color: #00f000;">  fdType               = 0x66647270 (fdrp)
  fdCreator            = 0x4d414353 (MACS)
  fdFlags              = 1000000000000000
                       . kIsAlias</span>
  fdLocation           = (v = 0, h = 0)
  opaque               = 0
  # Data Fork
  logicalSize          = 0 bytes
<span style="background-color: #00f000;">  # Resource Fork
  logicalSize          = 464 bytes</span>
  totalBlocks          = 1
  fork temperature     = no HFC record in B-Tree
  clumpSize            = 0
  extents              =   startBlock   blockCount      % of file
                             0xbae746          0x1       100.00 %
                         1 allocation blocks in 1 extents total.
                         1.00 allocation blocks per extent on an average.

<span style="background-color: #00f000;">  rsrc contents        = (up to 464 bytes)
       00 00 01 00 00 00 01 9e 00 00 00 9e 00 00 00 32 00 00 00 00 00 00 00 00
                                                     2
...
       00 00 00 00 00 00 00 1c 00 32 00 00 61 6c 69 73 00 00 00 0a 00 00 ff ff
                                   2        a  l  i  s
       00 00 00 00 00 00 00 00</span>
</pre>
<p></code></p>
<p>We see that <code>dir1</code>&#8217;s transformation is more drastic than what we had observed in the case of file hard links. After we created a directory hard link to <code>dir1</code>, it&#8217;s no longer a directory inside the file system. In fact, the &#8220;real&#8221; directory (that is, the link target) has moved to a special folder (<code>/.HFS+ Private Directory Data\xd</code>), just as the link target of a file hard link had moved to a (different) special folder. Its name within the special folder is <code>dir_1927398</code>, where the number represents the original &#8220;inode&#8221; number of <code>dir1</code>. However, <code>dir1</code> hasn&#8217;t been replaced by another directory that points to the link target&mdash;it has been replaced by a <em>file</em>, or specifically, an <em>alias</em>. (Backward compatibility!) The immutable alias file has <code>fdrp</code> and <code>MACS</code> as its type and creator codes, respectively. It also as a resource fork. Moreover, we see that as in the case of file hard links, there exists a hard link chain.</p>
<p>Let us also examine the link target using HFSDebug. The path would be &#8220;hard&#8221; to type because of the characters in the special folder&#8217;s name. We can use the folder ID instead, which would be the original ID of <code>dir1</code>.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug -c 1927398</strong>
...
  path                 = Leopard HD:/.HFS+ Private Directory Data%000d/dir_1928557
# Catalog Folder Record
  type                 = folder
<span style="background-color: #00f000;">  folder ID            = 1927398
  flags                = 0000000000100100
                       . Folder has extended attributes.
                       . Folder has hardlink chain.</span>
  valence              = 0
...
  # BSD Info
<span style="background-color: #00f000;">  ownerID              = 501 (singh)
  groupID              = 0 (wheel)</span>
  adminFlags           = 00000000
  ownerFlags           = 00000000
  fileMode             = drwxr-xr-x
  linkCount            = 2
  textEncoding         = 0
  attrBlocks           = 0
  # Finder Info
  frRect               = (top = 0, left = 0), (bottom = 0, right = 0)
  frFlags              = 0000000000000000
  frLocation           = (v = 0, h = 0)
  opaque               = 0
...
# Attributes
...
  # Attribute Key
  keyLength            = 72
  pad                  = 0
  fileID               = 1927398
  startBlock           = 0
  attrNameLen          = 30
<span style="background-color: #00f000;">  attrName             = com.apple.system.hfs.firstlink</span>
  # Inline Data
  recordType           = 0x10
  reserved[0]          = 0
  reserved[1]          = 0
  attrSize             = 8 bytes
  attrData             = 31 39 32 37 34 30 38 00
<span style="background-color: #00f000;">                          1  9  2  7  4  0  8     </span>
</pre>
<p></code></p>
<p>We see mostly what we would expect given our previous observation of the implementation details of file hard links. There is one more thing in this case though: the folder has an extended attribute whose name is <code>com.apple.system.hfs.firstlink</code> and whose value is an encoding of the &#8220;inode&#8221; number of the head of the directory hard link chain.</p>
<h3>HFSDebug Filters</h3>
<p>At this point, you could use the built-in <code>dirhardlink</code> filter in HFSDebug to enumerate all directory hard links on the volume.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug --filter=builtin:dirhardlink</strong>
2 links -> dir_1927398
Leopard HD:/private/tmp/test/dir1 -> dir_1927398
Leopard HD:/private/tmp/test/subdir/dir2 -> dir_1927398
</pre>
<p></code></p>
<p>The filter prints both link targets and link references. For a link target, the number of references to it is printed before it. For a link reference, the target that it points to is printed after it.</p>
<p>By the way, <a href="http://osxbook.com/software/hfsdebug/#FILTERS" title="HFSDebug Filters">filters</a> are a <em>very</em> useful recent addition to HFSDebug. A fundamental capability of HFSDebug is to go over all the entries in the HFS+ catalog file. It uses this capability to generate many types of statistics. The recently added filter support makes it possible for <em>you</em> to write a program that plugs into HFSDebug and receives a callback for each catalog file entry. That way, you can examine each entry, apply arbitrary criteria, and show (or not show) details about that entry. Say, you wish to list all setuid/setgid files on an HFS+ volume. Sure, you could run a <code>find</code> command to do that. On one of my HFS+ volumes with about a million files and 200K folders, <code>find</code> takes a while to do this.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>time sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \)</strong>
...
<span style="background-color: #00f000;">6.41s user 94.12s system 34% cpu 4:53.35 total</span>
$
</pre>
<p></code></p>
<p>You could do this <em>much</em> faster with the <code>sxid</code> built-in HFSDebug filter, whose implementation is a mere ten lines of C code. (Of course, the absolute time taken will also depend on the underlying hardware, but we are only interested in the relative time difference.)</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>time sudo hfsdebug --filter=builtin:sxid</strong>
...
<span style="background-color: #00f000;">2.86s user 9.33s system 17% cpu 1:08.04 total</span>
$
</pre>
<p></code></p>
<p>Note that many types of searches on HFS+ can also be done through the <code>searchfs()</code> system call, although it can be quite cumbersome to use. Of course, <code>searchfs()</code> cannot be done on an unmounted volume.</p>
<h3>Specifying File System Objects by Path on Unmounted Volumes</h3>
<p>As we have seen, a common use for HFSDebug is to have it display implementation details of individual file system objects. You could specify the object of interest in several ways: by providing its catalog node ID (CNID), by providing an &#8220;fsspec&#8221; style pair consisting of the parent folder&#8217;s CNID and the object&#8217;s name, or by providing a POSIX-style path to the object. The latter is often the easiest and most convenient to specify. However, until now, HFSDebug did not do component-wise path lookups itself&mdash;it used the operating system to convert the path to an inode number. This results in a few caveats. To begin with, it&#8217;s against the HFSDebug philosophy of <em>not relying</em> on the operating system for any HFS+-related operations. It also means that if the volume in question is not mounted (say, it&#8217;s corrupt and can&#8217;t be mounted or you are investigating something and don&#8217;t want to mount it), you can&#8217;t use paths to look at individual objects. You will have to dump all objects on the file system and then find the node ID of the object of interest. Moreover, even on a mounted volume, the operating system disallows path-based access to several files. (See Chapter 12 of <a href="http://osxbook.com/" title="Mac OS X Internals: The Book">Mac OS X Internals</a>.) In such cases, again you will need to know the node ID of the object of interest, even on a mounted volume.</p>
<p>I&#8217;ve &#8220;fixed this issue&#8221; (or &#8220;added the feature&#8221;, depending on how you look at it) in the new version of HFSDebug. Say, if you have an unmounted volume on <code>/dev/disk5s1</code> and you want to examine <code>/tmp/foo/bar</code> on it. Now you can simply do:</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug -d /dev/disk5s1 /tmp/foo/bar</strong>
...
</pre>
<p></code></p>
<p>The semantics of symbolic link resolution are as follows. If the object (<code>bar</code> in this example) is a symbolic link itself, then HFSDebug will show you properties of <code>bar</code> and not what it points to. This is in line with HFSDebug philosophy and also how things work today on mounted volumes. If, however, a nonterminal component of the path is a symbolic link, HFSDebug <em>will</em> resolve it. Again, this is desirable.</p>
<p>That&#8217;s about it.</p>
<h3>One More Thing</h3>
<p>I can&#8217;t talk about HFSDebug&#8217;s Snow Leopard-specific features since the latter is under NDA. If you do have access to the latest Snow Leopard seed, try HFSDebug on it. For example, examine some standard Mac OS X files using HFSDebug.</p>
<p><code></p>
<pre style="font-size: 85%;">
$ <strong>sudo hfsdebug /bin/ls</strong>
...
$ <strong>sudo hfsdebug /etc/asl.conf</strong>
...
$ <strong>sudo hfsdebug /Applications/Mail.app/Contents/PkgInfo</strong>
...
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.osxbook.com/blog/2008/11/09/hfsdebug-40-and-new-hfs-features/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
