public static async Task CopyFileAsync(FileSystem srcFileSystem, string srcPath, FileSystem destFileSystem, string destPath, CopyFileParams?param = null, object?state = null, CancellationToken cancel = default, RefBool?readErrorIgnored = null) { if (readErrorIgnored == null) { readErrorIgnored = new RefBool(false); } readErrorIgnored.Set(false); if (param == null) { param = new CopyFileParams(); } srcPath = await srcFileSystem.NormalizePathAsync(srcPath, cancel : cancel); destPath = await destFileSystem.NormalizePathAsync(destPath, cancel : cancel); if (srcFileSystem == destFileSystem) { if (srcFileSystem.PathParser.PathStringComparer.Equals(srcPath, destPath)) { throw new FileException(destPath, "Both source and destination is the same file."); } } using (ProgressReporterBase reporter = param.ProgressReporterFactory.CreateNewReporter($"CopyFile '{srcFileSystem.PathParser.GetFileName(srcPath)}'", state)) { using (var srcFile = await srcFileSystem.OpenAsync(srcPath, flags: param.Flags, cancel: cancel)) { try { FileMetadata srcFileMetadata = await srcFileSystem.GetFileMetadataAsync(srcPath, param.MetadataCopier.OptimizedMetadataGetFlags, cancel); bool destFileExists = await destFileSystem.IsFileExistsAsync(destPath, cancel); using (var destFile = await destFileSystem.CreateAsync(destPath, flags: param.Flags, doNotOverwrite: !param.Overwrite, cancel: cancel)) { try { reporter.ReportProgress(new ProgressData(0, srcFileMetadata.Size)); Ref <uint> srcZipCrc = new Ref <uint>(); long copiedSize = await CopyBetweenFileBaseAsync(srcFile, destFile, param, reporter, srcFileMetadata.Size, cancel, readErrorIgnored, srcZipCrc); if (param.Flags.Bit(FileFlags.CopyFile_Verify) && param.IgnoreReadError == false) { // Verify を実施する // キャッシュを無効にするため、一度ファイルを閉じて再度開く await destFile.CloseAsync(); using (var destFile2 = await destFileSystem.OpenAsync(destPath, flags: param.Flags, cancel: cancel)) { uint destZipCrc = await CalcZipCrc32HandleAsync(destFile2, param, cancel); if (srcZipCrc.Value != destZipCrc) { // なんと Verify に失敗したぞ throw new CoresException($"CopyFile_Verify error. Src file: '{srcPath}', Dest file: '{destPath}', srcCrc: {srcZipCrc.Value}, destCrc = {destZipCrc}"); } } } reporter.ReportProgress(new ProgressData(copiedSize, copiedSize, true)); await destFile.CloseAsync(); try { await destFileSystem.SetFileMetadataAsync(destPath, param.MetadataCopier.Copy(srcFileMetadata), cancel); } catch (Exception ex) { Con.WriteDebug($"CopyFileAsync: '{destPath}': SetFileMetadataAsync failed. Error: {ex.Message}"); } } catch { if (destFileExists == false) { try { await destFile.CloseAsync(); } catch { } try { await destFileSystem.DeleteFileAsync(destPath); } catch { } } throw; } finally { await destFile.CloseAsync(); } } } finally { await srcFile.CloseAsync(); } } } }
protected async Task InternalInitAsync(CancellationToken cancel = default) { cancel.ThrowIfCancellationRequested(); try { bool newFille = false; LargeFileSystem.ParsedPath?lastFileParsed = InitialRelatedFiles.OrderBy(x => x.FileNumber).LastOrDefault(); if (lastFileParsed == null) { // New file CurrentFileSize = 0; newFille = true; if (FileParams.Mode == FileMode.Open || FileParams.Mode == FileMode.Truncate) { throw new IOException($"The file '{FileParams.Path}' not found."); } } else { // File exists if (FileParams.Mode == FileMode.CreateNew) { throw new IOException($"The file '{FileParams.Path}' already exists."); } checked { long sizeOfLastFile = (await UnderlayFileSystem.GetFileMetadataAsync(lastFileParsed.PhysicalFilePath, FileMetadataGetFlags.NoAlternateStream | FileMetadataGetFlags.NoSecurity, cancel)).Size; sizeOfLastFile = Math.Min(sizeOfLastFile, LargeFileSystem.Params.MaxSinglePhysicalFileSize); CurrentFileSize = lastFileParsed.FileNumber * LargeFileSystem.Params.MaxSinglePhysicalFileSize + sizeOfLastFile; } } if (FileParams.Mode == FileMode.Create || FileParams.Mode == FileMode.CreateNew || FileParams.Mode == FileMode.Truncate) { if (lastFileParsed != null) { // Delete the files first await LargeFileSystem.DeleteFileAsync(FileParams.Path, FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel); lastFileParsed = null; CurrentFileSize = 0; newFille = true; } } long currentPosition = 0; if (FileParams.Mode == FileMode.Append) { currentPosition = this.CurrentFileSize; } InitAndCheckFileSizeAndPosition(currentPosition, await GetFileSizeImplAsync(cancel), cancel); if (newFille) { using (var handle = await GetUnderlayRandomAccessHandle(0, cancel)) { } } } catch { throw; } }
public static async Task <CopyDirectoryStatus> CopyDirAsync(FileSystem srcFileSystem, string srcPath, FileSystem destFileSystem, string destPath, CopyDirectoryParams?param = null, object?state = null, CopyDirectoryStatus?statusObject = null, CancellationToken cancel = default) { CopyDirectoryStatus status = statusObject ?? new CopyDirectoryStatus(); status.Clear(); status.State = state; status.StartTick = Tick64.Now; if (param == null) { param = new CopyDirectoryParams(); } srcPath = await srcFileSystem.NormalizePathAsync(srcPath, cancel : cancel); destPath = await destFileSystem.NormalizePathAsync(destPath, cancel : cancel); if (srcFileSystem == destFileSystem) { if (srcFileSystem.PathParser.PathStringComparer.Equals(srcPath, destPath)) { throw new FileException(destPath, "Both source and destination is the same directory."); } } using (ProgressReporterBase dirReporter = param.EntireProgressReporterFactory.CreateNewReporter($"CopyDir '{srcFileSystem.PathParser.GetFileName(srcPath)}'", state)) { DirectoryWalker walker = new DirectoryWalker(srcFileSystem); bool walkRet = await walker.WalkDirectoryAsync(srcPath, async (dirInfo, entries, c) => { c.ThrowIfCancellationRequested(); foreach (FileSystemEntity entity in entries) { c.ThrowIfCancellationRequested(); try { if (await param.ProgressCallbackProc(status, entity) == false) { throw new OperationCanceledException($"Copying of the file '{entity.FullPath}' is cancaled by the user."); } string entryName = entity.Name; if (entity.IsCurrentDirectory) { entryName = ""; } string srcFullPath = srcFileSystem.PathParser.Combine(srcPath, dirInfo.RelativePath, entryName); string destFullPath = destFileSystem.PathParser.Combine(destPath, srcFileSystem.PathParser.ConvertDirectorySeparatorToOtherSystem(dirInfo.RelativePath, destFileSystem.PathParser), entryName); if (entity.IsDirectory == false) { // Copy a file lock (status.LockObj) status.NumFilesTotal++; FileMetadataGetFlags metadataGetFlags = FileMetadataCopier.CalcOptimizedMetadataGetFlags(param.FileMetadataCopier.Mode | FileMetadataCopyMode.Attributes); FileMetadata srcFileMetadata = await srcFileSystem.GetFileMetadataAsync(srcFullPath, metadataGetFlags, cancel); FileFlags copyFileAdditionalFlags = FileFlags.None; lock (status.LockObj) status.SizeTotal += srcFileMetadata.Size; if (param.CopyDirFlags.Bit(CopyDirectoryFlags.CopyFileCompressionFlag)) { if (srcFileMetadata.Attributes is FileAttributes attr) { if (attr.Bit(FileAttributes.Compressed)) { copyFileAdditionalFlags |= FileFlags.OnCreateSetCompressionFlag; } else { copyFileAdditionalFlags |= FileFlags.OnCreateRemoveCompressionFlag; } } } if (param.CopyDirFlags.Bit(CopyDirectoryFlags.CopyFileSparseFlag)) { if (srcFileMetadata.Attributes is FileAttributes attr) { if (attr.Bit(FileAttributes.SparseFile)) { copyFileAdditionalFlags |= FileFlags.SparseFile; } } } var copyFileParam = param.GenerateCopyFileParams(copyFileAdditionalFlags); RefBool ignoredReadError = new RefBool(false); await CopyFileAsync(srcFileSystem, srcFullPath, destFileSystem, destFullPath, copyFileParam, state, cancel, ignoredReadError); lock (status.LockObj) { status.NumFilesOk++; status.SizeOk += srcFileMetadata.Size; if (ignoredReadError) { status.IgnoreReadErrorFileNameList.Add(srcFullPath); } } } else { // Make a directory lock (status.LockObj) { status.NumDirectoriesTotal++; } FileMetadataGetFlags metadataGetFlags = FileMetadataCopier.CalcOptimizedMetadataGetFlags(param.DirectoryMetadataCopier.Mode | FileMetadataCopyMode.Attributes); FileMetadata srcDirMetadata = await srcFileSystem.GetDirectoryMetadataAsync(srcFullPath, metadataGetFlags, cancel); FileFlags copyDirFlags = FileFlags.None; if (param.CopyDirFlags.Bit(CopyDirectoryFlags.BackupMode)) { copyDirFlags |= FileFlags.BackupMode; } if (param.CopyDirFlags.Bit(CopyDirectoryFlags.CopyDirectoryCompressionFlag)) { if (srcDirMetadata.Attributes is FileAttributes attr) { if (attr.Bit(FileAttributes.Compressed)) { copyDirFlags |= FileFlags.OnCreateSetCompressionFlag; } else { copyDirFlags |= FileFlags.OnCreateRemoveCompressionFlag; } } } await destFileSystem.CreateDirectoryAsync(destFullPath, copyDirFlags, cancel); FileMetadata dstDirMetadata = param.DirectoryMetadataCopier.Copy(srcDirMetadata); if (param.CopyDirFlags.Bit(CopyDirectoryFlags.SetAclProtectionFlagOnRootDir)) { if (dirInfo.IsRoot) { if (dstDirMetadata.Security != null) { if (dstDirMetadata.Security.Acl != null) { dstDirMetadata.Security.Acl.Win32AclSddl = "!" + dstDirMetadata.Security.Acl.Win32AclSddl; } if (dstDirMetadata.Security.Audit != null) { dstDirMetadata.Security.Audit.Win32AuditSddl = "!" + dstDirMetadata.Security.Audit.Win32AuditSddl; } } } } await destFileSystem.SetDirectoryMetadataAsync(destFullPath, dstDirMetadata, cancel); lock (status.LockObj) status.NumDirectoriesOk++; } } catch (Exception ex) { if (await param.ExceptionCallbackProc(status, entity, ex) == false) { throw ex; } } } return(true); }, async (dirInfo, entries, c) => { c.ThrowIfCancellationRequested(); foreach (FileSystemEntity entity in entries) { c.ThrowIfCancellationRequested(); string entryName = entity.Name; if (entity.IsCurrentDirectory) { entryName = ""; } string srcFullPath = srcFileSystem.PathParser.Combine(srcPath, dirInfo.RelativePath, entryName); string destFullPath = destFileSystem.PathParser.Combine(destPath, srcFileSystem.PathParser.ConvertDirectorySeparatorToOtherSystem(dirInfo.RelativePath, destFileSystem.PathParser), entryName); if (entity.IsDirectory) { // Update the directory LastWriteTime metadata after placing all inside files into the directory if (param.DirectoryMetadataCopier.Mode.BitAny(FileMetadataCopyMode.TimeAll)) { FileMetadataGetFlags metadataGetFlags = FileMetadataCopier.CalcOptimizedMetadataGetFlags(param.DirectoryMetadataCopier.Mode & (FileMetadataCopyMode.TimeAll)); FileMetadata srcDirMetadata = await srcFileSystem.GetDirectoryMetadataAsync(srcFullPath, metadataGetFlags, cancel); FileMetadata dstDirMetadata = param.DirectoryMetadataCopier.Copy(srcDirMetadata); await destFileSystem.SetDirectoryMetadataAsync(destFullPath, dstDirMetadata, cancel); } } } return(true); }, async (dirInfo, exception, c) => { c.ThrowIfCancellationRequested(); if (await param.ExceptionCallbackProc(status, dirInfo.Entity, exception) == false) { throw exception; } return(true); }, param.CopyDirFlags.Bit(CopyDirectoryFlags.Recursive), cancel ); } status.EndTick = Tick64.Now; return(status); }