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); }
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); } }
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); }
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); } }
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; } }
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); } }
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()); } }
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); }
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)); }
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); }
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); } }
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); }
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); }
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; }
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); }
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); }
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); }
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); }
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); }