Exemple #1
0
 private static FileSystemType GetFileSystemType(string path)
 {
     using (FileStream fileStream = FileUtilities.CreateFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
     {
         return(FileUtilities.GetVolumeFileSystemByHandle(fileStream.SafeFileHandle));
     }
 }
Exemple #2
0
 private static bool SupportCopyOnWrite(string path)
 {
     using (FileStream fileStream = FileUtilities.CreateFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
     {
         return(FileUtilities.CheckIfVolumeSupportsCopyOnWriteByHandle(fileStream.SafeFileHandle));
     }
 }
Exemple #3
0
        public void TestVolumeFileSystemName()
        {
            var file = GetFullPath(nameof(TestVolumeFileSystemName));

            File.WriteAllText(file, nameof(TestVolumeFileSystemName));

            using (var stream = FileUtilities.CreateFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
            {
                FileSystemType fsType = FileUtilities.GetVolumeFileSystemByHandle(stream.SafeFileHandle);
                XAssert.AreNotEqual(FileSystemType.Unknown, fsType);
            }
        }
Exemple #4
0
        /// <summary>
        /// Retrieves an already-known <see cref="ContentHash" /> for the given path. If no such hash is available (such as if the
        /// file has been modified since a hash was last recorded), null is returned instead.
        /// </summary>
        /// <remarks>
        /// Note that this results in a small amount of I/O (e.g., on Windows, a file open and USN query), but never hashes the file or reads its contents.
        /// </remarks>
        /// <exception cref="BuildXLException">Thrown if the given path could not be opened for reading.</exception>
        public VersionedFileIdentityAndContentInfo?TryGetKnownContentHash(string path)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(path));

            try
            {
                using (
                    FileStream stream = FileUtilities.CreateFileStream(
                        path,
                        FileMode.Open,
                        FileAccess.Read,
                        FileShare.Read | FileShare.Delete))
                {
                    return(TryGetKnownContentHash(stream.Name, stream.SafeFileHandle));
                }
            }
            catch (BuildXLException)
            {
                return(null);
            }
        }
Exemple #5
0
        private static void WithNewFileMemoryMapped(string path, Action action)
        {
            using (FileStream file = FileUtilities.CreateFileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete | FileShare.Read))
            {
                file.SetLength(1024);
                using (
                    MemoryMappedFile.CreateFromFile(
                        file,
                        mapName: null,
                        capacity: 0,
                        access: MemoryMappedFileAccess.ReadWrite,
#if !DISABLE_FEATURE_MEMORYMAP_SECURITY
                        memoryMappedFileSecurity: null,
#endif
                        inheritability: HandleInheritability.None,
                        leaveOpen: false))
                {
                    action();
                }
            }
        }
Exemple #6
0
        private void SaveInternal(string fileContentTablePath)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(fileContentTablePath));
            Contract.EnsuresOnThrow <BuildXLException>(true);

            ExceptionUtilities.HandleRecoverableIOException(
                () =>
            {
                int numEvicted = 0;

                Directory.CreateDirectory(Path.GetDirectoryName(fileContentTablePath));

                // Note that we are using a non-async file stream here. That's because we're doing lots of tiny writes for simplicity,
                // but tiny writes on an async stream end up blocking anyway while adding silly overhead.
                using (FileStream stream = FileUtilities.CreateFileStream(
                           fileContentTablePath,
                           FileMode.Create,
                           FileAccess.Write,
                           FileShare.Delete,
                           // Do not write the file with SequentialScan since it will be reread in the subsequent build
                           FileOptions.None))
                {
                    // We don't have anything in particular to correlate this file to,
                    // so we are simply creating a unique correlation id that is used as part
                    // of the header consistency check.
                    FileEnvelopeId correlationId = FileEnvelopeId.Create();
                    s_fileEnvelope.WriteHeader(stream, correlationId);

                    using (var writer = new BuildXLWriter(debug: false, stream: stream, leaveOpen: true, logStats: false))
                    {
                        long numberOfEntriesPosition = writer.BaseStream.Position;
                        writer.Write(0U);

                        uint entriesWritten = 0;
                        var hashBuffer      = new byte[ContentHashingUtilities.HashInfo.ByteLength];

                        foreach (var fileAndEntryPair in m_entries)
                        {
                            // Skip saving anything with a TTL of zero. These entries were loaded
                            // with a TTL of one (immediately decremented) and were not used since load.
                            // See class remarks.
                            if (fileAndEntryPair.Value.TimeToLive == 0)
                            {
                                numEvicted++;
                                continue;
                            }

                            // Key: Volume and File ID
                            fileAndEntryPair.Key.Serialize(writer);

                            // Entry: USN, hash, time to live.
                            writer.Write(fileAndEntryPair.Value.Usn.Value);
                            fileAndEntryPair.Value.Hash.SerializeHashBytes(hashBuffer, 0);
                            writer.Write(hashBuffer);
                            writer.Write(fileAndEntryPair.Value.Length);
                            writer.Write(fileAndEntryPair.Value.TimeToLive);

                            entriesWritten++;
                        }

                        var endPosition            = writer.BaseStream.Position;
                        writer.BaseStream.Position = numberOfEntriesPosition;
                        writer.Write(entriesWritten);
                        writer.BaseStream.Position = endPosition;
                    }

                    s_fileEnvelope.FixUpHeader(stream, correlationId);
                }

                Counters.AddToCounter(FileContentTableCounters.NumEvicted, numEvicted);
                return(Unit.Void);
            },
                ex => { throw new BuildXLException("Failure writing file content table", ex); });
        }
Exemple #7
0
        private static LoadResult TryLoadInternal(string fileContentTablePath, byte entryTimeToLive)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(fileContentTablePath));
            Contract.Requires(entryTimeToLive > 0);

            if (!FileUtilities.FileExistsNoFollow(fileContentTablePath))
            {
                return(LoadResult.FileNotFound(fileContentTablePath));
            }

            Stopwatch sw = Stopwatch.StartNew();

            try
            {
                using (FileStream stream = FileUtilities.CreateFileStream(
                           fileContentTablePath,
                           FileMode.Open,
                           FileAccess.Read,
                           FileShare.Read | FileShare.Delete,
                           // Ok to evict the file from standby since the file will be overwritten and never reread from disk after this point.
                           FileOptions.SequentialScan))
                {
                    try
                    {
                        Analysis.IgnoreResult(s_fileEnvelope.ReadHeader(stream));
                    }
                    catch (BuildXLException ex)
                    {
                        return(LoadResult.InvalidFormat(fileContentTablePath, ex.LogEventMessage, sw.ElapsedMilliseconds));
                    }

                    using (var reader = new BuildXLReader(debug: false, stream: stream, leaveOpen: true))
                    {
                        var loadedTable = new FileContentTable();

                        uint numberOfEntries = reader.ReadUInt32();
                        int  hashLength      = ContentHashingUtilities.HashInfo.ByteLength;
                        var  hashBuffer      = new byte[hashLength];

                        for (uint i = 0; i < numberOfEntries; i++)
                        {
                            // Key: Volume and file ID
                            var fileIdAndVolumeId = FileIdAndVolumeId.Deserialize(reader);

                            // Entry: USN, hash, length, time to live.
                            Usn usn = new Usn(reader.ReadUInt64());

                            int hashBytesRead = 0;
                            while (hashBytesRead != hashLength)
                            {
                                int thisRead = reader.Read(hashBuffer, hashBytesRead, hashLength - hashBytesRead);
                                if (thisRead == 0)
                                {
                                    return(LoadResult.InvalidFormat(fileContentTablePath, "Unexpected end of stream", sw.ElapsedMilliseconds));
                                }

                                hashBytesRead += thisRead;
                                Contract.Assert(hashBytesRead <= hashLength);
                            }

                            long length = reader.ReadInt64();

                            byte thisEntryTimeToLive = reader.ReadByte();
                            if (thisEntryTimeToLive == 0)
                            {
                                return(LoadResult.InvalidFormat(fileContentTablePath, "TTL value must be positive", sw.ElapsedMilliseconds));
                            }

                            thisEntryTimeToLive = Math.Min(thisEntryTimeToLive, entryTimeToLive);
                            Contract.Assert(thisEntryTimeToLive > 0);

                            // We've loaded this entry just now and so clearly haven't used it yet. Tentatively decrement the TTL
                            // for the in-memory table; if the table is saved again without using this entry, the TTL will stay at this
                            // lower value.
                            thisEntryTimeToLive--;

                            var  observedVersionAndHash = new Entry(usn, ContentHashingUtilities.CreateFrom(hashBuffer), length, thisEntryTimeToLive);
                            bool added = loadedTable.m_entries.TryAdd(fileIdAndVolumeId, observedVersionAndHash);
                            Contract.Assume(added);
                        }

                        loadedTable.Counters.AddToCounter(FileContentTableCounters.NumEntries, loadedTable.Count);

                        return(LoadResult.Success(fileContentTablePath, loadedTable, sw.ElapsedMilliseconds));
                    }
                }
            }
            catch (Exception ex)
            {
                return(LoadResult.Exception(fileContentTablePath, ex, sw.ElapsedMilliseconds));
            }
        }