Fixed: Mono internals does not properly copy/move symlinks, but instead copies the contents.

This commit is contained in:
Qstick 2017-12-20 22:30:28 -05:00
parent c83353e7ee
commit a4e632d95a
3 changed files with 144 additions and 3 deletions

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -200,6 +200,11 @@ namespace NzbDrone.Common.Disk
throw new IOException(string.Format("Source and destination can't be the same {0}", source));
}
CopyFileInternal(source, destination, overwrite);
}
protected virtual void CopyFileInternal(string source, string destination, bool overwrite = false)
{
File.Copy(source, destination, overwrite);
}
@ -219,6 +224,11 @@ namespace NzbDrone.Common.Disk
}
RemoveReadOnly(source);
MoveFileInternal(source, destination);
}
protected virtual void MoveFileInternal(string source, string destination)
{
File.Move(source, destination);
}

View File

@ -1,4 +1,6 @@
using System;
using System;
using System.IO;
using FluentAssertions;
using Mono.Unix;
using NUnit.Framework;
using NzbDrone.Common.Test.DiskTests;
@ -35,5 +37,55 @@ namespace NzbDrone.Mono.Test.DiskProviderTests
entry.FileAccessPermissions &= ~(FileAccessPermissions.UserWrite | FileAccessPermissions.GroupWrite | FileAccessPermissions.OtherWrite);
}
}
[Test]
public void should_move_symlink()
{
var tempFolder = GetTempFilePath();
Directory.CreateDirectory(tempFolder);
var file = Path.Combine(tempFolder, "target.txt");
var source = Path.Combine(tempFolder, "symlink_source.txt");
var destination = Path.Combine(tempFolder, "symlink_destination.txt");
File.WriteAllText(file, "Some content");
new UnixSymbolicLinkInfo(source).CreateSymbolicLinkTo(file);
Subject.MoveFile(source, destination);
File.Exists(file).Should().BeTrue();
File.Exists(source).Should().BeFalse();
File.Exists(destination).Should().BeTrue();
UnixFileSystemInfo.GetFileSystemEntry(destination).IsSymbolicLink.Should().BeTrue();
File.ReadAllText(destination).Should().Be("Some content");
}
[Test]
public void should_copy_symlink()
{
var tempFolder = GetTempFilePath();
Directory.CreateDirectory(tempFolder);
var file = Path.Combine(tempFolder, "target.txt");
var source = Path.Combine(tempFolder, "symlink_source.txt");
var destination = Path.Combine(tempFolder, "symlink_destination.txt");
File.WriteAllText(file, "Some content");
new UnixSymbolicLinkInfo(source).CreateSymbolicLinkTo(file);
Subject.CopyFile(source, destination);
File.Exists(file).Should().BeTrue();
File.Exists(source).Should().BeTrue();
File.Exists(destination).Should().BeTrue();
UnixFileSystemInfo.GetFileSystemEntry(source).IsSymbolicLink.Should().BeTrue();
UnixFileSystemInfo.GetFileSystemEntry(destination).IsSymbolicLink.Should().BeTrue();
File.ReadAllText(source).Should().Be("Some content");
File.ReadAllText(destination).Should().Be("Some content");
}
}
}

View File

@ -96,11 +96,90 @@ namespace NzbDrone.Mono.Disk
return mount?.TotalSize;
}
protected override void CopyFileInternal(string source, string destination, bool overwrite)
{
var sourceInfo = UnixFileSystemInfo.GetFileSystemEntry(source);
if (sourceInfo.IsSymbolicLink)
{
var isSameDir = UnixPath.GetDirectoryName(source) == UnixPath.GetDirectoryName(destination);
var symlinkInfo = (UnixSymbolicLinkInfo)sourceInfo;
var symlinkPath = symlinkInfo.ContentsPath;
var newFile = new UnixSymbolicLinkInfo(destination);
if (FileExists(destination) && overwrite)
{
DeleteFile(destination);
}
if (isSameDir)
{
// We're in the same dir, so we can preserve relative symlinks.
newFile.CreateSymbolicLinkTo(symlinkInfo.ContentsPath);
}
else
{
var fullPath = UnixPath.Combine(UnixPath.GetDirectoryName(source), symlinkPath);
newFile.CreateSymbolicLinkTo(fullPath);
}
}
else
{
base.CopyFileInternal(source, destination, overwrite);
}
}
protected override void MoveFileInternal(string source, string destination)
{
var sourceInfo = UnixFileSystemInfo.GetFileSystemEntry(source);
if (sourceInfo.IsSymbolicLink)
{
var isSameDir = UnixPath.GetDirectoryName(source) == UnixPath.GetDirectoryName(destination);
var symlinkInfo = (UnixSymbolicLinkInfo)sourceInfo;
var symlinkPath = symlinkInfo.ContentsPath;
var newFile = new UnixSymbolicLinkInfo(destination);
if (isSameDir)
{
// We're in the same dir, so we can preserve relative symlinks.
newFile.CreateSymbolicLinkTo(symlinkInfo.ContentsPath);
}
else
{
var fullPath = UnixPath.Combine(UnixPath.GetDirectoryName(source), symlinkPath);
newFile.CreateSymbolicLinkTo(fullPath);
}
try
{
// Finally remove the original symlink.
symlinkInfo.Delete();
}
catch
{
// Removing symlink failed, so rollback the new link and throw.
newFile.Delete();
throw;
}
}
else
{
base.MoveFileInternal(source, destination);
}
}
public override bool TryCreateHardLink(string source, string destination)
{
try
{
UnixFileSystemInfo.GetFileSystemEntry(source).CreateLink(destination);
var fileInfo = UnixFileSystemInfo.GetFileSystemEntry(source);
if (fileInfo.IsSymbolicLink) return false;
fileInfo.CreateLink(destination);
return true;
}
catch (Exception ex)