Example #1
0
        private MetadataFile ProcessEpisodeMetadata(IMetadata consumer, Series series, EpisodeFile episodeFile, List <MetadataFile> existingMetadataFiles)
        {
            var episodeMetadata = consumer.EpisodeMetadata(series, episodeFile);

            if (episodeMetadata == null)
            {
                return(null);
            }

            var fullPath = Path.Combine(series.Path, episodeMetadata.RelativePath);

            var existingMetadata = existingMetadataFiles.SingleOrDefault(c => c.Type == MetadataType.EpisodeMetadata &&
                                                                         c.EpisodeFileId == episodeFile.Id);

            if (existingMetadata != null)
            {
                var existingFullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
                if (!fullPath.PathEquals(existingFullPath))
                {
                    _diskProvider.MoveFile(existingFullPath, fullPath);
                    existingMetadata.RelativePath = episodeMetadata.RelativePath;
                }
            }

            var hash = episodeMetadata.Contents.SHA256Hash();

            var metadata = existingMetadata ??
                           new MetadataFile
            {
                SeriesId      = series.Id,
                EpisodeFileId = episodeFile.Id,
                Consumer      = consumer.GetType().Name,
                Type          = MetadataType.EpisodeMetadata,
                RelativePath  = episodeMetadata.RelativePath
            };

            if (hash == metadata.Hash)
            {
                return(null);
            }

            _logger.Debug("Writing Episode Metadata to: {0}", fullPath);
            SaveMetadataFile(fullPath, episodeMetadata.Contents);

            metadata.Hash = hash;

            return(metadata);
        }
Example #2
0
        public void RenameOtherExtraFile(Movie movie, string path)
        {
            if (!_diskProvider.FileExists(path))
            {
                return;
            }

            var relativePath = movie.Path.GetRelativePath(path);

            var otherExtraFile = _otherExtraFileService.FindByPath(relativePath);

            if (otherExtraFile != null)
            {
                var newPath = path + "-orig";

                // Recycle an existing -orig file.
                RemoveOtherExtraFile(movie, newPath);

                // Rename the file to .*-orig
                _diskProvider.MoveFile(path, newPath);
                otherExtraFile.RelativePath = relativePath + "-orig";
                otherExtraFile.Extension   += "-orig";
                _otherExtraFileService.Upsert(otherExtraFile);
            }
        }
Example #3
0
        protected TExtraFile MoveFile(Artist artist, TrackFile trackFile, TExtraFile extraFile, string fileNameSuffix = null)
        {
            var newFolder       = Path.GetDirectoryName(trackFile.Path);
            var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(trackFile.Path));

            if (fileNameSuffix.IsNotNullOrWhiteSpace())
            {
                filenameBuilder.Append(fileNameSuffix);
            }

            filenameBuilder.Append(extraFile.Extension);

            var existingFileName = Path.Combine(artist.Path, extraFile.RelativePath);
            var newFileName      = Path.Combine(newFolder, filenameBuilder.ToString());

            if (newFileName.PathNotEquals(existingFileName))
            {
                try
                {
                    _diskProvider.MoveFile(existingFileName, newFileName);
                    extraFile.RelativePath = artist.Path.GetRelativePath(newFileName);

                    return(extraFile);
                }
                catch (Exception ex)
                {
                    _logger.Warn(ex, "Unable to move file after rename: {0}", existingFileName);
                }
            }

            return(null);
        }
Example #4
0
        private void MoveFile(EpisodeFile episodeFile, string destinationFilename)
        {
            if (!_diskProvider.FileExists(episodeFile.Path))
            {
                throw new FileNotFoundException("Episode file path does not exist", episodeFile.Path);
            }

            if (episodeFile.Path.PathEquals(destinationFilename))
            {
                throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path);
            }

            _diskProvider.CreateFolder(new FileInfo(destinationFilename).DirectoryName);

            _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename);
            _diskProvider.MoveFile(episodeFile.Path, destinationFilename);

            //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important.
            try
            {
                _diskProvider.InheritFolderPermissions(destinationFilename);
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.Debug("Unable to apply folder permissions to: ", destinationFilename);
                _logger.TraceException(ex.Message, ex);
            }
        }
Example #5
0
        public void Restore()
        {
            var dbRestorePath = _appFolderInfo.GetDatabaseRestore();

            if (!_diskProvider.FileExists(dbRestorePath))
            {
                return;
            }

            try
            {
                Logger.Info("Restoring Database");

                var dbPath = _appFolderInfo.GetDatabase();

                _diskProvider.DeleteFile(dbPath + "-shm");
                _diskProvider.DeleteFile(dbPath + "-wal");
                _diskProvider.DeleteFile(dbPath + "-journal");
                _diskProvider.DeleteFile(dbPath);

                _diskProvider.MoveFile(dbRestorePath, dbPath);
            }
            catch (Exception e)
            {
                Logger.Error(e, "Failed to restore database");
                throw;
            }
        }
Example #6
0
        public void DeleteFile(string path)
        {
            logger.Debug("Attempting to send '{0}' to recycling bin", path);
            var recyclingBin = _configService.RecycleBin;

            if (String.IsNullOrWhiteSpace(recyclingBin))
            {
                logger.Info("Recycling Bin has not been configured, deleting permanently.");

                if (!OsInfo.IsMono)
                {
                    logger.Debug(_diskProvider.GetFileAttributes(path));
                }

                _diskProvider.DeleteFile(path);
                logger.Debug("File has been permanently deleted: {0}", path);
            }

            else
            {
                var destination = Path.Combine(recyclingBin, new FileInfo(path).Name);

                logger.Debug("Moving '{0}' to '{1}'", path, destination);
                _diskProvider.MoveFile(path, destination);
                _diskProvider.FileSetLastWriteTimeUtc(destination, DateTime.UtcNow);
                logger.Debug("File has been moved to the recycling bin: {0}", destination);
            }
        }
Example #7
0
        private void MigrateAppDataFolder()
        {
            try
            {
                var oldDbFile = Path.Combine(_appFolderInfo.AppDataFolder, "nzbdrone.db");

                if (_startupContext.Args.ContainsKey(StartupContext.APPDATA))
                {
                    if (_diskProvider.FileExists(_appFolderInfo.GetDatabase()))
                    {
                        return;
                    }

                    if (!_diskProvider.FileExists(oldDbFile))
                    {
                        return;
                    }

                    _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase());
                    CleanupSqLiteRollbackFiles();
                    RemovePidFile();
                }

                // Exit if a prowlarr.db already exists
                if (_diskProvider.FileExists(_appFolderInfo.GetDatabase()))
                {
                    return;
                }

                // Rename the DB file
                if (_diskProvider.FileExists(oldDbFile))
                {
                    _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase());
                }

                // Remove SQLite rollback files
                CleanupSqLiteRollbackFiles();

                // Remove Old PID file
                RemovePidFile();
            }
            catch (Exception ex)
            {
                _logger.Debug(ex, ex.Message);
                throw new ProwlarrStartupException("Unable to migrate DB from nzbdrone.db to {0}. Migrate manually", _appFolderInfo.GetDatabase());
            }
        }
Example #8
0
        public void Restore(string backupFileName)
        {
            if (backupFileName.EndsWith(".zip"))
            {
                var restoredFile  = false;
                var temporaryPath = Path.Combine(_appFolderInfo.TempFolder, "radarr_backup_restore");

                _archiveService.Extract(backupFileName, temporaryPath);

                foreach (var file in _diskProvider.GetFiles(temporaryPath, SearchOption.TopDirectoryOnly))
                {
                    var fileName = Path.GetFileName(file);

                    if (fileName.Equals("Config.xml", StringComparison.InvariantCultureIgnoreCase))
                    {
                        _diskProvider.MoveFile(file, _appFolderInfo.GetConfigPath(), true);
                        restoredFile = true;
                    }

                    if (fileName.Equals("nzbdrone.db", StringComparison.InvariantCultureIgnoreCase))
                    {
                        _diskProvider.MoveFile(file, _appFolderInfo.GetDatabaseRestore(), true);
                        restoredFile = true;
                    }

                    if (fileName.Equals("radarr.db", StringComparison.InvariantCultureIgnoreCase))
                    {
                        _diskProvider.MoveFile(file, _appFolderInfo.GetDatabaseRestore(), true);
                        restoredFile = true;
                    }
                }

                if (!restoredFile)
                {
                    throw new RestoreBackupFailedException(HttpStatusCode.NotFound, "Unable to restore database file from backup");
                }

                _diskProvider.DeleteFolder(temporaryPath, true);

                return;
            }

            _diskProvider.MoveFile(backupFileName, _appFolderInfo.GetDatabaseRestore(), true);
        }
Example #9
0
        public override void AfterRename(Series series, List <MetadataFile> existingMetadataFiles, List <EpisodeFile> episodeFiles)
        {
            var episodeFilesMetadata = existingMetadataFiles.Where(c => c.EpisodeFileId > 0).ToList();
            var updatedMetadataFiles = new List <MetadataFile>();

            foreach (var episodeFile in episodeFiles)
            {
                var metadataFiles = episodeFilesMetadata.Where(m => m.EpisodeFileId == episodeFile.Id).ToList();

                foreach (var metadataFile in metadataFiles)
                {
                    string newFilename;

                    if (metadataFile.Type == MetadataType.EpisodeImage)
                    {
                        newFilename = GetEpisodeImageFilename(episodeFile.Path);
                    }

                    else if (metadataFile.Type == MetadataType.EpisodeMetadata)
                    {
                        newFilename = GetEpisodeNfoFilename(episodeFile.Path);
                    }

                    else
                    {
                        _logger.Debug("Unknown episode file metadata: {0}", metadataFile.RelativePath);
                        continue;
                    }

                    var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);

                    if (!newFilename.PathEquals(existingFilename))
                    {
                        _diskProvider.MoveFile(existingFilename, newFilename);
                        metadataFile.RelativePath = DiskProviderBase.GetRelativePath(series.Path, newFilename);

                        updatedMetadataFiles.Add(metadataFile);
                    }
                }
            }

            _eventAggregator.PublishEvent(new MetadataFilesUpdated(updatedMetadataFiles));
        }
Example #10
0
        public override IEnumerable <ExtraFile> MoveFilesAfterRename(Series series, List <EpisodeFile> episodeFiles)
        {
            // TODO: Remove
            // We don't want to move files after rename yet.

            return(Enumerable.Empty <ExtraFile>());

            var subtitleFiles = _subtitleFileService.GetFilesBySeries(series.Id);

            var movedFiles = new List <SubtitleFile>();

            foreach (var episodeFile in episodeFiles)
            {
                var groupedExtraFilesForEpisodeFile = subtitleFiles.Where(m => m.EpisodeFileId == episodeFile.Id)
                                                      .GroupBy(s => s.Language + s.Extension).ToList();

                foreach (var group in groupedExtraFilesForEpisodeFile)
                {
                    var groupCount = group.Count();
                    var copy       = 1;

                    if (groupCount > 1)
                    {
                        _logger.Warn("Multiple subtitle files found with the same language and extension for {0}", Path.Combine(series.Path, episodeFile.RelativePath));
                    }

                    foreach (var extraFile in group)
                    {
                        var existingFileName = Path.Combine(series.Path, extraFile.RelativePath);
                        var extension        = GetExtension(extraFile, existingFileName, copy, groupCount > 1);
                        var newFileName      = Path.ChangeExtension(Path.Combine(series.Path, episodeFile.RelativePath), extension);

                        if (newFileName.PathNotEquals(existingFileName))
                        {
                            try
                            {
                                _diskProvider.MoveFile(existingFileName, newFileName);
                                extraFile.RelativePath = series.Path.GetRelativePath(newFileName);
                                movedFiles.Add(extraFile);
                            }
                            catch (Exception ex)
                            {
                                _logger.Warn(ex, "Unable to move subtitle file: {0}", existingFileName);
                            }
                        }

                        copy++;
                    }
                }
            }

            _subtitleFileService.Upsert(movedFiles);

            return(movedFiles);
        }
Example #11
0
        public void DeleteFile(string path)
        {
            logger.Debug("Attempting to send '{0}' to recycling bin", path);
            var recyclingBin = _configService.RecycleBin;

            if (String.IsNullOrWhiteSpace(recyclingBin))
            {
                logger.Info("Recycling Bin has not been configured, deleting permanently.");

                if (OsInfo.IsWindows)
                {
                    logger.Debug(_diskProvider.GetFileAttributes(path));
                }

                _diskProvider.DeleteFile(path);
                logger.Debug("File has been permanently deleted: {0}", path);
            }

            else
            {
                var fileInfo    = new FileInfo(path);
                var destination = Path.Combine(recyclingBin, fileInfo.Name);

                var index = 1;
                while (_diskProvider.FileExists(destination))
                {
                    index++;
                    if (fileInfo.Extension.IsNullOrWhiteSpace())
                    {
                        destination = Path.Combine(recyclingBin, fileInfo.Name + "_" + index);
                    }
                    else
                    {
                        destination = Path.Combine(recyclingBin, Path.GetFileNameWithoutExtension(fileInfo.Name) + "_" + index + fileInfo.Extension);
                    }
                }

                logger.Debug("Moving '{0}' to '{1}'", path, destination);
                _diskProvider.MoveFile(path, destination, true);

                //TODO: Better fix than this for non-Windows?
                if (OsInfo.IsWindows)
                {
                    _diskProvider.FileSetLastWriteTimeUtc(destination, DateTime.UtcNow);
                }

                logger.Debug("File has been moved to the recycling bin: {0}", destination);
            }
        }
Example #12
0
        public override List <MetadataFile> AfterRename(Series series, List <MetadataFile> existingMetadataFiles, List <EpisodeFile> episodeFiles)
        {
            var episodeFilesMetadata = existingMetadataFiles.Where(c => c.EpisodeFileId > 0).ToList();
            var updatedMetadataFiles = new List <MetadataFile>();

            foreach (var episodeFile in episodeFiles)
            {
                var metadataFiles = episodeFilesMetadata.Where(m => m.EpisodeFileId == episodeFile.Id).ToList();

                foreach (var metadataFile in metadataFiles)
                {
                    string newFilename;

                    if (metadataFile.Type == MetadataType.EpisodeImage)
                    {
                        newFilename = GetEpisodeImageFilename(episodeFile.RelativePath);
                    }

                    else if (metadataFile.Type == MetadataType.EpisodeMetadata)
                    {
                        newFilename = GetEpisodeMetadataFilename(episodeFile.RelativePath);
                    }

                    else
                    {
                        _logger.Trace("Unknown episode file metadata: {0}", metadataFile.RelativePath);
                        continue;
                    }

                    var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);
                    newFilename = Path.Combine(series.Path, newFilename);

                    if (!newFilename.PathEquals(existingFilename))
                    {
                        _diskProvider.MoveFile(existingFilename, newFilename);
                        metadataFile.RelativePath = series.Path.GetRelativePath(newFilename);

                        updatedMetadataFiles.Add(metadataFile);
                    }
                }
            }

            return(updatedMetadataFiles);
        }
Example #13
0
        public override IEnumerable <ExtraFile> MoveFilesAfterRename(Movie movie, List <MovieFile> movieFiles)
        {
            var movieRelativePaths = string.Join(", ", movieFiles.Select(movieFile => Path.Combine(movie.Path, movieFile.RelativePath)));

            _logger.Debug("Move Movie Files after Movie Rename for: {0}", movieRelativePaths);

            var metadataFiles = _metadataFileService.GetFilesByMovie(movie.Id);
            var movedFiles    = new List <MetadataFile>();

            // TODO: Move EpisodeImage and EpisodeMetadata metadata files, instead of relying on consumers to do it
            // (Xbmc's EpisodeImage is more than just the extension)
            foreach (var consumer in _metadataFactory.GetAvailableProviders())
            {
                foreach (var movieFile in movieFiles)
                {
                    var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles).Where(m => m.MovieFileId == movieFile.Id).ToList();

                    foreach (var metadataFile in metadataFilesForConsumer)
                    {
                        var newFileName      = consumer.GetFilenameAfterMove(movie, movieFile, metadataFile);
                        var existingFileName = Path.Combine(movie.Path, metadataFile.RelativePath);

                        if (newFileName.PathNotEquals(existingFileName))
                        {
                            try
                            {
                                _diskProvider.MoveFile(existingFileName, newFileName);
                                metadataFile.RelativePath = movie.Path.GetRelativePath(newFileName);
                                movedFiles.Add(metadataFile);
                            }
                            catch (Exception ex)
                            {
                                _logger.Warn(ex, "Unable to move metadata file after rename: {0}", existingFileName);
                            }
                        }
                    }
                }
            }

            _metadataFileService.Upsert(movedFiles);

            return(movedFiles);
        }
Example #14
0
        public override IEnumerable<ExtraFile> MoveFilesAfterRename(Series series, List<EpisodeFile> episodeFiles)
        {
            // TODO: Remove
            // We don't want to move files after rename yet.

            return Enumerable.Empty<ExtraFile>();

            var extraFiles = _otherExtraFileService.GetFilesBySeries(series.Id);
            var movedFiles = new List<OtherExtraFile>();

            foreach (var episodeFile in episodeFiles)
            {
                var extraFilesForEpisodeFile = extraFiles.Where(m => m.EpisodeFileId == episodeFile.Id).ToList();

                foreach (var extraFile in extraFilesForEpisodeFile)
                {
                    var existingFileName = Path.Combine(series.Path, extraFile.RelativePath);
                    var extension = Path.GetExtension(existingFileName).TrimStart('.');
                    var newFileName = Path.ChangeExtension(Path.Combine(series.Path, episodeFile.RelativePath), extension);

                    if (newFileName.PathNotEquals(existingFileName))
                    {
                        try
                        {
                            _diskProvider.MoveFile(existingFileName, newFileName);
                            extraFile.RelativePath = series.Path.GetRelativePath(newFileName);
                            movedFiles.Add(extraFile);
                        }
                        catch (Exception ex)
                        {
                            _logger.Warn(ex, "Unable to move extra file: {0}", existingFileName);
                        }
                    }
                }
            }

            _otherExtraFileService.Upsert(movedFiles);

            return movedFiles;
        }
Example #15
0
        public TransferMode TransferFile(string sourcePath, string targetPath, TransferMode mode, bool overwrite, DiskTransferVerificationMode verificationMode)
        {
            Ensure.That(sourcePath, () => sourcePath).IsValidPath();
            Ensure.That(targetPath, () => targetPath).IsValidPath();

            _logger.Debug("{0} [{1}] > [{2}]", mode, sourcePath, targetPath);

            var originalSize = _diskProvider.GetFileSize(sourcePath);

            if (sourcePath == targetPath)
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
            }

            if (sourcePath.PathEquals(targetPath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (mode.HasFlag(TransferMode.HardLink) || mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    var tempPath = sourcePath + ".backup~";

                    _diskProvider.MoveFile(sourcePath, tempPath, true);
                    try
                    {
                        ClearTargetPath(targetPath, overwrite);

                        _diskProvider.MoveFile(tempPath, targetPath);

                        return(TransferMode.Move);
                    }
                    catch
                    {
                        RollbackMove(sourcePath, tempPath);
                        throw;
                    }
                }

                return(TransferMode.None);
            }

            if (sourcePath.GetParentPath() == targetPath.GetParentPath())
            {
                if (mode.HasFlag(TransferMode.Move))
                {
                    TryMoveFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Move);
                }
            }

            if (sourcePath.IsParentPath(targetPath))
            {
                throw new IOException(string.Format("Destination cannot be a child of the source [{0}] => [{1}]", sourcePath, targetPath));
            }

            ClearTargetPath(targetPath, overwrite);

            if (mode.HasFlag(TransferMode.HardLink))
            {
                var createdHardlink = _diskProvider.TryCreateHardLink(sourcePath, targetPath);
                if (createdHardlink)
                {
                    return(TransferMode.HardLink);
                }
                if (!mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException("Hardlinking from '" + sourcePath + "' to '" + targetPath + "' failed.");
                }
            }

            // We force a transactional transfer if the transfer occurs between mounts and one of the mounts is cifs, it would be a copy anyway.
            if (verificationMode == DiskTransferVerificationMode.TryTransactional && OsInfo.IsNotWindows)
            {
                var sourceMount = _diskProvider.GetMount(sourcePath);
                var targetMount = _diskProvider.GetMount(targetPath);

                if (sourceMount != null && targetMount != null && sourceMount.RootDirectory != targetMount.RootDirectory &&
                    (sourceMount.DriveFormat == "cifs" || targetMount.DriveFormat == "cifs"))
                {
                    verificationMode = DiskTransferVerificationMode.Transactional;
                }
            }

            if (mode.HasFlag(TransferMode.Copy))
            {
                if (verificationMode == DiskTransferVerificationMode.Transactional || verificationMode == DiskTransferVerificationMode.TryTransactional)
                {
                    if (TryCopyFileTransactional(sourcePath, targetPath, originalSize))
                    {
                        return(TransferMode.Copy);
                    }

                    throw new IOException(string.Format("Failed to completely transfer [{0}] to [{1}], aborting.", sourcePath, targetPath));
                }
                else if (verificationMode == DiskTransferVerificationMode.VerifyOnly)
                {
                    TryCopyFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Copy);
                }
                else
                {
                    _diskProvider.CopyFile(sourcePath, targetPath);
                    return(TransferMode.Copy);
                }
            }

            if (mode.HasFlag(TransferMode.Move))
            {
                if (verificationMode == DiskTransferVerificationMode.Transactional || verificationMode == DiskTransferVerificationMode.TryTransactional)
                {
                    if (TryMoveFileTransactional(sourcePath, targetPath, originalSize, verificationMode))
                    {
                        return(TransferMode.Move);
                    }

                    throw new IOException(string.Format("Failed to completely transfer [{0}] to [{1}], aborting.", sourcePath, targetPath));
                }
                else if (verificationMode == DiskTransferVerificationMode.VerifyOnly)
                {
                    TryMoveFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Move);
                }
                else
                {
                    _diskProvider.MoveFile(sourcePath, targetPath);
                    return(TransferMode.Move);
                }
            }

            return(TransferMode.None);
        }
        public TransferMode TransferFile(string sourcePath, string targetPath, TransferMode mode, bool overwrite = false)
        {
            Ensure.That(sourcePath, () => sourcePath).IsValidPath();
            Ensure.That(targetPath, () => targetPath).IsValidPath();

            _logger.Debug("{0} [{1}] > [{2}]", mode, sourcePath, targetPath);

            var originalSize = _diskProvider.GetFileSize(sourcePath);

            if (sourcePath == targetPath)
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
            }

            if (sourcePath.PathEquals(targetPath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (mode.HasFlag(TransferMode.HardLink) || mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    var tempPath = sourcePath + ".backup~";

                    _diskProvider.MoveFile(sourcePath, tempPath, true);
                    try
                    {
                        ClearTargetPath(sourcePath, targetPath, overwrite);

                        _diskProvider.MoveFile(tempPath, targetPath);

                        return(TransferMode.Move);
                    }
                    catch
                    {
                        RollbackMove(sourcePath, tempPath);
                        throw;
                    }
                }

                return(TransferMode.None);
            }

            if (sourcePath.GetParentPath() == targetPath.GetParentPath())
            {
                if (mode.HasFlag(TransferMode.Move))
                {
                    TryMoveFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Move);
                }
            }

            if (sourcePath.IsParentPath(targetPath))
            {
                throw new IOException(string.Format("Destination cannot be a child of the source [{0}] => [{1}]", sourcePath, targetPath));
            }

            ClearTargetPath(sourcePath, targetPath, overwrite);

            if (mode.HasFlag(TransferMode.HardLink))
            {
                var createdHardlink = _diskProvider.TryCreateHardLink(sourcePath, targetPath);
                if (createdHardlink)
                {
                    return(TransferMode.HardLink);
                }

                if (!mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException("Hardlinking from '" + sourcePath + "' to '" + targetPath + "' failed.");
                }
            }

            // Adjust the transfer mode depending on the filesystems
            var sourceMount = _diskProvider.GetMount(sourcePath);
            var targetMount = _diskProvider.GetMount(targetPath);

            var isSameMount = sourceMount != null && targetMount != null && sourceMount.RootDirectory == targetMount.RootDirectory;

            var sourceDriveFormat = sourceMount?.DriveFormat ?? string.Empty;
            var targetDriveFormat = targetMount?.DriveFormat ?? string.Empty;

            var isCifs  = targetDriveFormat == "cifs";
            var isBtrfs = sourceDriveFormat == "btrfs" && targetDriveFormat == "btrfs";

            if (mode.HasFlag(TransferMode.Copy))
            {
                if (isBtrfs)
                {
                    if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
                    {
                        return(TransferMode.Copy);
                    }
                }

                TryCopyFileVerified(sourcePath, targetPath, originalSize);
                return(TransferMode.Copy);
            }

            if (mode.HasFlag(TransferMode.Move))
            {
                if (isBtrfs)
                {
                    if (isSameMount && _diskProvider.TryRenameFile(sourcePath, targetPath))
                    {
                        _logger.Trace("Renamed [{0}] to [{1}].", sourcePath, targetPath);
                        return(TransferMode.Move);
                    }

                    if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
                    {
                        _logger.Trace("Reflink successful, deleting source [{0}].", sourcePath);
                        _diskProvider.DeleteFile(sourcePath);
                        return(TransferMode.Move);
                    }
                }

                if (isCifs && !isSameMount)
                {
                    _logger.Trace("On cifs mount. Starting verified copy [{0}] to [{1}].", sourcePath, targetPath);
                    TryCopyFileVerified(sourcePath, targetPath, originalSize);
                    _logger.Trace("Copy successful, deleting source [{0}].", sourcePath);
                    _diskProvider.DeleteFile(sourcePath);
                    return(TransferMode.Move);
                }

                TryMoveFileVerified(sourcePath, targetPath, originalSize);
                return(TransferMode.Move);
            }

            return(TransferMode.None);
        }
Example #17
0
        public override IEnumerable <ExtraFile> MoveFilesAfterRename(Author author, List <BookFile> bookFiles)
        {
            var metadataFiles          = _metadataFileService.GetFilesByAuthor(author.Id);
            var movedFiles             = new List <MetadataFile>();
            var distinctTrackFilePaths = bookFiles.DistinctBy(s => Path.GetDirectoryName(s.Path)).ToList();

            // TODO: Move EpisodeImage and EpisodeMetadata metadata files, instead of relying on consumers to do it
            // (Xbmc's EpisodeImage is more than just the extension)
            foreach (var consumer in _metadataFactory.GetAvailableProviders())
            {
                foreach (var filePath in distinctTrackFilePaths)
                {
                    var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles)
                                                   .Where(m => m.BookId == filePath.EditionId)
                                                   .Where(m => m.Type == MetadataType.BookImage || m.Type == MetadataType.BookMetadata)
                                                   .ToList();

                    foreach (var metadataFile in metadataFilesForConsumer)
                    {
                        var newFileName      = consumer.GetFilenameAfterMove(author, Path.GetDirectoryName(filePath.Path), metadataFile);
                        var existingFileName = Path.Combine(author.Path, metadataFile.RelativePath);

                        if (newFileName.PathNotEquals(existingFileName))
                        {
                            try
                            {
                                _diskProvider.MoveFile(existingFileName, newFileName);
                                metadataFile.RelativePath = author.Path.GetRelativePath(newFileName);
                                movedFiles.Add(metadataFile);
                            }
                            catch (Exception ex)
                            {
                                _logger.Warn(ex, "Unable to move metadata file after rename: {0}", existingFileName);
                            }
                        }
                    }
                }

                foreach (var bookFile in bookFiles)
                {
                    var metadataFilesForConsumer = GetMetadataFilesForConsumer(consumer, metadataFiles).Where(m => m.BookFileId == bookFile.Id).ToList();

                    foreach (var metadataFile in metadataFilesForConsumer)
                    {
                        var newFileName      = consumer.GetFilenameAfterMove(author, bookFile, metadataFile);
                        var existingFileName = Path.Combine(author.Path, metadataFile.RelativePath);

                        if (newFileName.PathNotEquals(existingFileName))
                        {
                            try
                            {
                                _diskProvider.MoveFile(existingFileName, newFileName);
                                metadataFile.RelativePath = author.Path.GetRelativePath(newFileName);
                                movedFiles.Add(metadataFile);
                            }
                            catch (Exception ex)
                            {
                                _logger.Warn(ex, "Unable to move metadata file after rename: {0}", existingFileName);
                            }
                        }
                    }
                }
            }

            _metadataFileService.Upsert(movedFiles);

            return(movedFiles);
        }
Example #18
0
        public TransferMode TransferFile(string sourcePath, string targetPath, TransferMode mode, bool overwrite = false, bool verified = true)
        {
            Ensure.That(sourcePath, () => sourcePath).IsValidPath();
            Ensure.That(targetPath, () => targetPath).IsValidPath();

            if (VerificationMode != DiskTransferVerificationMode.Transactional)
            {
                verified = false;
            }

            _logger.Debug("{0} [{1}] > [{2}]", mode, sourcePath, targetPath);

            if (sourcePath == targetPath)
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
            }

            if (sourcePath.PathEquals(targetPath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (mode.HasFlag(TransferMode.HardLink) || mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    var tempPath = sourcePath + ".backup~";

                    _diskProvider.MoveFile(sourcePath, tempPath, true);
                    try
                    {
                        ClearTargetPath(targetPath, overwrite);

                        _diskProvider.MoveFile(tempPath, targetPath);

                        return(TransferMode.Move);
                    }
                    catch
                    {
                        RollbackMove(sourcePath, tempPath);
                        throw;
                    }
                }

                return(TransferMode.None);
            }

            if (sourcePath.IsParentPath(targetPath))
            {
                throw new IOException(string.Format("Destination cannot be a child of the source [{0}] => [{1}]", sourcePath, targetPath));
            }

            ClearTargetPath(targetPath, overwrite);

            if (mode.HasFlag(TransferMode.HardLink))
            {
                var createdHardlink = _diskProvider.TryCreateHardLink(sourcePath, targetPath);
                if (createdHardlink)
                {
                    return(TransferMode.HardLink);
                }
                if (!mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException("Hardlinking from '" + sourcePath + "' to '" + targetPath + "' failed.");
                }
            }

            if (verified)
            {
                if (mode.HasFlag(TransferMode.Copy))
                {
                    if (TryCopyFile(sourcePath, targetPath))
                    {
                        return(TransferMode.Copy);
                    }
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    if (TryMoveFile(sourcePath, targetPath))
                    {
                        return(TransferMode.Move);
                    }
                }

                throw new IOException(string.Format("Failed to completely transfer [{0}] to [{1}], aborting.", sourcePath, targetPath));
            }
            else if (VerificationMode == DiskTransferVerificationMode.VerifyOnly)
            {
                var originalSize = _diskProvider.GetFileSize(sourcePath);

                if (mode.HasFlag(TransferMode.Copy))
                {
                    try
                    {
                        _diskProvider.CopyFile(sourcePath, targetPath);

                        var targetSize = _diskProvider.GetFileSize(targetPath);
                        if (targetSize != originalSize)
                        {
                            throw new IOException(string.Format("File copy incomplete. [{0}] was {1} bytes long instead of {2} bytes.", targetPath, targetSize, originalSize));
                        }

                        return(TransferMode.Copy);
                    }
                    catch
                    {
                        RollbackCopy(sourcePath, targetPath);
                        throw;
                    }
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    try
                    {
                        _diskProvider.MoveFile(sourcePath, targetPath);

                        var targetSize = _diskProvider.GetFileSize(targetPath);
                        if (targetSize != originalSize)
                        {
                            throw new IOException(string.Format("File copy incomplete, data loss may have occured. [{0}] was {1} bytes long instead of the expected {2}.", targetPath, targetSize, originalSize));
                        }

                        return(TransferMode.Move);
                    }
                    catch
                    {
                        RollbackPartialMove(sourcePath, targetPath);
                        throw;
                    }
                }
            }
            else
            {
                if (mode.HasFlag(TransferMode.Copy))
                {
                    _diskProvider.CopyFile(sourcePath, targetPath);
                    return(TransferMode.Copy);
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    _diskProvider.MoveFile(sourcePath, targetPath);
                    return(TransferMode.Move);
                }
            }

            return(TransferMode.None);
        }
Example #19
0
        private void MigrateAppDataFolder()
        {
            try
            {
                var oldDbFile = Path.Combine(_appFolderInfo.AppDataFolder, "nzbdrone.db");

                if (_startupContext.Args.ContainsKey(StartupContext.APPDATA))
                {
                    if (_diskProvider.FileExists(_appFolderInfo.GetDatabase()))
                    {
                        return;
                    }
                    if (!_diskProvider.FileExists(oldDbFile))
                    {
                        return;
                    }

                    _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase());
                    CleanupSqLiteRollbackFiles();
                    RemovePidFile();
                }

                if (_appFolderInfo.LegacyAppDataFolder.IsNullOrWhiteSpace())
                {
                    return;
                }
                if (_diskProvider.FileExists(_appFolderInfo.GetDatabase()) || _diskProvider.FileExists(_appFolderInfo.GetConfigPath()))
                {
                    return;
                }
                if (!_diskProvider.FolderExists(_appFolderInfo.LegacyAppDataFolder))
                {
                    return;
                }

                // Delete the bin folder on Windows
                var binFolder = Path.Combine(_appFolderInfo.LegacyAppDataFolder, "bin");

                if (OsInfo.IsWindows && _diskProvider.FolderExists(binFolder))
                {
                    _diskProvider.DeleteFolder(binFolder, true);
                }

                // Transfer other files and folders (with copy so a backup is maintained)
                _diskTransferService.TransferFolder(_appFolderInfo.LegacyAppDataFolder, _appFolderInfo.AppDataFolder, TransferMode.Copy);

                // Rename the DB file
                if (_diskProvider.FileExists(oldDbFile))
                {
                    _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase());
                }

                // Remove SQLite rollback files
                CleanupSqLiteRollbackFiles();

                // Remove Old PID file
                RemovePidFile();

                // Delete the old files after everything has been copied
                _diskProvider.DeleteFolder(_appFolderInfo.LegacyAppDataFolder, true);
            }
            catch (Exception ex)
            {
                _logger.Debug(ex, ex.Message);
                throw new SonarrStartupException("Unable to migrate AppData folder from {0} to {1}. Migrate manually", _appFolderInfo.LegacyAppDataFolder, _appFolderInfo.AppDataFolder);
            }
        }
        private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List <Episode> episodes, String destinationFilename, Boolean copyOnly)
        {
            Ensure.That(episodeFile, () => episodeFile).IsNotNull();
            Ensure.That(series, () => series).IsNotNull();
            Ensure.That(destinationFilename, () => destinationFilename).IsValidPath();

            var episodeFilePath = episodeFile.Path ?? Path.Combine(series.Path, episodeFile.RelativePath);

            if (!_diskProvider.FileExists(episodeFilePath))
            {
                throw new FileNotFoundException("Episode file path does not exist", episodeFilePath);
            }

            if (episodeFilePath.PathEquals(destinationFilename))
            {
                throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath);
            }

            var directoryName = new FileInfo(destinationFilename).DirectoryName;

            if (!_diskProvider.FolderExists(directoryName))
            {
                try
                {
                    _diskProvider.CreateFolder(directoryName);
                }
                catch (IOException ex)
                {
                    _logger.ErrorException("Unable to create directory: " + directoryName, ex);
                }

                SetFolderPermissions(directoryName);

                if (!directoryName.PathEquals(series.Path))
                {
                    SetFolderPermissions(series.Path);
                }
            }

            if (copyOnly)
            {
                _logger.Debug("Copying [{0}] > [{1}]", episodeFilePath, destinationFilename);
                _diskProvider.CopyFile(episodeFilePath, destinationFilename);
            }
            else
            {
                _logger.Debug("Moving [{0}] > [{1}]", episodeFilePath, destinationFilename);
                _diskProvider.MoveFile(episodeFilePath, destinationFilename);
            }

            episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilename);

            _updateEpisodeFileService.ChangeFileDateForFile(episodeFile, series, episodes);

            try
            {
                SetFolderLastWriteTime(series.Path, episodeFile.DateAdded);

                if (series.SeasonFolder)
                {
                    var seasonFolder = Path.GetDirectoryName(destinationFilename);

                    SetFolderLastWriteTime(seasonFolder, episodeFile.DateAdded);
                }
            }

            catch (Exception ex)
            {
                _logger.WarnException("Unable to set last write time", ex);
            }

            //We should only run this on Windows
            if (OsInfo.IsWindows)
            {
                //Wrapped in Try/Catch to prevent this from causing issues with remote NAS boxes, the move worked, which is more important.
                try
                {
                    _diskProvider.InheritFolderPermissions(destinationFilename);
                }
                catch (Exception ex)
                {
                    if (ex is UnauthorizedAccessException || ex is InvalidOperationException)
                    {
                        _logger.Debug("Unable to apply folder permissions to: ", destinationFilename);
                        _logger.DebugException(ex.Message, ex);
                    }

                    else
                    {
                        throw;
                    }
                }
            }

            else
            {
                SetPermissions(destinationFilename, _configService.FileChmod);
            }

            return(episodeFile);
        }
        private MovieFile TransferFile(MovieFile movieFile, Movie movie, string destinationFilePath, TransferMode mode)
        {
            Ensure.That(movieFile, () => movieFile).IsNotNull();
            Ensure.That(movie, () => movie).IsNotNull();
            Ensure.That(destinationFilePath, () => destinationFilePath).IsValidPath();

            var movieFilePath = movieFile.Path ?? Path.Combine(movie.Path, movieFile.RelativePath);

            if (!_diskProvider.FileExists(movieFilePath))
            {
                throw new FileNotFoundException("Movie file path does not exist", movieFilePath);
            }

            if (movieFilePath == destinationFilePath)
            {
                throw new SameFilenameException("File not moved, source and destination are the same", movieFilePath);
            }

            _diskTransferService.TransferFile(movieFilePath, destinationFilePath, mode);

            var oldMoviePath = movie.Path;

            var newMoviePath = new OsPath(destinationFilePath).Directory.FullPath.TrimEnd(Path.DirectorySeparatorChar);

            movie.Path = newMoviePath; //We update it when everything went well!

            movieFile.RelativePath = movie.Path.GetRelativePath(destinationFilePath);

            _updateMovieFileService.ChangeFileDateForFile(movieFile, movie);

            try
            {
                _mediaFileAttributeService.SetFolderLastWriteTime(movie.Path, movieFile.DateAdded);
            }

            catch (Exception ex)
            {
                _logger.Warn(ex, "Unable to set last write time");
            }

            _mediaFileAttributeService.SetFilePermissions(destinationFilePath);

            if (oldMoviePath != newMoviePath && _diskProvider.FolderExists(oldMoviePath))
            {
                //Let's move the old files before deleting the old folder. We could just do move folder, but the main file (movie file) is already moved, so eh.
                var files = _diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories);

                foreach (var file in files)
                {
                    try
                    {
                        var destFile = Path.Combine(newMoviePath, oldMoviePath.GetRelativePath(file));
                        _diskProvider.EnsureFolder(Path.GetDirectoryName(destFile));
                        _diskProvider.MoveFile(file, destFile);
                    }
                    catch (Exception e)
                    {
                        _logger.Warn(e, "Error while trying to move extra file {0} to new folder. Maybe it already exists? (Manual cleanup necessary!).", oldMoviePath.GetRelativePath(file));
                    }
                }

                if (_diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories).Count() == 0)
                {
                    _recycleBinProvider.DeleteFolder(oldMoviePath);
                }
            }

            //Only update the movie path if we were successfull!
            if (oldMoviePath != newMoviePath)
            {
                _movieService.UpdateMovie(movie);
            }

            return(movieFile);
        }
Example #22
0
        public TransferMode TransferFile(string sourcePath, string targetPath, TransferMode mode, bool overwrite, DiskTransferVerificationMode verificationMode)
        {
            Ensure.That(sourcePath, () => sourcePath).IsValidPath();
            Ensure.That(targetPath, () => targetPath).IsValidPath();

            _logger.Debug("{0} [{1}] > [{2}]", mode, sourcePath, targetPath);

            var originalSize = _diskProvider.GetFileSize(sourcePath);

            if (sourcePath == targetPath)
            {
                throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
            }

            if (sourcePath.PathEquals(targetPath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (mode.HasFlag(TransferMode.HardLink) || mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException(string.Format("Source and destination can't be the same {0}", sourcePath));
                }

                if (mode.HasFlag(TransferMode.Move))
                {
                    var tempPath = sourcePath + ".backup~";

                    _diskProvider.MoveFile(sourcePath, tempPath, true);
                    try
                    {
                        ClearTargetPath(sourcePath, targetPath, overwrite);

                        _diskProvider.MoveFile(tempPath, targetPath);

                        return(TransferMode.Move);
                    }
                    catch
                    {
                        RollbackMove(sourcePath, tempPath);
                        throw;
                    }
                }

                return(TransferMode.None);
            }

            if (sourcePath.GetParentPath() == targetPath.GetParentPath())
            {
                if (mode.HasFlag(TransferMode.Move))
                {
                    TryMoveFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Move);
                }
            }

            if (sourcePath.IsParentPath(targetPath))
            {
                throw new IOException(string.Format("Destination cannot be a child of the source [{0}] => [{1}]", sourcePath, targetPath));
            }

            ClearTargetPath(sourcePath, targetPath, overwrite);

            if (mode.HasFlag(TransferMode.HardLink))
            {
                var createdHardlink = _diskProvider.TryCreateHardLink(sourcePath, targetPath);
                if (createdHardlink)
                {
                    return(TransferMode.HardLink);
                }
                if (!mode.HasFlag(TransferMode.Copy))
                {
                    throw new IOException("Hardlinking from '" + sourcePath + "' to '" + targetPath + "' failed.");
                }
            }

            // Adjust the transfer mode depending on the filesystems
            if (verificationMode == DiskTransferVerificationMode.TryTransactional)
            {
                var sourceMount = _diskProvider.GetMount(sourcePath);
                var targetMount = _diskProvider.GetMount(targetPath);

                var isSameMount = (sourceMount != null && targetMount != null && sourceMount.RootDirectory == targetMount.RootDirectory);

                var sourceDriveFormat = sourceMount?.DriveFormat ?? string.Empty;
                var targetDriveFormat = targetMount?.DriveFormat ?? string.Empty;

                if (isSameMount)
                {
                    // No transaction needed for operations on same mount, force VerifyOnly
                    verificationMode = DiskTransferVerificationMode.VerifyOnly;
                }
                else if (sourceDriveFormat.Contains("mergerfs") || sourceDriveFormat.Contains("rclone") ||
                         targetDriveFormat.Contains("mergerfs") || targetDriveFormat.Contains("rclone"))
                {
                    // Cloud storage filesystems don't need any Transactional stuff and it hurts performance, force VerifyOnly
                    verificationMode = DiskTransferVerificationMode.VerifyOnly;
                }
                else if ((sourceDriveFormat == "cifs" || targetDriveFormat == "cifs") && OsInfo.IsNotWindows)
                {
                    // Force Transactional on a cifs mount due to the likeliness of move failures on certain scenario's on mono
                    verificationMode = DiskTransferVerificationMode.Transactional;
                }
            }

            if (mode.HasFlag(TransferMode.Copy))
            {
                if (verificationMode == DiskTransferVerificationMode.Transactional || verificationMode == DiskTransferVerificationMode.TryTransactional)
                {
                    if (TryCopyFileTransactional(sourcePath, targetPath, originalSize))
                    {
                        return(TransferMode.Copy);
                    }

                    throw new IOException(string.Format("Failed to completely transfer [{0}] to [{1}], aborting.", sourcePath, targetPath));
                }
                else if (verificationMode == DiskTransferVerificationMode.VerifyOnly)
                {
                    TryCopyFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Copy);
                }
                else
                {
                    _diskProvider.CopyFile(sourcePath, targetPath);
                    return(TransferMode.Copy);
                }
            }

            if (mode.HasFlag(TransferMode.Move))
            {
                if (verificationMode == DiskTransferVerificationMode.Transactional || verificationMode == DiskTransferVerificationMode.TryTransactional)
                {
                    if (TryMoveFileTransactional(sourcePath, targetPath, originalSize, verificationMode))
                    {
                        return(TransferMode.Move);
                    }

                    throw new IOException(string.Format("Failed to completely transfer [{0}] to [{1}], aborting.", sourcePath, targetPath));
                }
                else if (verificationMode == DiskTransferVerificationMode.VerifyOnly)
                {
                    TryMoveFileVerified(sourcePath, targetPath, originalSize);
                    return(TransferMode.Move);
                }
                else
                {
                    _diskProvider.MoveFile(sourcePath, targetPath);
                    return(TransferMode.Move);
                }
            }

            return(TransferMode.None);
        }