예제 #1
0
        internal static Task <PipRuntimeTimeTable> LoadAsync(Stream fileStream)
        {
            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                int size = await ReadFileFormatMarkerAsync(fileStream);
                var table = new PipRuntimeTimeTable(LoggingContext);

                using (BuildXLReader reader = new BuildXLReader(false, fileStream, true))
                {
                    for (int i = 0; i < size; ++i)
                    {
                        long semiStableHash = reader.ReadInt64();
                        PipHistoricPerfData historicData;
                        if (PipHistoricPerfData.Deserialize(reader, out historicData))
                        {
                            if (!table.m_runtimeData.TryAdd(semiStableHash, historicData))
                            {
                                throw new BuildXLException("Corrupted file has duplicate records");
                            }
                        }
                    }
                }

                if (fileStream.Position != fileStream.Length)
                {
                    throw new BuildXLException("Corrupted file has excess bytes");
                }

                return table;
            },
                       ex => { throw new BuildXLException("Reading of file failed", ex); }));
        }
예제 #2
0
        /// <inheritdoc />
        public Task <Possible <Unit, Failure> > TryMaterializeAsync(
            FileRealizationMode fileRealizationMode,
            ExpandedAbsolutePath path,
            ContentHash contentHash)
        {
            return(Task.Run(
                       () =>
            {
                lock (m_lock)
                {
                    CacheEntry entry;
                    if (m_content.TryGetValue(contentHash, out entry))
                    {
                        if ((entry.Sites & CacheSites.Local) == 0)
                        {
                            return new Failure <string>("Content is available in 'remote' cache but is not local. Load it locally first with TryLoadAvailableContentAsync.");
                        }

                        string expandedPath = path.ExpandedPath;

                        var result = ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                            async() => await PlaceFileInternalAsync(expandedPath, contentHash, fileRealizationMode),
                            ex => { throw new BuildXLException("Failed to materialize content (content found, but couldn't write it)", ex); });

                        m_pathRealizationModes[expandedPath] = fileRealizationMode;
                        return result.Result;
                    }
                    else
                    {
                        return new Failure <string>("Content not found (locally or remotely). Store it first with TryStoreAsync.");
                    }
                }
            }));
        }
예제 #3
0
        /// <inheritdoc />
        public Task <bool> CopyFileAsync(
            string source,
            string destination,
            Func <SafeFileHandle, SafeFileHandle, bool> predicate = null,
            Action <SafeFileHandle, SafeFileHandle> onCompletion  = null)
        {
            Contract.Requires(!string.IsNullOrEmpty(source));
            Contract.Requires(!string.IsNullOrEmpty(destination));

            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                using (FileStream sourceStream = CreateAsyncFileStream(
                           source,
                           FileMode.Open,
                           FileAccess.Read,
                           FileShare.Read | FileShare.Delete))
                {
                    if (predicate != null)
                    {
                        SafeFileHandle destinationHandle;
                        OpenFileResult predicateQueryOpenResult = s_fileSystem.TryCreateOrOpenFile(
                            destination,
                            FileDesiredAccess.GenericRead,
                            FileShare.Read | FileShare.Delete,
                            FileMode.OpenOrCreate,
                            FileFlagsAndAttributes.None,
                            out destinationHandle);
                        using (destinationHandle)
                        {
                            if (!predicateQueryOpenResult.Succeeded)
                            {
                                throw new BuildXLException(
                                    I($"Failed to open a copy destination '{destination}' to check its version"),
                                    predicateQueryOpenResult.CreateExceptionForError());
                            }

                            if (!predicate(sourceStream.SafeFileHandle, predicateQueryOpenResult.OpenedOrTruncatedExistingFile ? destinationHandle : null))
                            {
                                return false;
                            }
                        }
                    }

                    using (FileStream destinationStream = CreateReplacementFile(destination, FileShare.Delete, openAsync: true))
                    {
                        await sourceStream.CopyToAsync(destinationStream);
                        onCompletion?.Invoke(sourceStream.SafeFileHandle, destinationStream.SafeFileHandle);
                    }
                }

                return true;
            },
                       ex => { throw new BuildXLException("File copy failed", ex); }));
        }
예제 #4
0
        /// <inheritdoc />
        public Task <bool> WriteAllBytesAsync(
            string filePath,
            byte[] bytes,
            Func <SafeFileHandle, bool> predicate = null,
            Action <SafeFileHandle> onCompletion  = null)
        {
            Contract.Requires(!string.IsNullOrEmpty(filePath));
            Contract.Requires(bytes != null);

            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                if (predicate != null)
                {
                    SafeFileHandle destinationHandle;
                    OpenFileResult predicateQueryOpenResult = m_fileSystem.TryCreateOrOpenFile(
                        filePath,
                        FileDesiredAccess.GenericRead,
                        FileShare.Read | FileShare.Delete,
                        FileMode.OpenOrCreate,
                        FileFlagsAndAttributes.None,
                        out destinationHandle);
                    using (destinationHandle)
                    {
                        if (!predicateQueryOpenResult.Succeeded)
                        {
                            throw new BuildXLException(
                                I($"Failed to open file '{filePath}' to check its version"),
                                predicateQueryOpenResult.CreateExceptionForError());
                        }

                        if (!predicate(predicateQueryOpenResult.OpenedOrTruncatedExistingFile ? destinationHandle : null))
                        {
                            return false;
                        }
                    }
                }

                using (FileStream stream = CreateReplacementFile(filePath, FileShare.Delete, openAsync: true))
                {
                    await stream.WriteAsync(bytes, 0, bytes.Length);
                }

                if (onCompletion != null)
                {
                    using (var file = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Delete))
                    {
                        onCompletion(file.SafeFileHandle);
                    }
                }

                return true;
            },
                       ex => { throw new BuildXLException("File write failed", ex); }));
        }
예제 #5
0
        /// <summary>
        /// Tries to duplicate a file.
        /// </summary>
        public static Task <FileDuplicationResult> TryDuplicateOneFileAsync(string sourcePath, string destinationPath)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(sourcePath));
            Contract.Requires(!string.IsNullOrWhiteSpace(destinationPath));

            if (string.Compare(sourcePath, destinationPath, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return(Task.FromResult(FileDuplicationResult.Existed)); // Nothing to do.
            }

            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                var destinationDirectory = Path.GetDirectoryName(destinationPath);
                if (DirectoryExistsNoFollow(destinationDirectory))
                {
                    if (FileExistsNoFollow(destinationPath))
                    {
                        DeleteFile(destinationPath);
                    }
                }
                else
                {
                    CreateDirectory(destinationDirectory);
                }

                if (!OperatingSystemHelper.IsUnixOS)
                {
                    var hardlinkResult = s_fileSystem.TryCreateHardLinkViaSetInformationFile(destinationPath, sourcePath);

                    if (hardlinkResult == CreateHardLinkStatus.Success)
                    {
                        return FileDuplicationResult.Hardlinked;
                    }
                }
                else
                {
                    if (IsCopyOnWriteSupportedByEnlistmentVolume)
                    {
                        var possiblyCreateCopyOnWrite = TryCreateCopyOnWrite(sourcePath, destinationPath, followSymlink: false);
                        if (possiblyCreateCopyOnWrite.Succeeded)
                        {
                            return FileDuplicationResult.Copied;
                        }
                    }
                }

                await CopyFileAsync(sourcePath, destinationPath);
                return FileDuplicationResult.Copied;
            },
                       ex => { throw new BuildXLException(ex.Message); }));
        }
예제 #6
0
        /// <summary>
        /// Tries to duplicate a file.
        /// </summary>
        public static Task <FileDuplicationResult> TryDuplicateOneFileAsync(string sourcePath, string destinationPath)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(sourcePath));
            Contract.Requires(!string.IsNullOrWhiteSpace(destinationPath));

            if (string.Compare(sourcePath, destinationPath, StringComparison.OrdinalIgnoreCase) == 0)
            {
                return(Task.FromResult(FileDuplicationResult.Existed)); // Nothing to do.
            }

            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                var destinationDirectory = Path.GetDirectoryName(destinationPath);
                if (DirectoryExistsNoFollow(destinationDirectory))
                {
                    if (FileExistsNoFollow(destinationPath))
                    {
                        DeleteFile(destinationPath);
                    }
                }
                else
                {
                    CreateDirectory(destinationDirectory);
                }

                // Our implementation on macOS requires APFS which has copy on write. There's no advantage to using
                // a hardlink over a file copy. VSTS 1333283
                if (!OperatingSystemHelper.IsUnixOS)
                {
                    var hardlinkResult = s_fileSystem.TryCreateHardLinkViaSetInformationFile(destinationPath, sourcePath);

                    if (hardlinkResult == CreateHardLinkStatus.Success)
                    {
                        return FileDuplicationResult.Hardlinked;
                    }
                }

                await CopyFileAsync(sourcePath, destinationPath);
                return FileDuplicationResult.Copied;
            },
                       ex => { throw new BuildXLException(ex.Message); }));
        }
예제 #7
0
        internal Task SaveAsync(Stream fileStream)
        {
            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                await WriteFileFormatMarkerAsync(fileStream, m_runtimeData.Count);

                using (BuildXLWriter writer = new BuildXLWriter(false, fileStream, true, false))
                {
                    foreach (KeyValuePair <long, PipHistoricPerfData> kvp in m_runtimeData)
                    {
                        writer.Write(kvp.Key);
                        kvp.Value.Serialize(writer);
                    }
                }

                // Truncate, just in case file already existed but was bigger
                fileStream.SetLength(fileStream.Position);
                return (object)null;
            },
                       ex => { throw new BuildXLException("Writing of file failed", ex); }));
        }
예제 #8
0
        /// <inheritdoc />
        public Task <bool> CopyFileAsync(
            string source,
            string destination,
            Func <SafeFileHandle, SafeFileHandle, bool> predicate = null,
            Action <SafeFileHandle, SafeFileHandle> onCompletion  = null)
        {
            Contract.Requires(!string.IsNullOrEmpty(source));
            Contract.Requires(!string.IsNullOrEmpty(destination));

            return(ExceptionUtilities.HandleRecoverableIOExceptionAsync(
                       async() =>
            {
                using (FileStream sourceStream = CreateAsyncFileStream(
                           source,
                           FileMode.Open,
                           FileAccess.Read,
                           FileShare.Read | FileShare.Delete))
                {
                    if (predicate != null)
                    {
                        SafeFileHandle destinationHandle;
                        OpenFileResult predicateQueryOpenResult = m_fileSystem.TryCreateOrOpenFile(
                            destination,
                            FileDesiredAccess.GenericRead,
                            FileShare.Read | FileShare.Delete,
                            FileMode.OpenOrCreate,
                            FileFlagsAndAttributes.None,
                            out destinationHandle);
                        using (destinationHandle)
                        {
                            if (!predicateQueryOpenResult.Succeeded)
                            {
                                throw new BuildXLException(
                                    I($"Failed to open a copy destination '{destination}' to check its version"),
                                    predicateQueryOpenResult.CreateExceptionForError());
                            }

                            if (!predicate(sourceStream.SafeFileHandle, predicateQueryOpenResult.OpenedOrTruncatedExistingFile ? destinationHandle : null))
                            {
                                return false;
                            }
                        }
                    }

                    using (var destinationStream = CreateReplacementFile(destination, FileShare.Delete, openAsync: true))
                    {
                        await sourceStream.CopyToAsync(destinationStream);
                        var mode = GetFilePermissionsForFilePath(source, followSymlink: false);
                        var result = SetFilePermissionsForFilePath(destination, checked ((FilePermissions)mode), followSymlink: false);
                        if (result < 0)
                        {
                            throw new BuildXLException($"Failed to set permissions for file copy at '{destination}' - error: {Marshal.GetLastWin32Error()}");
                        }
                    }

                    if (onCompletion != null)
                    {
                        using (var dest = File.Open(destination, FileMode.Open, FileAccess.Read, FileShare.Delete))
                        {
                            onCompletion(sourceStream.SafeFileHandle, dest.SafeFileHandle);
                        }
                    }
                }

                return true;
            },
                       ex => { throw new BuildXLException(I($"File copy from '{source}' to '{destination}' failed"), ex); }));
        }