先来张效果图
零
网上已经有的方法都比较麻烦,而且在新版系统中大多已经失效。我试过的还可以用的方法(在 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 编译。
如果不出意外的话,会报错,提示 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 分区试试看?