nextcloud中,一个用户可以将自己的目录或者文件分享给另外一个文件,任何一方对文件修改,对双方都是一致可见的。分享类似于文件系统中的软链接,其实指向的都是同一个节点。
在nextcloud中,分享的实现原理是挂载。如user1的文件file1分享给user2,则实际上是将文件/user1/files/file1 挂载到/user2/files/file1这个路径,这样,user2便能查看到file1这个文件,对这个文件的修改,也实际上是在修改/user1/files/file1这个文件。
分享的挂载是在nextcloud的文件系统初始化的时候执行的,在分享挂载的过程中,挂载点实际上是会变的,分享插件会检查挂载点是否可用,如果不可用则寻找一个父目录存在且文件路径不与已有文件重复的新路径挂载。
如file1指定的挂载点是dir/dir2/file1,但是用户把dir2删除了,那么分享插件就会将挂载点改成/file1,如果这个路径下已存在,则尝试"/file1 (2)"这个路径,失败则继续尝试。
分享挂载点自动迁移是一个隐形的坑,想要避免挂载点被迁移,就需要保证父目录存在。
也是因为如此,所以在nextcloud的文件系统初始化的过程中,存储实例的挂载是有先后顺序的。
在用户挂载的实现函数MountProviderCollection::addMountForUser()中,便可以看到,先挂载的非分享存储,后挂载分享。
public function addMountForUser(IUser $user, IMountManager $mountManager) {
// shared mount provider gets to go last since it needs to know existing files
// to check for name collisions
$firstMounts = [];
$firstProviders = array_filter($this->providers, function (IMountProvider $provider) {
return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
});
$lastProviders = array_filter($this->providers, function (IMountProvider $provider) {
return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
});
foreach ($firstProviders as $provider) {
$mounts = $provider->getMountsForUser($user, $this->loader);
if (is_array($mounts)) {
$firstMounts = array_merge($firstMounts, $mounts);
}
}
$firstMounts = $this->filterMounts($user, $firstMounts);
array_walk($firstMounts, [$mountManager, 'addMount']);
$lateMounts = [];
foreach ($lastProviders as $provider) {
$mounts = $provider->getMountsForUser($user, $this->loader);
if (is_array($mounts)) {
$lateMounts = array_merge($lateMounts, $mounts);
}
}
$lateMounts = $this->filterMounts($user, $lateMounts);
array_walk($lateMounts, [$mountManager, 'addMount']);
return array_merge($lateMounts, $firstMounts);
}
也就是如此,在Home存储挂载之后,分享才能个基本的挂载点。如果有外部存储,或者自行提高的存储方式,分享也才能找到正确的挂载点,避免自动迁移到错误的目录下。
网友评论