木匣子

Web/Game/Programming/Life etc.

几个与文件系统有关的坑

入职 Monkii 后,按自己的喜好选了 iMac 作为工作环境。不料一上来就给我安排了一个用 .Net 作后端的项目,让我负责前端。人在江湖身不由己,只好折腾起 Windows 。

Case-sensitive

在这之前想做一次系统迁移,把之前配置好的环境从另一台 iMac 弄过来。苹果的迁移助手非常厉害,直接通过 Wifi 就可以迁移系统。不过这次不灵了!迁移助手无法在 Case-sensitve Filesytem 与 Case-insensitve Filesystem 之间做系统迁移!这才意识到,在用的这台电脑在装机的时候被老大搞成了大小写敏感的文件系统。

Steam

以前从来没注意这个问题,觉得这没什么问题,大小写敏感还增加了文件命名空间,不是挺好吗。直到我装了 Steam 后发现怎么也打不开,一直卡在登陆界面。

通过终端运行 Steam ,看到了打印出来的日志:

Errors in public/subpanelwelcomeintro.res:
error loading file 'public/subpanelwelcomeintro.res', no such file
Errors in public/subpanelwelcomecreatenewaccount.res:
error loading file 'public/subpanelwelcomecreatenewaccount.res', no such file
Errors in public/subpanelwelcomecreatenewaccountaccountname.res:
error loading file 'public/subpanelwelcomecreatenewaccountaccountname.res', no such file
Errors in public/subpanelwelcomecreatenewaccountemail.res:
error loading file 'public/subpanelwelcomecreatenewaccountemail.res', no such file
...

才发现 Steam 的加载器全部以小写文件名加载文件,而目录中的文件名则是驼峰式的,(e.g. SubPanelWelcomeIntro.res)。只好暂时写个脚本将所有文件名转成小写,终于可以正常打开 Steam 了。不过在每次 Steam 更新后,都得重做这一步骤。

Webpack

BTW,自动化打包工具在 Case-sensitive 的文件系统上常常也会出各种问题。以下是在项目中使用 ScrollMagic.js 时遇到的警告:

// include ScrollMagic library and its jQuery Plugin
require('scrollmagic')
require('scrollmagic/scrollmagic/uncompressed/plugins/jquery.ScrollMagic')

在打包的时候会出现下面的提示:

WARNING in ./~/ScrollMagic/scrollmagic/uncompressed/ScrollMagic.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* G:\Sites\Secret-Project\node_modules\ScrollMagic\scrollmagic\uncompressed\ScrollMagic.js
    Used by 1 module(s), i. e.
    G:\Sites\Secret-Project\node_modules\scrollmagic\scrollmagic\uncompressed\plugins\jquery.ScrollMagic.js
* G:\Sites\Secret-Project\node_modules\scrollmagic\scrollmagic\uncompressed\ScrollMagic.js
    Used by 1 module(s), i. e.
    G:\Sites\Secret-Project\node_modules\babel-loader\lib\index.js!G:\Sites\Secret-Project\src\entry-client.js

原因是 jquery.ScrollMagic.js 使用 UMD 定义库引用的时候,使用了驼峰式:define(['ScrollMagic', 'jquery'], factory);,所以 Webpack 给出了警告。

(function (root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(['ScrollMagic', 'jquery'], factory);
	} else if (typeof exports === 'object') {
		// CommonJS
		factory(require('scrollmagic'), require('jquery'));
	} else {
		// Browser global
		factory(root.ScrollMagic, root.jQuery);
	}
}(...));

解决办法是全部使用小写。不过还好这个项目放在 NTFS 分区,暂时正常。

ExFAT

iMac 用的是 128G 的 SSD,有点小。分区装个 Windows 后就不顶用了。于是从同事那弄了个 128G 的扩展 SSD 。这货只能格式化成 ExFAT 或 NTFS 格式。不过 ExFAT 这个文件系统可以同时在 macOS 和 windows 支持读和写,凑合用吧。

Block Size

后来才发现,ExFAT 的最小文件块大小居然是 512KB!对于前端来说简直是恶梦!因为前端会使用 NPM 管理大量的第三方库,这些库基本上就是成千上万个小文件。感受一下数据:

Contains: 15,766 Files, 2,028 Folders
Size:72.9 MB (76,526,168 bytes)
Size on disk: 1.93 GB (2,083,258,368 bytes)

70M 左右的文件放在 ExFAT 上居然占了接近 2G,而在 NTFS 上只有不到 90M 。

另一个坑是,ExFAT 是不支持软链的。一些需要 Symlink 支持的项目没办法放在 ExFAT 文件系统中。像是使用 broccoli.js 打包的前端库,还有运行在 Vagrant 里,需要与外部文件系统建立联系的时候:

ln: creating symbolic link `dist`: Protocol error

最后只好再在这个扩展 SSD 上分了个 NTFS 的区来用。

File Permissions

September 9, 2019 补充: 在一次处理 Vagrant 链接问题的时候发现放在 ExFAT 分区的 vagrant.d 配置目录里的 insecure_private_key 无法使用,因为权限给的太宽:

D:\.vagrant.d>ssh-keygen -y -f insecure_private_key > ./insecure_public_key.pub
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for 'insecure_private_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "insecure_private_key": bad permissions

并且无法修改,后来一查才知道,原来 ExFAT 是没有权限控制的,相当于整个硬盘都是0777。解决方案是将其移动到其它盘符下再处理。

所以请不要把重要的文件放在 ExFAT 盘中,尤其是密钥。

Summary

文件系统还是尽量使用大小写不敏感为好。ExFAT 之类的 SSD 比较适合放媒体文件,不适合存放代码。