You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Lidarr/src/NzbDrone.Mono/Disk/RefLinkCreator.cs

76 lines
2.6 KiB

using System;
using Mono.Unix;
using Mono.Unix.Native;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Mono.Interop;
namespace NzbDrone.Mono.Disk
{
public interface IRefLinkCreator
{
bool TryCreateRefLink(string srcPath, string linkPath);
}
public class RefLinkCreator : IRefLinkCreator
{
private readonly Logger _logger;
private readonly bool _supported;
public RefLinkCreator(Logger logger)
{
_logger = logger;
// Only support x86_64 because we know the FICLONE value is valid for it
_supported = OsInfo.IsLinux && (Syscall.uname(out var results) == 0 && results.machine == "x86_64");
}
public bool TryCreateRefLink(string srcPath, string linkPath)
{
if (!_supported)
{
return false;
}
try
{
using (var srcHandle = NativeMethods.open(srcPath, OpenFlags.O_RDONLY))
{
if (srcHandle.IsInvalid)
{
_logger.Trace("Failed to create reflink at '{0}' to '{1}': Couldn't open source file", linkPath, srcPath);
return false;
}
using (var linkHandle = NativeMethods.open(linkPath, OpenFlags.O_WRONLY | OpenFlags.O_CREAT | OpenFlags.O_TRUNC))
{
if (linkHandle.IsInvalid)
{
_logger.Trace("Failed to create reflink at '{0}' to '{1}': Couldn't create new link file", linkPath, srcPath);
return false;
}
if (NativeMethods.clone_file(linkHandle, srcHandle) == -1)
{
var error = new UnixIOException();
linkHandle.Dispose();
Syscall.unlink(linkPath);
_logger.Trace("Failed to create reflink at '{0}' to '{1}': {2}", linkPath, srcPath, error.Message);
return false;
}
_logger.Trace("Created reflink at '{0}' to '{1}'", linkPath, srcPath);
return true;
}
}
}
catch (Exception ex)
{
Syscall.unlink(linkPath);
_logger.Trace(ex, "Failed to create reflink at '{0}' to '{1}'", linkPath, srcPath);
return false;
}
}
}
}