2015年12月14日月曜日

OwnCloud 8でシンボリックリンクを有効にする方法

Simple Solution:

Comment out lines 343-345 in ${owncloud}/3rdparty/league/flysystem/src/Adapter/Local.php
that check if the file is link or not.  Please see following Japanese description part if you want to see what is the code regarding to.

Then, you will re-activate the function for following symbolic link within your local data folder in ownCloud 8.2.1.

Only those three lines are the part for blocking traversal of {sym,hard}links in current implementation.


やってみたらできたのでご報告。

OwnCloud 7までは、利用者の共有領域からシンボリックリンクで外部ディスクのフォルダやファイルを指してもデータベースに登録できたのですが、OwnCloudでは「禁止」となりました。

参照:ownCloud Does Not Follow Symlinks (ownCloud 8.0 Release Note)
ownCloud’s file scanner does not follow symlinks, which could lead to infinite loops. To avoid this do not use soft or hard links in your ownCloud data directory.
シンボリックリンクは適当に張っていくと無意識にループを作ってしまうことがあり、そんな状態のファイルシステムをたどってデータベースにファイル登録する作業をかけるとまずいという意図はよくわかります。でもそれはそれで使い勝手がよろしくない。

検索してみるといくつか質問があり、公式フォーラムでは、逆にライブラリ本体をownCloudの管理下に置いて、他のアプリ用に通常の場所からシンボリックリンク張って使ってますよという話が出ていたりするわけです。

しかし、外付けの大容量HDDに整理したライブラリがあるのに、そこにownCloud本体を置いて、data/${ユーザ名}/files以下に移動するというのもどうなのかと思って調べてみました。ちなみに、この場合はWebサーバ側の設定で外付けHDDに置いたownCloudをrootに設定するとか、Webサーバから見える適当な場所にシンボリックリンクを貼るとかすることになります。

それで、ownCloud 8では外部のクラウドと連携してownCloud側でまとめるようなアプリの実現に、PHPライブラリのLeague\Flysystemを最初から内蔵することで対応しておりました。Amazon S3, Dropbox, SFTP, WebDAV, Azureなど数多くの外部サービスをローカルファイルと同様のAPIでアクセスする設計であります。なんか、既存のDropBox, AWS, Google Drive, SMB対応とかぶってるような気がしないでもないですが、徐々に統合されていくのでしょうか。

FlysystemにおけるローカルファイルのモジュールはLOCALでありまして、ドキュメントに「ルートからのパスの一貫性を破壊するからリンクはサポートしない」ということが宣言されており、結局それをownCloud 8が引き継いでいるのが、シンボリックリンク非対応の真相でありました。逆に、ownCloud側の${owncloud}/lib/private/files/storage/local.phpではリンクの場合リンク先のパスを調べ直す処理が残っていて、ownCloudが積極的にリンクを排除することを現状ではやっていないようです。

ownCloud同梱のFlysystemでは、

${owncloud}/3rdparty/league/flysystem/src/Adapter/Local.php

がLOCALファイルシステムの実装でして、343〜345行目あたり、normalizeFileInfo(SplFileInfo $file)メソッドの先頭の、
if ($file->isLink()) {
    throw NotSupportedException::forLink($file);
}
の3行が該当部分という、わりとあっさりな結論。このforLink()メソッドはただエラーメッセージを含む例外オブジェクトを返すだけの簡単な処理であります。びっくり。

この状態でownCloud 8.2.1を初期設定からやり直すと、あらびっくり、シンボリックリンク追跡機能が復活です。しっかり、外付けHDDに構築したライブラリがモバイルアプリから参照でき、ダウンロードして再生することができました。

あんまりにもあんまりなので、遠からず、しっかりリンクを排除するよう改善されると思いますが、検索でいろいろ質問が出る割には簡単な話だったので、ご報告する次第です。

いや、これはあれですか、公然の秘密ってやつなんでしょうか。だとしたら野暮な話でありました。