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

2017-04-05  本文已影响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 分区试试看?

上一篇下一篇

猜你喜欢

热点阅读