示例#1
0
        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();
                    }
                }
            }
        }
示例#2
0
        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;
            }
        }
示例#3
0
        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);
        }