Fixed: Mono internals does not properly copy/move symlinks, but instead copies the contents.
This commit is contained in:
parent
747f3e171c
commit
459d6ea906
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -96,11 +96,88 @@ 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)
|
||||
|
|
Loading…
Reference in New Issue