<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Chris Suter&apos;s Blog</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/" />
    <link rel="self" type="application/atom+xml" href="http://sutes.co.uk/atom.xml" />
    <id>tag:sutes.co.uk,2010-05-14://1</id>
    <updated>2010-08-17T10:51:55Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.01</generator>

<entry>
    <title>errno</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2010/08/errno.html" />
    <id>tag:sutes.co.uk,2010://1.25</id>

    <published>2010-08-17T10:31:51Z</published>
    <updated>2010-08-17T10:51:55Z</updated>

    <summary>errno is a macro on OS X and expands to this: #define errno (*__error()) The reason for this is for thread safety. That means that in the debugger, if you want to see what the current value of errno is,...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>errno is a macro on OS X and expands to this:</p>

<blockquote><code><pre>
#define errno (*__error())
</pre></code></blockquote>

<p>The reason for this is for thread safety. That means that in the debugger, if you want to see what the current value of errno is, you can type:</p>

<blockquote><code><pre>
p *(int *)__error()
</pre></code></blockquote>

<p>It&#8217;s important to remember that if you&#8217;re using errno, any system call can reset it. The following code is broken:</p>

<blockquote><code><pre>
NSLog (@"errno: %d", errno);
if (errno == EIO)
  ...
</pre></code></blockquote>

<p>The call to NSLog can, and probably will, reset errno. On 10.6 calls to the free library function (which NSLog can call) will usually reset errno to 2 (ENOENT), so bear this in mind if you&#8217;re seeing an errno value of 2 when you wouldn&#8217;t expect it.</p>

<p>As a consequence of this, you <em>cannot</em> single step through code in Xcode when you have &#8220;Use Data Formatters&#8221; checked, and expect errno to be preserved. You will find in many cases errno is reset to 2. In fact, I would recommend turning off &#8220;Use Data Formatters&#8221;&#8212;they cause many problems. Hopefully lldb will bring a non-invasive method of inspecting variables.</p>

<p>Was this post born from bitter experience? Yes it was.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Compile Time Checks</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2010/08/compile-time-checks.html" />
    <id>tag:sutes.co.uk,2010://1.24</id>

    <published>2010-08-06T04:57:19Z</published>
    <updated>2010-08-06T05:07:15Z</updated>

    <summary>Here&#8217;s a handy macro you can use to do compile time checks: #define CHECK__(line, x) typedef char check_##line##_[(x) ? 1 : -1]; #define CHECK_(line, x) CHECK__(line, x) #define CHECK(x) CHECK_(__LINE__, (x)) You&#8217;ll get a compiler error if the check is...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>Here&#8217;s a handy macro you can use to do compile time checks:</p>

<blockquote><pre><code>#define CHECK__(line, x) typedef char check_##line##_[(x) ? 1 : -1];
#define CHECK_(line, x) CHECK__(line, x)
#define CHECK(x) CHECK_(__LINE__, (x))</code></pre></blockquote>

<p>You&#8217;ll get a compiler error if the check is false. Obviously the condition needs to be something the compiler can figure out at compile time. You might use it like this:</p>

<blockquote><pre><code>#pragma pack(push, 1)
struct x {
  uint8_t  a;
  uint32_t b;
};
#pragma pack(pop)

CHECK (sizeof (struct x) == 5)</code></pre></blockquote>

<p>I use it to check sizes of structures that have to match a protocol or format, for example, on disk structures that you know are supposed to be 512 bytes in size.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Static Analyser Invariants</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2010/07/static-analyser-invariants.html" />
    <id>tag:sutes.co.uk,2010://1.23</id>

    <published>2010-07-28T04:28:29Z</published>
    <updated>2010-07-28T05:00:46Z</updated>

    <summary>If you&#8217;re not using the Static Analyser, you should be. However, sometimes you need to give it a helping hand in order to avoid false positives. Mostly you can use assert to tell the analyser that a certain path is...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>If you&#8217;re not using the Static Analyser, you should be. However, sometimes you need to give it a helping hand in order to avoid false positives. Mostly you can use <code>assert</code> to tell the analyser that a certain path is impossible. The problem with that is that it will usually add code to your built product. You could avoid this by defining the NDEBUG macro in your release build but I don&#8217;t like to do that (and it isn&#8217;t by default); I prefer to leave assertions in my release build. Anyway, here&#8217;s some code you can use to do the same thing as <code>assert</code> but won&#8217;t add any extra code to your built product. You&#8217;d use this instead of <code>assert</code> when it might affect performance and is also obviously always true.</p></p>

<blockquote><code><pre><span style="color:#74492d">#if __clang__</span>

<span style="color:#b50da1">static void inline</span> static_analyser_no_return (void) 
  __attribute__ ((analyzer_noreturn));

<span style="color:#b50da1">static void inline</span> static_analyser_no_return (void) {}

<span style="color: #14870b">/* Use this to shut the analyser up without actually adding any code. */</span>
<span style="color: #74492d">
#define static_analyser_invariant(cond) \
  do { if (!cond) static_analyser_no_return (); } while (0)

#else

#define static_analyser_invariant(cond) ((void)0)

#endif
</span>
</pre></code></blockquote>
]]>
        

    </content>
</entry>

<entry>
    <title>Unsupported iPhone Applications</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2010/05/unsupported-iphone-application.html" />
    <id>tag:sutes.co.uk,2010://1.22</id>

    <published>2010-05-14T04:37:05Z</published>
    <updated>2010-05-14T04:56:44Z</updated>

    <summary>Mike Ash just posted a list of applications he can&#8217;t have on his iPhone. I think that most of his examples are cases where a suitable API doesn&#8217;t exist, rather than it being expressly forbidden by Apple. I&#8217;m sure there...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>Mike Ash just posted a <a href="http://www.mikeash.com/pyblog/iphone-apps-i-cant-have.html">list of applications he can&#8217;t have on his iPhone</a>. I think that most of his examples are cases where a suitable API doesn&#8217;t exist, <em>rather</em> than it being expressly forbidden by Apple. I&#8217;m sure there are some applications that are not currently possible on OS X due to lack of a suitable API. I remember that Disk Arbitration (a framework we use for our products) wasn&#8217;t made public until 10.4. Another example is Flash Player 10 on OS X; it&#8217;s my understanding that the performance improvements are because of an API being made available that wasn&#8217;t before.</p>

<p>The iPhone is still relatively new and I&#8217;m guessing that they&#8217;re fairly busy over at Apple HQ so something has to give. I can&#8217;t think of a reason why Apple wouldn&#8217;t eventually want to add the APIs to make all his applications possible.</p>

<p>Don&#8217;t get me wrong, I don&#8217;t particularly like the restrictive nature of the App Store. I actually think it would be nice if there was a mode you could put your iPhone into that disabled many of the restrictions&#8212;in this mode you could do whatever you like, e.g. load non-Apple sanctioned applications on your phone, but obviously, in this mode you&#8217;d be on your own if something went wrong.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>NSURLConnection &amp; Using HEAD Method</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/12/nsurlconnection-using-head-met.html" />
    <id>tag:sutes.co.uk,2009://1.21</id>

    <published>2009-12-16T20:00:06Z</published>
    <updated>2009-12-16T20:11:09Z</updated>

    <summary>If you want to use the HEAD method with NSURLConnection, it&#8217;s simple, you use -[NSMutableURLRequest setHTTPMethod:]. However, you need to be careful with redirects. Redirections will revert to using the GET method which usually isn&#8217;t what you want, so you...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>If you want to use the HEAD method with NSURLConnection, it&#8217;s simple, you use <code>-[NSMutableURLRequest setHTTPMethod:]</code>.</p>

<p>However, you need to be careful with redirects. Redirections will revert to using the GET method which usually isn&#8217;t what you want, so you need something like:</p>

<blockquote><code><pre>
- (NSURLRequest *)connection:(NSURLConnection *)connection
             willSendRequest:(NSURLRequest *)request
            redirectResponse:(NSURLResponse *)redirectResponse
{
    if ([[request HTTPMethod] isEqualTo:@"HEAD"])
        return request;

    NSMutableURLRequest *newRequest = [request mutableCopy];
    [newRequest setHTTPMethod:@"HEAD"];

    return [newRequest autorelease];
}
</pre></code></blockquote>

<p>I suspect that this bug report is invalid: <a href="http://openradar.appspot.com/7019347">http://openradar.appspot.com/7019347</a>.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>x86_64 Assembler</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/12/x86-64-assembler.html" />
    <id>tag:sutes.co.uk,2009://1.20</id>

    <published>2009-12-11T00:58:24Z</published>
    <updated>2009-12-11T01:18:25Z</updated>

    <summary>I&#8217;m OK at deciphering PowerPC assembler and i386 assembler but now it&#8217;s all x86_64. If you&#8217;re having a look at the internals of AppKit in x86_64, you need to print out page 21 of this: http://www.x86-64.org/documentation/abi.pdf and stick it on...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>I&#8217;m OK at deciphering PowerPC assembler and i386 assembler but now it&#8217;s all x86_64. If you&#8217;re having a look at the internals of AppKit in x86_64, you need to print out page 21 of this: <a href="http://www.x86-64.org/documentation/abi.pdf">http://www.x86-64.org/documentation/abi.pdf</a> and stick it on your wall next to your C operator precedence table.</p>

<p>Now wherever you see objc_msgSend (or something similar), the selector gets passed in $rsi. To find out what it is, type:</p>

<blockquote><code>p (char *)sel_getName($rsi)</code></blockquote>

<p>x86_64 comes with instruction pointer relative addressing so you might notice that gdb helpfully displays what the target address is wherever it&#8217;s used. So if you&#8217;re looking at some assembler that looks like this:</p>

<blockquote style="font-size:75%"><code>
0x00007fff811f33fc <-[NSTableView reloadData]+115>: mov    -0x10f16b8b(%rip),%rsi        # 0x7fff702dc878<br/>
0x00007fff811f3403 <-[NSTableView reloadData]+122>: mov    %rbx,%rdi<br/>
0x00007fff811f3406 <-[NSTableView reloadData]+125>: callq  0x7fff8184278e &lt;dyld_stub_objc_msgSend&gt;<br/>
</code></blockquote>

<p>You can figure out what the call is by typing:</p>

<blockquote><code>p (char *)sel_getName(*(void **)0x7fff702dc878)</code></blockquote>

<p>And you&#8217;ll see something like:</p>

<blockquote><code>$2 = 0x7fff8187bb68 "_endMyEditing"</code></blockquote>
]]>
        

    </content>
</entry>

<entry>
    <title>Attempt to Pop an Unknown Autorelease Pool</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/11/attempt-to-pop-an-unknown-auto.html" />
    <id>tag:sutes.co.uk,2009://1.19</id>

    <published>2009-11-13T03:47:34Z</published>
    <updated>2009-11-13T03:53:39Z</updated>

    <summary>If you see: *** attempt to pop an unknown autorelease pool (0x12345678) You can debug it by setting a breakpoint in the _CFAutoreleasePoolPop function. To find out exactly where, disassemble the _CFAutoreleasePoolPop function, and look for the first call to...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>If you see:</p>

<pre><code>*** attempt to pop an unknown autorelease pool (0x12345678)
</code></pre>

<p>You can debug it by setting a breakpoint in the _CFAutoreleasePoolPop function. To find out exactly where, disassemble the _CFAutoreleasePoolPop function, and look for the first call to CFLog. On the i386 architecture it&#8217;s at _CFAutoreleasePoolPop+84.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>_Block_dump</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/10/-block-dump.html" />
    <id>tag:sutes.co.uk,2009://1.17</id>

    <published>2009-10-19T07:28:24Z</published>
    <updated>2009-10-19T07:31:38Z</updated>

    <summary>If you&#8217;re playing with blocks you can get debug information by using: char *_Block_dump (block_t block); It&#8217;s not in any public header so you&#8217;ll have to declare it yourself. It returns a debug string you can log and will give...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>If you&#8217;re playing with blocks you can get debug information by using:</p>

<pre><code>char *_Block_dump (block_t block);
</code></pre>

<p>It&#8217;s not in any public header so you&#8217;ll have to declare it yourself. It returns a debug string you can log and will give you the retain count of the block, whether it&#8217;s a global, stack or heap block and other information.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Hacking</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/10/hacking.html" />
    <id>tag:sutes.co.uk,2009://1.16</id>

    <published>2009-10-08T09:47:46Z</published>
    <updated>2009-10-08T10:53:08Z</updated>

    <summary>In my last entry I mentioned the private API _LSSetStrongBindingForRef that Launch Services has to set the application that launches a particular file. I thought it might be interesting to post how I figured it out. Firstly, I reasoned that...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>In my last entry I mentioned the private API <code>_LSSetStrongBindingForRef</code> that Launch Services has to set the application that launches a particular file. I thought it might be interesting to post how I figured it out.</p>

<p>Firstly, I reasoned that Launch Services would probably have a private API that Finder uses to set it. I could have gone through all the symbols that Launch Services exports, including the private ones looking for likely candidates. To do that, you use the nm tool:</p>

<blockquote><code>
 nm /System/Library/Frameworks/CoreServices.framework/ \<br/>
 Versions/A/Frameworks/LaunchServices.framework/LaunchServices
</code></blockquote>

<p>That will spew out a load of information. Any symbols that are tagged <code>U</code>, are undefined which mean they're come from somewhere else--another framework or library. We're interested in symbols that are tagged <code>T</code> since they're symbols that are exported by that framework. Symbols that have a lower case <code>t</code>, are local to the module and aren't exported. Binaries that are stripped shouldn't have any symbols with a lower case codes. Remember that all C symbols will have an underscore at the beginning that you won't see in your code. C++ symbols are a different story that I won't go into here.</p>

<p>OK, so that's one way I could have figured it, but I got bored looking through them all, so...</p>

<p>Since I knew that Finder was able to set the binding, I figured I could just see what Finder does, but how to do that? What I did was attach the debugger (gdb) to Finder and set some breakpoints. To attach the debugger to Finder:</p>

<blockquote><code>gdb /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder<br/>
attach Finder<em>&lt;TAB&gt;</em>
</code></blockquote>

<p>Apple's version of gdb supports tab completion for the attach command so when you press the tab command you should find it fills in the process id of Finder.</p>

<p>Now what to set the breakpoints on? Well, I first tried setting the breakpoint on write--obviously setting the binding is going to involve writing to the disk at some point (I already knew that the binding was set as part of the <code>usro</code> resource in the resource fork) so my idea was that I'd set a breakpoint on write and then set a binding in Finder and see what we got. There aren't actually that many primitives for writing to the disk; all the Cocoa and Carbon frameworks eventually call BSD primitives to do what they want so you usually just need to set breakpoints on write/pwrite. For example, you'll probably find <code>-[NSData writeToFile:atomically:]</code> calls a CoreFoundation function which then calls one of the BSD write functions. </p>

<p>To set a breakpoint:</p>

<blockquote><code>b write</code></blockquote>

<p>Now on my system it sets breakpoints in two places, on <code>write</code> and <code>write$NOCANCEL</code>. That's fine so I just continued. Type <code>c</code> to continue.</p>

<p>OK, those of you playing along at home will find that whilst it might stop in a few places whilst you're trying to set the binding (e.g. when an open panel appears), it doesn't stop after you've actually set the binding. By the way, to continue after hitting a breakpoint, type <code>c</code>.</p>

<p>So then I set a breakpoint on <code>pwrite</code>, and this time, just after setting the binding, the debugger stops. What now? Well, we want a backtrace. To get that, type <code>bt</code> and this is what we get:</p>

<blockquote><code>#0  0x00007fff82b8b03c in pwrite ()<br/>
#1  0x00007fff821b6b1a in BasicWrite ()<br/>
#2  0x00007fff821b6a49 in PBWriteForkSync ()<br/>
#3  0x00007fff821b69d6 in FSWriteFork ()<br/>
#4  0x00007fff822281c0 in WriteData ()<br/>
#5  0x00007fff822282d3 in WrResource ()<br/>
#6  0x00007fff821ca33a in UpdateTheFile ()<br/>
#7  0x00007fff821ca035 in UpdateResFileCommon ()<br/>
#8  0x00007fff8213a028 in _LSSetStrongBindingForRef ()<br/>
</code></blockquote>

<p>It goes on but I stopped at <code>_LSSetStrongBindingForRef</code>. As you can see, there are a bunch of Carbon functions before we get to the <code>pwrite</code> call.</p>

<p>To get the prototype for the function I searched Google and found someone had already done it for me. ;-)</p>

<p>I should note that you'll probably want to detach from Finder: type detach, and then Finder will continue running. If you don't, you'll probably end up killing Finder which isn't actually such a big deal as it'll just be restarted for you.</p>

<p>Anyway, every programmer should get seriously familiar with gdb. In this case, I've used it to discover a private API which I personally wouldn't use and don't recommend others using either, but I have used similar techniques before to debug problems I've had with some of Apple's frameworks, not to mention my own code. I've mentioned the nm command which is useful, but there's also otool which will dump things like what libraries a binary is linked to; there's the awesome <a href="http://www.codethecode.com/projects/class-dump/">class-dump</a> tool; there's fs_usage for monitoring what accesses the disk and lsof for tracking down open files, and then there's dtrace and probably many more that I've forgotten.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Creator Codes Are Not Replaced by Uniform Type Identifiers</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/09/creator-codes-are-not-replaced.html" />
    <id>tag:sutes.co.uk,2009://1.15</id>

    <published>2009-09-22T22:20:32Z</published>
    <updated>2009-09-23T00:29:25Z</updated>

    <summary>There&#8217;s some press about suggesting that Creator Codes are replaced by Uniform Type Identifiers (UTI) which is rubbish. They&#8217;re not. Uniform Type Identifiers are just a type. To be able to work out the type of something you have to...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>There&#8217;s some <a href="http://forums.appleinsider.com/showthread.php?s=&amp;threadid=103219">press</a> <a href="http://db.tidbits.com/article/10537">about</a> suggesting that Creator Codes are replaced by Uniform Type Identifiers (UTI) which is rubbish.</p>

<p>They&#8217;re not.</p>

<p>Uniform Type Identifiers are just a type. To be able to work out the type of something you have to look at some metadata which for the vast majority of things isn&#8217;t a UTI. For most files on your Mac, it will be the extension of the file that determines what type of file it is. About the only place that you&#8217;ll see a UTI is within the property list of an application where it says what types it supports.</p>

<p>As far as I know, there is no direct replacement for creator codes. There is no other metadata that you can put on the file that tells the system what application created it, and even if there was, UTIs would have little to do with it since UTIs represent types, not applications.</p>

<p>There is metadata on a file that is used to say what application should open the file (on a per file basis). This is stored within the resource fork of the file in a <tt>usro</tt> resource. This simply stores the path of the application (no UTI is involved) that should open a file and yes, this could be used to replace creator codes<del>&#8212;I don&#8217;t know if there&#8217;s an API for setting them, I haven&#8217;t checked.</del> Launch Services has a private API that you could use to set the binding:</p>

<pre><code>extern OSStatus _LSSetStrongBindingForRef(const FSRef *inItemRef,
                                          FSRef *inAppRefOrNil);
</code></pre>

<p>I don&#8217;t know why Apple have got rid of creator codes but it is a shame they haven&#8217;t replaced them with something. Perhaps they haven&#8217;t had time to figure out what to replace them with. Thinking about it, what you probably want is to store the bundle ID of the application that created the file in some metadata somewhere (as an extended attribute or within the resource fork). I haven&#8217;t thought it through, but there might also be security issues with creator codes&#8212;malicious programs could set them behind your back and cause bad stuff to happen.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>AppleGlot on Snow Leopard</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/09/appleglot-on-snow-leopard.html" />
    <id>tag:sutes.co.uk,2009://1.14</id>

    <published>2009-09-14T22:26:00Z</published>
    <updated>2009-09-14T22:32:29Z</updated>

    <summary>To get AppleGlot to work properly on Snow Leopard, apply this patch to /Developer/Applications/AppleGlot/AppleGlot.app/Contents/Frameworks /AppleGlot.framework/Resources/ibtoolWrapper. (It&#8217;s broken because ibtool runs as a 64-bit app. and can&#8217;t load AppleGlot&#8217;s plugin which is 32-bit)....</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>To get AppleGlot to work properly on Snow Leopard, apply this <a href="/stuff/ibtoolWrapper.patch">patch</a> to <tt>/Developer/Applications/AppleGlot/AppleGlot.app/Contents/Frameworks /AppleGlot.framework/Resources/ibtoolWrapper</tt>.</p>

<p>(It&#8217;s broken because ibtool runs as a 64-bit app. and can&#8217;t load AppleGlot&#8217;s plugin which is 32-bit).</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Getting hexdump to Give Suitable Output for Use in C</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2009/02/getting-hexdump-to-give-suitab.html" />
    <id>tag:sutes.co.uk,2009://1.13</id>

    <published>2009-02-03T22:15:26Z</published>
    <updated>2009-02-03T22:21:18Z</updated>

    <summary><![CDATA[Here&#8217;s how to get hexdump to give you a suitable output for embedding in a C file: hexdump -e "8/1 \"0x%02x, \" \"\n\"" &lt;file&gt; (This post is for my benefit as much as anyone else.)...]]></summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>Here&#8217;s how to get <code>hexdump</code> to give you a suitable output for embedding in a C file:</p>

<blockquote><code><pre>hexdump -e "8/1 \"0x%02x, \" \"\n\"" &lt;file&gt;</pre></code></blockquote>

<p>(This post is for my benefit as much as anyone else.)</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Kernel Log Buffer Size</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2008/12/kernel-log-buffer-size.html" />
    <id>tag:sutes.co.uk,2008://1.12</id>

    <published>2008-12-05T11:19:35Z</published>
    <updated>2008-12-05T11:50:07Z</updated>

    <summary>I&#8217;ve been working on some kernel code recently. The default log buffer size is only 4 KB so it doesn&#8217;t take much before you lose messages (not that I recommend you use logging for debugging purposes, but there are some...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>I&#8217;ve been working on some kernel code recently. The default log buffer size is only 4 KB so it doesn&#8217;t take much before you lose messages (not that I recommend you use logging for debugging purposes, but there are some times when it&#8217;s necessary). Anyway to increase it, you need to set the <tt>msgbuf</tt> boot argument. For example, in Terminal type this:</p>

<blockquote><tt>sudo nvram boot-args=msgbuf=65536</tt></blockquote>
]]>
        

    </content>
</entry>

<entry>
    <title>C++ Operator Overloading</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2008/10/c-operator-overloading.html" />
    <id>tag:sutes.co.uk,2008://1.11</id>

    <published>2008-10-28T09:20:47Z</published>
    <updated>2008-10-28T10:01:06Z</updated>

    <summary>I came across this code recently: level = kIOStorageAccessNone; while ( ( object = objects-&gt;getNextObject( ) ) ) { if ( object != client ) { level += _openClients-&gt;getObject( ( OSSymbol * ) object ); } } Basically, it&#8217;s going...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>I came across this code recently:</p>

<p><code><pre>
level = kIOStorageAccessNone;
while ( ( object = objects->getNextObject( ) ) )
{
    if ( object != client )
    {
        level += _openClients->getObject( ( OSSymbol * ) object );
    }
}
</pre></code></p>

<p>Basically, it&#8217;s going through a list of clients that it services and works out what the aggregate access level is for all the clients. Here are the possible access levels:</p>

<p><code><pre>
enum
{
    kIOStorageAccessNone          = 0x00,
    kIOStorageAccessReader        = 0x01,
    kIOStorageAccessReaderWriter  = 0x03,
    kIOStorageAccessSharedLock    = 0x04,
    kIOStorageAccessExclusiveLock = 0x08
};
</pre></code></p>

<p>Now, from looking at this code, it looks wrong because of the use of the <code>+=</code>. Surely <code>|=</code> is more appropriate. It&#8217;s obvious to me now, but it took me some time before I found the bit where they&#8217;d overridden the <code>+=</code> operator:</p>

<p><code><pre>
inline void operator+=( IOStorageAccess access )
{
    _access = ( ( _access - 1 ) >> 1 ) &amp; 7;
    _access = gIOMediaAccessTable[ ( ( access - 1 ) >> 1 ) &amp; 7 ][ _access ];
    _access = ( ( _access &amp; 7 ) &lt;&lt; 1 ) + 1;
}
</pre></code></p>

<p>Anyway, this, in my opinion, is a classic example of an abuse of C++ operator overloading. The rule when writing code should be to make it as readable and as obvious as possible first before you start trying to be clever. If the code had been something like this:</p>

<p><code><pre>
    clientLevel = _openClients->getObject( ( OSSymbol * ) object )->unsigned32BitValue( );
    level = aggregateLevel( level, clientLevel );
</pre></code></p>

<p>it wouldn&#8217;t have cost me any time as it would have been clear what was going on.</p>

<p>It&#8217;s for similar reasons that I always put brackets round expressions that combine <code>&amp;&amp;</code> and <code>||</code> clauses: not everybody knows the order of precedence of these two and it&#8217;s easy to forget; adding brackets means you don&#8217;t need to remember.</p>

<p>For example, I would always do:</p>

<p><code><pre>
    if ((a &amp;&amp; b) || (c &amp;&amp; d))
</pre></code></p>

<p>rather than</p>

<p><code><pre>
    if (a &amp;&amp; b || c &amp;&amp; d)
</pre></code></p>

<p>I know it&#8217;s tempting to use that clever bit of the language that you just learnt about but in doing so you might make it harder for the person that follows you. The general rule should be: unless it is a common idiom, make it clear what&#8217;s going on and if a better known alternative exists, use that instead.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Disk Arbitration</title>
    <link rel="alternate" type="text/html" href="http://sutes.co.uk/2008/10/disk-arbitration.html" />
    <id>tag:sutes.co.uk,2008://1.8</id>

    <published>2008-10-25T05:43:00Z</published>
    <updated>2008-10-25T04:58:56Z</updated>

    <summary>Disk Arbitration is what is used on the Mac to handle automatic mounting of volumes and various other disk related things. When you insert a disk, the kernel will instantiate drivers for it and notify the Disk Arbitration daemon. It...</summary>
    <author>
        <name>Chris Suter</name>
        
    </author>
    
    
    <content type="html" xml:lang="en-US" xml:base="http://sutes.co.uk/">
        <![CDATA[<p>Disk Arbitration is what is used on the Mac to handle automatic mounting of volumes and various other disk related things. When you insert a disk, the kernel will instantiate drivers for it and notify the Disk Arbitration daemon. It will then ask filesystem plugins if they recognise the volume and if they do it will usually proceed to mount them.</p>

<p>Using Disk Arbitration, you can send requests to eject disks, mount and unmount volumes, rename volumes and you can claim a disk for exclusive use. For each of those operations you can also approve or reject requests that other applications make. It&#8217;s not actually enforced: you could still force a volume to be unmounted and claiming a disk for exclusive use doesn&#8217;t stop anyone else from using it (like advisory file locks). You can see some of these notifications flying around by using <code>disktool</code> with the undocumented <code>-y</code> flag. You can get more debug by hacking the <code>com.apple.diskarbitration.plist</code> file in <code>/System/Library/LaunchDaemons</code> and adding the <code>-d</code> flag to the argument list. You&#8217;ll then get <code>/var/log/diskarbitrationd.log</code>.</p>

<p><code>diskarbitrationd</code> is the main daemon that&#8217;s responsible for all this stuff. The source code for it and related things can be found on the Open Source part of Apple&#8217;s site. To use Disk Arbitration from within your application, you need to link to the Disk Arbitration framework. It was a private framework in Panther (10.3) but was made public in Tiger (10.4). Things like Spotlight use it to know when to stop indexing a volume when you want to unmount a volume and you should use it too if you&#8217;re writing a similar application.</p>

<p>There are a couple of files that it looks at to tell it what to do. <code>/etc/fstab</code> is one of them. The shipped version (in Leopard) has some examples in the comments of <code>/etc/fstab</code> and the <code>man</code> page looks pretty good. By making the appropriate change to this file, you can, amongst other things, stop a volume from being automatically mounted. The other file it looks at is <code>/var/db/volinfo.database</code>. This text file stores the setting of the &#8220;Ignore ownership of this volume&#8221; flag that you see in Finder.</p>

<p>Disk Arbitration will also give you information about all the disks and volumes on the system. Here&#8217;s the kind of information it might have about your startup volume:</p>

<pre><code>
{
    DAAppearanceTime = 244372661.099552;
    DABusName = PMP;
    DABusPath = "IODeviceTree:/PCI0@0/SATA@1F,2/PRT2@2/PMP@0";
    DADeviceInternal = 1;
    DADeviceModel = "WDC WD1600JS-40NGB2                     ";
    DADevicePath = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleAHCI/PRT2@2/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice";
    DADeviceProtocol = SATA;
    DADeviceRevision = "10.02E04";
    DADeviceUnit = 0;
    DAMediaBSDMajor = 14;
    DAMediaBSDMinor = 3;
    DAMediaBSDName = disk0s3;
    DAMediaBSDUnit = 0;
    DAMediaBlockSize = 512;
    DAMediaContent = "48465300-0000-11AA-AA11-00306543ECAC";
    DAMediaEjectable = 0;
    DAMediaIcon =     {
        CFBundleIdentifier = "com.apple.iokit.IOStorageFamily";
        IOBundleResourceFile = "Internal.icns";
    };
    DAMediaKind = IOMedia;
    DAMediaLeaf = 1;
    DAMediaName = "Macintosh HD";
    DAMediaPath = "IODeviceTree:/PCI0@0/SATA@1F,2/PRT2@2/PMP@0/@0:3";
    DAMediaRemovable = 0;
    DAMediaSize = 138155196416;
    DAMediaUUID = &lt;NSCFType: 0xd32f150&gt;;
    DAMediaWhole = 0;
    DAMediaWritable = 1;
    DAVolumeKind = hfs;
    DAVolumeMountable = 1;
    DAVolumeName = "Macintosh HD";
    DAVolumeNetwork = 0;
    DAVolumePath = file://localhost/;
    DAVolumeUUID = &lt;NSCFType: 0xd3316b0&gt;;
}
</code></pre>

<p>That&#8217;s obviously for a specific partition on a disk. There&#8217;s another entry that represents the whole disk.</p>

<p>Something to note regarding disk/volume UUIDs: GUID partition schemes have a UUID that is used for the partition but in addition to that, there is a UUID that is stored as part of the file system (in the case of HFS+, it&#8217;s not actually a UUID but eight bytes that get turned into a UUID), so if you do end up using them, make sure you know which one you&#8217;re dealing with. The UUID reported by Disk Arbitration happens to be the file system UUID but the UUID property of IOMedia objects is from the partition table.</p>

<p>One thing that isn&#8217;t ideal is there&#8217;s no actual notification indicating when the system wants to eject a disk. You can use the eject approval notification, but then there&#8217;s no way to find out if the eject was ultimately approved. This would be a problem for, say, an indexing application, where it might want to release all resources for the disk (so that the eject will actually succeed) when an eject is requested. Spotlight probably uses the eject approval callback, but the only way it would be able to restart indexing on a volume that failed to eject, is by checking again after a certain amount of time (I don&#8217;t know if it does that).</p>

<p>Another problem I found recently is that bad clients can cause it to eat memory and this in turn can cause kernel memory leaks (of IOMedia objects). For example, on the currently shipping version of Leopard, the WindowServer process doesn&#8217;t appear to be properly processing Disk Arbitration notifications (probably because it uses a funny run loop) which is ultimately causing IOMedia objects to hang around in the kernel. It&#8217;s not a big deal but it does need fixing.</p>

<p>Oh, and one other thing, the system does not like it if Disk Arbitration crashes. Even though <code>launchd</code> will restart it, you still need to reboot as Finder and other processes don&#8217;t connect to the new version.</p>
]]>
        

    </content>
</entry>

</feed>
