Exemple #1
0
        protected void IgnoreOnMonoVersions(params string[] version_strings)
        {
            if (!PlatformInfo.IsMono)
            {
                return;
            }

            var current  = PlatformInfo.GetVersion();
            var versions = version_strings.Select(x => new Version(x)).ToList();

            if (versions.Any(x => x.Major == current.Major && x.Minor == current.Minor))
            {
                throw new IgnoreException($"Ignored on mono {PlatformInfo.GetVersion()}");
            }
        }
        public void SetUp()
        {
            if (PlatformInfo.IsMono && PlatformInfo.GetVersion() < new Version(5, 8))
            {
                Assert.Inconclusive("Not supported on Mono < 5.8");
            }

            Mocker.GetMock <IDiskProvider>()
            .Setup(v => v.FileExists(It.IsAny <string>()))
            .Returns <string>(s => File.Exists(s));

            Mocker.GetMock <IDiskProvider>()
            .Setup(v => v.DeleteFile(It.IsAny <string>()))
            .Callback <string>(s => File.Delete(s));

            Mocker.SetConstant <IPlatformInfo>(Mocker.Resolve <PlatformInfo>());
        }
Exemple #3
0
        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 if ((PlatformInfo.Platform == PlatformType.Mono && PlatformInfo.GetVersion() >= new Version(6, 0)) ||
                     PlatformInfo.Platform == PlatformType.NetCore)
            {
                TransferFilePatched(source, destination, false, true);
            }
            else
            {
                base.MoveFileInternal(source, destination);
            }
        }
Exemple #4
0
        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 if (((PlatformInfo.Platform == PlatformType.Mono && PlatformInfo.GetVersion() >= new Version(6, 0)) ||
                      PlatformInfo.Platform == PlatformType.NetCore) &&
                     (!FileExists(destination) || overwrite))
            {
                TransferFilePatched(source, destination, overwrite, false);
            }
            else
            {
                base.CopyFileInternal(source, destination, overwrite);
            }
        }
Exemple #5
0
        private void TransferFilePatched(string source, string destination, bool overwrite, bool move)
        {
            // Mono 6.x throws errors if permissions or timestamps cannot be set
            // - In 6.0 it'll leave a full length file
            // - In 6.6 it'll leave a zero length file
            // Catch the exception and attempt to handle these edgecases

            // Mono 6.x till 6.10 doesn't properly try use rename first.
            if (move && PlatformInfo.GetVersion() < new Version(6, 10))
            {
                if (Syscall.lstat(source, out var sourcestat) == 0 &&
                    Syscall.lstat(destination, out var deststat) != 0 &&
                    Syscall.rename(source, destination) == 0)
                {
                    _logger.Trace("Moved '{0}' -> '{1}' using Syscall.rename", source, destination);
                    return;
                }
            }

            try
            {
                if (move)
                {
                    base.MoveFileInternal(source, destination);
                }
                else
                {
                    base.CopyFileInternal(source, destination, overwrite);
                }
            }
            catch (UnauthorizedAccessException)
            {
                var srcInfo = new FileInfo(source);
                var dstInfo = new FileInfo(destination);
                var exists  = dstInfo.Exists && srcInfo.Exists;

                if (exists && dstInfo.Length == 0 && srcInfo.Length != 0)
                {
                    // mono >=6.6 bug: zero length file since chmod happens at the start
                    _logger.Debug("Mono failed to {2} file likely due to known mono bug, attempting to {2} directly. '{0}' -> '{1}'", source, destination, move ? "move" : "copy");

                    try
                    {
                        _logger.Trace("Copying content from {0} to {1} ({2} bytes)", source, destination, srcInfo.Length);
                        using (var srcStream = new FileStream(source, FileMode.Open, FileAccess.Read))
                            using (var dstStream = new FileStream(destination, FileMode.Create, FileAccess.Write))
                            {
                                srcStream.CopyTo(dstStream);
                            }
                    }
                    catch
                    {
                        // If it fails again then bail
                        throw;
                    }
                }
                else if (exists && dstInfo.Length == srcInfo.Length)
                {
                    // mono 6.0, 6.4 bug: full length file since utime and chmod happens at the end
                    _logger.Debug("Mono failed to {2} file likely due to known mono bug, attempting to {2} directly. '{0}' -> '{1}'", source, destination, move ? "move" : "copy");

                    // Check at least part of the file since UnauthorizedAccess can happen due to legitimate reasons too
                    var checkLength = (int)Math.Min(64 * 1024, dstInfo.Length);
                    if (checkLength > 0)
                    {
                        var srcData = new byte[checkLength];
                        var dstData = new byte[checkLength];

                        _logger.Trace("Check last {0} bytes from {1}", checkLength, destination);

                        using (var srcStream = new FileStream(source, FileMode.Open, FileAccess.Read))
                            using (var dstStream = new FileStream(destination, FileMode.Open, FileAccess.Read))
                            {
                                srcStream.Position = srcInfo.Length - checkLength;
                                dstStream.Position = dstInfo.Length - checkLength;

                                srcStream.Read(srcData, 0, checkLength);
                                dstStream.Read(dstData, 0, checkLength);
                            }

                        for (var i = 0; i < checkLength; i++)
                        {
                            if (srcData[i] != dstData[i])
                            {
                                // Files aren't the same, the UnauthorizedAccess was unrelated
                                _logger.Trace("Copy was incomplete, rethrowing original error");
                                throw;
                            }
                        }

                        _logger.Trace("Copy was complete, finishing {0} operation", move ? "move" : "copy");
                    }
                }
                else
                {
                    // Unrecognized situation, the UnauthorizedAccess was unrelated
                    throw;
                }

                if (exists)
                {
                    try
                    {
                        dstInfo.LastWriteTimeUtc = srcInfo.LastWriteTimeUtc;
                    }
                    catch
                    {
                        _logger.Debug("Unable to change last modified date for {0}, skipping.", destination);
                    }

                    if (move)
                    {
                        _logger.Trace("Removing source file {0}", source);
                        File.Delete(source);
                    }
                }
            }
        }