Apple/OS X

OSX Lion 에서 NTFS 쓰기

뭉기 2012. 8. 9. 22:03

NTFS WRITE SUPPORT ON OSX LION WITH NTFS-3G

출처 : http://fernandoff.posterous.com/ntfs-write-support-on-osx-lion-with-ntfs-3g-f

Update 2: Check out this post for a prebuilt binary installer for NTFS-3G that can be used with the Fuse4X solution detailed below (i.e., if you're not willing to go through all the steps of installing XCode, MacPorts, etc. that's detailed below, you can just install Fuse4X binary (fromhere) and the NTFS-3G installer I'm providing on the post linked above).

Update: Thanks to some suggestions from Marcos on the comments below, I kicked myself back into trying to solve the mount problem with uids/gids on fuse4x / ntfs-3g. I've updated the script below, it now improves things somewhat. It's still not perfect - it'll work fine if your user logs in automatically, otherwise, it'll try to wait for 20 seconds (adjustable on the TIMEOUT variable) until the user session is active and it picks up the user id from the session started, and if that too fails, it falls back to the old behavior (fixed uids/gids). There's also an alternative solution for that provided by Marcos on the comments area of his post, check it out (in portuguese - Google Translate is your friend).


It's a well known fact that OSX had NTFS read support for a long time, but write support could only be easily enabled either by:

  • Buying third-party solutions, from Paragon or Tuxera. The latter is actually a product-fied version of the open-source solution mentioned below;
  • Enabling manually on the native driver by messing around with system files. That option is known to be very unstable and can potentially corrupt your NTFS partition, so it's strongly NOT recommended. Also, this worked only on early versions of Snow Leopard - apparently Apple disabled this "feature" later (though it seems nobody tried it again with Lion). It's obvious that with this move Apple was clearly saying that the driver is not reliable for write support and should not be used as such.
  • A port of MacFuse and NTFS-3G provided by Tuxera. The official versions are old and don't work at all on 64-bit kernels (i.e. Lion).

    On the last case, there are unofficial builds of MacFuse that work on 64-bit kernels, but not without a few issues - this post will outline the steps on getting this unofficial version of MacFuse working along with the older version of NTFS-3G (the version that was still free, before Tuxera went completely commercial with it). Also, while most of the procedures detailed here were tested in my OSX Lion installation, it should in theory work on Snow Leopard too, I just have no way to confirm this at this time. Feedback is welcome on that.

    I'm also going to outline the steps on getting to work a solution based purely on MacPorts, a package manager for OSX that works by downloading the source code to a package, compiling it on your machine, and installing it. That solution works fine for the most part, with only a small caveat, that may or may not affect you depending on how you work with your Mac. In my opinion, though, this solution is also more robust and (hopefully, once the small kinks get worked out) bug-free solution and easier to maintain and update (thanks to MacPorts) on the long term, and I hope it gets noticed by the developers involved because of that. I'm personally using this solution right now, but due to it being somewhat more cumbersome to setup, it probably should be taken as geared towards power users - if you want something a bit easier to setup, you're probably better off with the MacFuse + Tuxera's NTFS-3G solution presented below.

    Before we start: While the steps I outline here are more or less foolproof, you'll be in fact messing around with a little bit of the inner workings of OSX. In theory, what you'll do shouldn't completely wreck your system (at worst, you'll no longer be able to mount your NTFS partitions), but the standard disclaimers apply: Any problems caused by what you'll do henceforth are entirely YOUR responsibility, not mine. If your system stops working correctly, if your NTFS partition gets corrupted, if your system blows up to pieces, etc. - it's YOUR fault. Also, since the procedures outlined here modifies system files and needs you to work mostly on the Terminal, some experience with working with the terminal and the bash shell is, while not required, advised, specially in the case you bump into problems. If you're not confortable with that and absolutely need NTFS write support, do me and yourself a favor, and buy one of the paid solutions mentioned above.

    I'll start with the easier solution (for now), since I suppose this will be the one that most people will end up going with as it requires less pre-setup procedures.

    And before you start either of the procedures below, umount your NTFS volume first(right-click / ctrl+click the volume icon on the desktop and select "Eject").

     

    MacFuse + NTFS-3G (older open-source release from Tuxera)

    Get the latest open-source version of NTFS-3G by Tuxera from here and only here - don't get anything newer than that, that would be Tuxera's commercial version, and it'll require you to buy it after the 15-day trial.

    For a 64-bit supported MacFuse, there are two options: this (use the link for the file macfuse-core-10.5-2.1.9.zip) or this. The former is the last open-source version of MacFuse from Tuxera patched by an independent developer to work on 64-bit. The latter is a patched version of a newer version (2.1.15) meant for Wuala's app - although, for our purposes, it should work with NTFS-3G just as well. There are no notable or even documented differences between the older and the newer, so the choice is up to you - during testing, I've used both without problems.

    Unpack the zip file for MacFuse and double-click the pkg file to install. Next, install NTFS-3G from the link above. Once it's done, you'll be requested to restart - do so.

    Once it comes back up, a few moments after the desktop comes up, you'll be greeted by something like this:

    Yeah, that's the issue I mentioned early on. It's not an usability issue, i.e. the partition will be mounted read-write correctly (even though it says on the dialog it wasn't), and you'll be able work with it without any problems or corruption issues, as far as I'm aware. The issue is really just that nagging dialog that pops up every time you mount a NTFS volume, including on boot in this case, if you've got a Windows install on your Mac like me. In short, everything works fine despite that dialog.

    The problem seems to stem from the binary "fuse_wait" from NTFS-3G that's run as a final part of the mounting procedure - for some reason it can't detect that ntfs-3g mounted the volume and stays on a hopeless loop trying to detect this condition until it gives up after 15 seconds. So my workaround involves replacing the fuse_wait binary with a script that does more or less the same thing, but actually detecting (sort of) the mount operation and not timing out.

    Open a Terminal window. First of all, make a backup of the original binary:

    sudo mv /usr/local/bin/fuse_wait /usr/local/bin/fuse_wait.orig

    Then create the file that'll hold our script and setup the proper permissions for it:

    sudo touch /usr/local/bin/fuse_wait
    sudo chmod 0755 /usr/local/bin/fuse_wait
    sudo chown 0:0 /usr/local/bin/fuse_wait

    Now, let's edit the file so we can paste our script into it:

    sudo nano /usr/local/bin/fuse_wait

    Here's the script, paste it into the editor:

    #!/bin/bash
    
    MNTPOINT=$1
    shift
    TIMEOUT=$1
    shift
    MNTCMD=$1
    shift
    
    $MNTCMD "$@" &> /var/log/ntfsmnt.log
    MNTCMD_RETVAL=$?
    
    if [ $MNTCMD_RETVAL -eq 0 ]; then
            until [ `/sbin/mount | /usr/bin/grep -c "$MNTPOINT"` -ge 1 ] || [ $TIMEOUT -eq 0 ]
            do
                           sleep 1
                    let TIMEOUT--
            done
    fi
    
    [ $TIMEOUT -eq 0 ] && RETVAL=1 || RETVAL=$MNTCMD_RETVAL
    
    exit $RETVAL;

    Press CTRL+X, say Yes to save the file, and press Enter to accept the file name.

    Next, we'll edit another file. Still on the Terminal, type:

    sudo nano /System/Library/Filesystems/ntfs-3g.fs/ntfs-3g.util

    We're on nano again. Find the line that looks like this:

    DEFAULT_NTFS_MOUNT_OPTIONS="auto_xattr"

    Add some options to the end so it looks like this:

    DEFAULT_NTFS_MOUNT_OPTIONS="auto_xattr,noatime,auto_cache"

    Again, CTRL+X, say Y to save and press Enter.

    That's it. Reboot, and you should no longer get the error dialog the next time you mount your NTFS partition. If you have any problems, look into the file /var/log/ntfsmnt.log, it should contain some description of any problems found during mount, but I hadn't any so far.

     

    Fuse4x + NTFS-3G from MacPorts

    Fuse4x is a fork of MacFuse intended to bring the old and abandoned MacFuse codebase up to date, and also improve compatibility with the Fuse upstream project, while maintaining compatibility with existing filesystems for MacFuse.

    To get it working, you'll need to install Xcode on your system - if you're on Lion, Xcode's a free download from the App Store. Since MacPorts works by compiling every package you ask to install, there's no way to escape that. You may uninstall Xcode after you install the packages you need, but then you'll lose the ability to easily upgrade packages (using port upgrade) once new versions are released - you'll need to install Xcode again for that.

    Once you get Xcode installed, get MacPorts and install it.

    Done? Ok, after you get all this installed, open a terminal window and type:

    javac

    That should pop up an Apple Update window asking if you'd like to install a Java update and some such. Do that. That's really just a small precaution - if you don't do that now, that window will popup during the build process on MacPorts - in my case, since I wasn't prepared for it, the Java update kept downloading on the background while MacPorts was still building the dependencies for Fuse4x and NTFS-3G. The build process completed sucessfully despite that though, so Java is probably not a required dependency, but it doesn't hurt to be careful, so I recommend to get this missing Java dependency installed first so your build process go without surprises.

    Now that you have the Java dependency installed, we can get to the real meat. First, if you haven't done that yet, update your MacPorts repository:

    sudo port selfupdate
    sudo port upgrade outdated

    Install NTFS-3G - as NTFS-3G now depends on Fuse4x by default (which wasn't the case back when this article was first written), using the command below should install Fuse4x automatically before installing NTFS-3G:

    sudo port install ntfs-3g

    Ok, at this point you should have a functional fuse4x and ntfs-3g install. Unfortunately, since most MacPorts packages are really just the straight source-code for their upstream project with only a few patches to make it compilable on OSX, those packages most often don't really integrate well with the workflow of the system, specially UI-wise (e.g., there are no preference panes for Fuse4x or NTFS-3G). Most importantly, that means that this ntfs-3g install won't automount NTFS volumes at boot or volume insertion (for removable disks) - this would still be done by the standard NTFS driver on OSX. Due to the nature of how most packages are ported over to MacPorts, you'd be expected to mount your NTFS volumes via NTFS-3G manually, via the terminal, which sucks. We'll have to hack our way around to get that working somewhat better.

    The idea is to trick OSX into redirecting the automount procedure for OSX's native NTFS to use NTFS-3G instead. Still on the terminal, make a backup of the file mount_ntfs, which is responsible for mounting NTFS volumes with the native driver:

    sudo mv /sbin/mount_ntfs /sbin/mount_ntfs.orig

    Again, create an empty file, setup the permissions, and open it in an editor:

    sudo touch /sbin/mount_ntfs
    sudo chmod 0755 /sbin/mount_ntfs
    sudo chown 0:0 /sbin/mount_ntfs
    sudo nano /sbin/mount_ntfs

    Ok, we're almost there. Paste this script in the editor:

    #!/bin/bash
    
    VOLUME_NAME="${@:$#}"
    VOLUME_NAME=${VOLUME_NAME#/Volumes/}
    USER_ID=501
    GROUP_ID=20
    TIMEOUT=20
    
    if [ `/usr/bin/stat -f "%u" /dev/console` -eq 0 ]; then
            USERNAME=`/usr/bin/defaults read /library/preferences/com.apple.loginwindow | /usr/bin/grep autoLoginUser | /usr/bin/awk '{ print $3 }' | /usr/bin/sed 's/;//'`
            if [ "$USERNAME" = "" ]; then
                    until [ `stat -f "%u" /dev/console` -ne 0 ] || [ $TIMEOUT -eq 0 ]; do
                            sleep 1
                            let TIMEOUT--
                    done
                    if [ $TIMEOUT -ne 0 ]; then
                            USER_ID=`/usr/bin/stat -f "%u" /dev/console`
                            GROUP_ID=`/usr/bin/stat -f "%g" /dev/console`
                    fi
            else
                    USER_ID=`/usr/bin/id -u $USERNAME`
                    GROUP_ID=`/usr/bin/id -g $USERNAME`
            fi
    else
            USER_ID=`/usr/bin/stat -f "%u" /dev/console`
            GROUP_ID=`/usr/bin/stat -f "%g" /dev/console`
    fi
    
    /opt/local/bin/ntfs-3g \
            -o volname="${VOLUME_NAME}" \
            -o local \
            -o negative_vncache \
            -o auto_xattr \
            -o auto_cache \
            -o noatime \
            -o windows_names \
            -o user_xattr \
            -o inherit \
            -o uid=$USER_ID \
            -o gid=$GROUP_ID \
            -o allow_other \
            "$@" &> /var/log/ntfsmnt.log
    
    exit $?;

    Press Ctrl+X, say Y to save, press Enter to accept the file name.

    Now, note the option -uid and -gid. It teels ntfs-3g which OSX user and group should own the files on the mounted volume. If you don't provide these options, ntfs-3g will default to the root user, which will allow you to do most writing operations on the volume except write/modify to existing files - to be able modify files, you should then specify the uid and gid for the login you use on your system. In a standard OSX installation, the uid 501 and gid 20 should be the first standard user you provided on OSX install, and the "staff" group, respectively. To make sure these uid and gid pair match the ones for the user you use on your system, type in the Terminal (make sure you're not on a root ("#") prompt):

    id -u && id -g

    This should output two lines, the first containing the id for your user, and the second the id of the default group for your user. If they don't match the ones on the script, edit the script again and modify it accordingly. Update: This is needed only in a worst case scenario where you have autologin disabled and you don't login manually within 20 seconds (adjustable in the TIMEOUT variable).

    Now, here's the caveat with the whole Fuse4x method: since we had to explicitly provide the uid and gid for the user/group that'll own the files on the volume in order to have full access to it, this means that this method will have problems in multi-user Mac stations.

    For example, if you have two users - say, john, and mary - on your Mac, john will have a uid of 501 and mary will have a uid of 502. If the mount script is setup as above, john will have full access to the volume, but mary, while being able to mount NTFS volumes just fine, won't be able to modify existing files on the volume, just like mentioned earlier when you don't provide the uid/gid parameter.

    There's no way out of that, as far as I know. I've tried a ton of argument combinations for ntfs-3g while trying to avoid the uid/gid arguments, nothing worked. I welcome suggestions. But for now, it works well enough for me as it is, I'm the only user on my Mac anyway, and I suppose that's the case for most Mac users, so I didn't bother to sweat about it too much. If that's really a problem for you though, then you should be better off with the MacFuse + Tuxera-NTFS-3G solution, that doesn't have this problem.

    Phew, that was a long one. Comments are welcome, of course. Cheers!