美文网首页
【折腾】开启 macOS 上原生的 NTFS 读写功能

【折腾】开启 macOS 上原生的 NTFS 读写功能

作者: _菜菜 | 来源:发表于2017-04-05 16:56 被阅读1708次

    先来张效果图


    效果图

    网上已经有的方法都比较麻烦,而且在新版系统中大多已经失效。我试过的还可以用的方法(在 10.12 中)只剩下修改 fstab 这一种了。很繁琐,每次插新设备都要改 fstab 表,还要重启后才能生效,更重要的是在 Finder 中找到分区位置还稍微有点麻烦。于是我想能不能从根源入手,(几乎)一劳永逸地解决这个问题。

    首先说一下这么折腾的优缺点。优点是省钱(Paragon 和 Tuxera 做的 NTFS 驱动都是付费的),原生,比较满足一些原生党的心理诉求;缺点的话,性能可能不如第三方的高,毕竟术业有专攻,功能也可能会有所缺失,并且由于涉及到系统文件的修改,还会禁用系统完整性保护(SIP)功能。

    然后是需要准备什么。一台 Mac,带与系统版本相匹配的 SDK 的 Xcode,然后就是苹果自己做的 macOS 版 NTFS 的代码。前两个不用说,第三个的话,可以在 https://opensource.apple.com 里下载的到。

    下载解压,打开 ntfs.xcodeproj,找到 kext 下面的 ntfs_vfsops.c,按 ⌘F 搜索 MNT_DONTBROWSE,最新版(ntfs-91.50.2)代码里会找到两处,把相关代码注释掉

        if ((vfs_flags(mp) & MNT_DONTBROWSE) == 0 && !vfs_isupdate(mp))
            vfs_setflags(mp, MNT_RDONLY);
    

    和这里

        if (vfs_isrdwr(mp))
            vfs_setflags(mp, MNT_DONTBROWSE);
    

    在工具栏中选 ntfs.kext -> My Mac (64-bit),然后按 ⌘B 编译。


    不要选成 32-bit 的

    如果不出意外的话,会报错,提示 lck_rw_t 类型不完整之类的,按住⌘点进去大概是这个样子的

    #ifndef _I386_LOCKS_H_
    #define _I386_LOCKS_H_
    
    #include <sys/appleapiopts.h>
    #include <kern/kern_types.h>
    
    
    typedef struct __lck_spin_t__   lck_spin_t;
    
    typedef struct __lck_mtx_t__        lck_mtx_t;
    typedef struct __lck_mtx_ext_t__    lck_mtx_ext_t;
    
    typedef struct __lck_rw_t__ lck_rw_t;
    
    
    #endif
    

    而苹果并没有给出譬如 __lck_spin_t__ 之类的结构体的确切定义。
    我在追根溯源的时候翻遍了 XNU 的代码,在从 XNU 生成的内核开发用的头文件中,我找到了可以用的这几个结构体的原型。

    typedef struct {
        unsigned long    opaque[10];
    } lck_spin_t;
    
    typedef struct {
        unsigned long       opaque[2];
    } lck_mtx_t;
    
    typedef struct {
        unsigned long       opaque[10];
    } lck_mtx_ext_t;
    
    
    #pragma pack(1)
    typedef struct {
        uint32_t        opaque[3];
        uint32_t        opaque4;
    } lck_rw_t;
    #pragma pack()
    

    用其替换掉原来的四个 typedef,重新按 ⌘B 编译就得到了 ntfs.kext。

    苹果曾经开放过 NTFS 的读写,但是不知道什么原因又禁用了,开发者在 mount_ntfs 里加了一行代码防止默认挂载为读写。
    在 mount 中的 mount_ntfs.c 的 main() 函数中找到并注释掉这一行

    /* Default to mounting read-only. */
        flags = MNT_RDONLY;
    

    然后选好,⌘B。

    放心,你依旧不会成功
    会提示缺少头文件 mntopts.h,这个文件说实话害的我苦找了好几个小时,因为一开始搜的话搜到的都是 FreeBSD 相关的,但是 FreeBSD 的这个文件和 macOS 的还有点小区别,导致不能用。后来我在这里找到了 macOS 用的头文件,要么扔到 SDK 的 include 文件夹中,要么直接拖进工程然后把 #include <mntopts.h> 改成 #include "mntopts.h",依个人喜好而定。
    最后 ⌘B,完成。

    准备工作都做完了,剩下的就是把系统原来的文件都替换掉了。重启按 ⌘R 进恢复环境,选实用工具菜单,启动终端,输入 csrutil disable,按下回车,关掉 SIP。因为 SIP 会阻止用户替换系统文件和加载未经签名的 kext。当然副作用是恶意软件更容易提权对系统造成危害。

    别问我怎么在恢复环境里截图的,这是技巧
    重启之后先运行 kextstat | grep ntfs 确认 ntfs.kext 没有被加载
    或者其他的方法也行,能确认就好
    然后打开 ntfs.xcodeproj,在 Products 中点选 mount_ntfs 或 ntfs.kext 任一项,右键点选 Show in Finder
    好磨叽啊有没有
    我非要在这再加一张图
    用终端把原来的 mount_ntfs 和 ntfs.kext 备份一下
    sudo mv /sbin/mount_ntfs /sbin/mount_ntfs_orig
    sudo mv /System/Library/Extensions/ntfs.kext /System/Library/Extensions/ntfs_orig.kext 
    

    然后再把这两个分别 cp 到对应位置,不能直接复制不然权限会乱
    比如我的在 /Users/alpine/Library/Developer/Xcode/DerivedData/ntfs-ccnxpvhcviyiuqcqzyqzrkoibcpc/Build/Products/Development/ 这里,如果你找不到的话,从 Finder 拖进终端里就行了

    sudo cp -r /Users/alpine/Library/Developer/Xcode/DerivedData/ntfs-ccnxpvhcviyiuqcqzyqzrkoibcpc/Build/Products/Development/ntfs.kext /System/Library/Extensions/
    sudo cp /Users/alpine/Library/Developer/Xcode/DerivedData/ntfs-ccnxpvhcviyiuqcqzyqzrkoibcpc/Build/Products/Development/mount_ntfs /sbin
    

    这次挂一个 NTFS 分区试试看?

    相关文章

      网友评论

          本文标题:【折腾】开启 macOS 上原生的 NTFS 读写功能

          本文链接:https://www.haomeiwen.com/subject/hbotattx.html