Blog

A new Canadian copyright bill

Our government just proposed a new copyright bill that grants a few more fair dealing rights to the public. But at the same time, it let publishers strip all those rights away by the use of a digital lock. Digital locks are those things which are often trivial to break but are meant to make some actions more difficult. Have you ever ripped a DVD to your iPod or otherwise extracted its content to play it somewhere else than an ‘approved’ DVD player with the DVD logo on it? Then you’ve broken a lock, perhaps without noticing since the software did it for you, and with this new bill you’d also be breaking the law.

The problem isn’t really the digital locks themselves. It’s really that the law forbid you to break a digital lock even if it’s to perform perfectly lawful activity. Digital locks often serve a legitimate use: they make it more difficult to do things you are not entitled to do with the music, video, software or other copyrighted work you purchased. I’m using a kind of digital lock myself integrated with the software I’m selling: you need to purchase a serial number (a key to the lock) to use it.

But a digital lock can be overly restrictive, and they often are. A digital lock can hinder you from creating a backup copy of any digital content. It can block copy-pasting a paragraph of a digital book, even if you’re doing so for quoting the book in your own research in a perfectly legal way. In all those cases, there’s generally a way to bypass the lock to accomplish what you’re entitled to do. But this bill, by making lock circumvention illegal even in those cases, is violating its own spirit by offering a way for publishers to make illegal the exertion of those rights the public is supposed to have.

As I said earlier, I’m not against digital locks: I’m even using one myself to help protect my software. Digital locks exist to make it harder to violate copyright; but they should be afforded legal protection only when they help achieve this goal. This bill needs to be changed so it doesn’t strip the public of its legal rights when a digital lock goes beyond what is normally protected under copyright.

I am aware that Canadian politicians are pressed by some multinational corporations (and countries sold to their interests) who’d very much like to grab all those rights for themselves. I’d be horrified to see fair dealing disappear under a digital lock, and I hope that Parliament can fix this problem before the bill is made into law.

Thank you for reading my plea.

Notes & References

Fair dealing and other rights stripped away by digital locks in the new copyright bill (based on the June 1 leaked document):

  • 29.22 (1) paragraph (c)
    Reproduction for Private Purposes

  • 29.23 (1) paragraph (b)
    Fixing Signals and Recording Programs for Later Listening or Viewing

  • 29.24 (1) paragraph (c)
    Backup Copies

  • 30.04 (3) and (4) paragraph (a)
    Education - Work available through Internet

Sections 41.1 to 41.24 forbid distribution and usage of any system for circumvention of a digital lock. Considering it is often necessary to circumvent a digital lock to make use of fair dealing rights, forbidding the tools to circumvent a digital lock makes fair dealing impossible. This should be addressed too.

This is a message I just sent to my MP, and in addition to Stephen Harper (Prime Minister), Tony Clement (Industry Minister), James Moore (Heritage Minister), Gilles Duceppe (Bloc Québécois Leader), Jack Layton (NDP Leader), Michael Ignatieff (Liberal Party Leader), Marc Garneau (Liberal Industry, Science & Technology Critic), Charlie Angus (NDP Heritage, Culture and Digital Issues Critic).

If you feel the same as me about this issue, perhaps it’ll help to let your MP know about it. No need to write a story like I did, just a quick, personal, and respectful opinion will do. You can find your MP coordinates easily on the Parliament web site.


The killer and the private eraser

In a previous post, I described a problem with the way System Preferences updates preference panes. The inelegant but working solution I found was to force quit System Preferences then reopen it immediately. I planned to explain how it works in this post. But in a recent comment, Dave Keck found a more elegant solution with no visible drawback and posted in the comments; the missing API does indeed exists, but only in private form. So I’ll explain how to use both to have a preference pane that upgrades correctly.

The killer solution

So how do we tell an application kill and relaunch itself? We first create a second process whose job is to relaunch the application, then we call exit(0) from inside System Preferences:

BOOL ReopenPreferences(NSBundle *prefBundle) {
    NSLog(@"Restarting System Preferences...");

    const char *prefPath = [[prefBundle bundlePath] UTF8String];
    const char *execPath = [[[prefBundle resourcePath] 
      stringByAppendingPathComponent:@"RestartPref"] UTF8String];

    if (fork() == 0) {
        // Execute RestartPref in a new process.
        execl(execPath, execPath, prefPath, nil);
    }
    // Exit system preferences (quite drastic, I know!).
    exit(0);
}

I could have use a more Cocoaesque way to do the above (using NSTask) but I was more familiar with the Posix-style API, so I here I use fork to create a child process and execl to execute a secondary program in that process.

The program run in the secondary process is called “RestartPref” and is stored in the preference pane’s resources. The program is quite short:

int main(int argc, char **argv) {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    // Just open given file
    [[NSWorkspace sharedWorkspace] 
      openFile:[NSString stringWithUTF8String:argv[1]]];

    [pool release];
    exit(0);
}

This will just make the workspace open the file given in argument one; in this case, the file is our preference pane at the location it was installed. The user will see the System Preference window reappear showing the newly-installed preference pane.1

The private eraser

Returning to the base problem, all we really need to do is clear the cache in our NSBundle instances. Restarting System Preferences is just an extreme way to do that in the absence of a better mechanism.

It turns out that there is one such mechanism. Dave Keck found a function to do that. Unfortunately it’s a private API2, so it might be removed or changed in future versions of Mac OS X and we can’t really count on it being there. Still, for now we can use it with some care. Here is how Dave does it:

// First, we declare the function. Making it weak-linked 
// ensures the preference pane won't crash if the function 
// is removed from in a future version of Mac OS X.
extern void _CFBundleFlushBundleCaches(CFBundleRef bundle) 
  __attribute__((weak_import));

BOOL FlushBundleCache(NSBundle *prefBundle) {
    // Before calling the function, we need to check if it exists
    // since it was weak-linked.
    if (_CFBundleFlushBundleCaches != NULL) {
        NSLog(@"Flushing bundle cache with _CFBundleFlushBundleCaches");
        CFBundleRef cfBundle =
           CFBundleCreate(nil, (CFURLRef)[prefBundle bundleURL]);
        _CFBundleFlushBundleCaches(cfBundle);
        CFRelease(cfBundle);
        return YES; // Success
    }
    return NO; // Not available
}

So that’s it. You just call _CFBundleFlushBundleCaches on the equivalent CFBundle whenever you detect a version mismatch and this’ll fix it.

Note that CFBundle isn’t freely-bridged with Cocoa — you can’t just cast a NSBundle* to a CFBundleRef like you can with many other types — so we need to create a CFBundle ourself to clear the cache. This works since we’re creating the CFBundle using the same URL, so we’ll get the same instance of CFBundle. And because the NSBundle we have just uses CFBundle under the hood, clearing the cache on the CFBundle instance also clears it for Cocoa.

Still, since it’s a private API, you can’t really count on it being always present. Moreover you can’t really count on NSBundle to be implemented that way either. For the case where this fails, you can always fall back to the killer solution.

The fable, finished

In the last post I’ve shown how to detect the problem and when to call ReopenPreferences during a preference pane’s initialization. Let’s now add the cache cleaner as the first solution and use the restart only as a last resort:

- (id)initWithBundle:(NSBundle *)bundle {
    static NSString *const expectedVersion = @"1.3";
    NSString *bundleVersion = [[bundle infoDictionary] 
      objectForKey:(NSString *)kCFBundleVersionKey];

    if (![bundleVersion isEqual:expectedVersion]) {
        NSLog(@"Preference pane version mismatch.");
        BOOL cacheCleared = NO;
        if (FlushBundleCache()) {
            // Check again to make sure it worked
            NSString *bundleVersion = [[bundle infoDictionary] 
              objectForKey:(NSString *)kCFBundleVersionKey];
            cacheCleared = [bundleVersion isEqual:expectedVersion];
        }
        if (!cacheCleared) {
            ReopenPreferences(bundle);
            exit(0);
        }
    }
}

And now the problem is fixed much more elegantly: as long as the private API exists and has the expected effect on our NSBundle instance, we won’t to restart System Preference. Thank you Dave for the tip.

That said, it’d be much nicer if Apple themselves could fix their bug in System Preferences. (If you are someone at Apple who can fix this, please see rdar://7890447).


  1. Note that this isn’t exactly what Magic Launch is doing. Magic Launch does a couple of things when first opening after an update and I feared that the System Preference window would take too much time to appear. Instead of the simple relauncher program above, I’m sending AppleEvents to System Preferences so that first the window appears and then Magic Launch opens. This is probably overkill for any normal preference pane so I’m only showing the simpler method here. ↩︎

  2. The API is private, but since Core Foundation is open source you can easily find _CFBundleFlushBundleCaches’s declaration in the header file and its implementation in the source file↩︎


Making their jobs easier

Apple isn’t going to support such layers itself, open source or not. And while individual developers using such layers could, in theory — in a hypothetical future scenario where the intermediary layer becomes incompatible or incomplete — fix it themselves, that’s not realistic. Developers using something like, say, MonoTouch or Flash to write iPhone apps are not signing up to be responsible for future maintenance of the entire underlying framework they’re building upon. The whole reason they want to use these intermediary meta-platforms is because they think they’re making their jobs easier. — John Gruber, replying to my reconciling proposal.

So developers wants tools to make their job easier. Very true. But making someone’s job easier is what creates advances in programming, otherwise we’d still be stuck with assembler. Who wants to take the “difficult” path and write assembler code nowadays? We all use mostly portable higher-level languages (such as C), except for the small occasional snippets of assembler when high-performance is required.

Good and well-informed programmers will choose the right tool to solve the problem at hand, and if the tool isn’t a good enough fit they’ll improve it as needed. Both proprietary tools (such as Flash) or imposed choices (such as Apple’s kindergarten of C, C++, Objective-C and no translation layer nor third-party frameworks) prevents improving the tools and thus building upon those improvements.

So with this rule Apple ensures only it can advance the tools used to develop on the platform. It’s becoming more like Flash where Adobe dictates both the platform and the development environment.

Back in the old Mac OS days, PowerPlant helped a lot of developers build quality apps which would have been harder to write directly on the Mac toolbox. How? By enabling easy reuse of existing components through object-oriented programming and inheritance, something that wasn’t easily doable with the original C/Pascal API. Apple didn’t really catch up until years later, with Mac OS X and Cocoa. It’s important to remember that before becoming a liability because of it’s pervasive use and the lack of update, PowerPlant was really an asset for the platform.

I don’t know which form will take the next fundamental advance in programming, but iPhone OS programmers might very well be locked out of it until Apple realizes its importance and rework its API to support it.

But that’s a pretty pessimistic view. Optimistically, Apple will just reject things it really doesn’t like and this won’t include too many things. Nonetheless, this rule, even if only half-enforced, will surely scare many innovators away from the platform. I can’t see this standing in the long term.


Multi-Safari Downloads

A couple of years ago, Stefan Skotte offered me to host the files for the standalone versions of Safari modified to run on newer OS X version. Multi-Safari has been quite useful to many web developer seeking to test their website on earlier browsers. Last week, Stefan’s server came down — I don’t know why, I haven’t been able to contact him — which prompted me to make other arrangements.

As an experiment, I’ve setup a BitTorrent tracker to distribute those files. So you will now need a BitTorrent client to download the files in a true peer to peer manner. Go look at Transmission or µTorrent if you don’t already have a BitTorrent client.

In conclusion, I hope nothing bad happened to Stefan (or his server), but I want to thank him for the few years he helped distribute Multi-Safari to the world.



  • © 2003–2024 Michel Fortin.