示例#1
0
        /// <summary>
        /// Fills in the magic
        /// </summary>
        /// <remarks>
        /// This method must be called at the very end of the stream construction.
        /// Afterwards, no further stream modifications should occur.
        /// </remarks>
        public void FixUpHeader(Stream stream, FileEnvelopeId correlationId)
        {
            Contract.Requires(stream != null);
            Contract.Requires(correlationId.IsValid);

            var length = stream.Position;

            // Truncate, just in case file already existed but was bigger
            stream.SetLength(stream.Position);

            stream.Position =
                m_name.Length +
                Eol.Length +
                correlationId.Value.Length;

            using (var writer = new BinaryWriter(stream, CharUtilities.Utf8NoBomNoThrow, leaveOpen: true))
            {
                WriteHeaderFixUp(
                    writer,
                    CleanEof,
                    Version,
                    m_version,
                    length,
                    ComputeMagic(length, correlationId));
            }

            stream.Position = length;
        }
示例#2
0
        internal void Save(Stream stream, string fileName)
        {
            ExceptionUtilities.HandleRecoverableIOException(
                () =>
            {
                // 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 (BuildXLWriter writer = new BuildXLWriter(debug: false, stream: stream, leaveOpen: true, logStats: false))
                {
                    m_pathTable.StringTable.Serialize(writer);
                    m_pathTable.Serialize(writer);

                    writer.Write(m_pathMapping.Count);

                    foreach (var kvp in m_pathMapping)
                    {
                        writer.Write(kvp.Key);
                        writer.Write(kvp.Value);
                    }
                }

                s_fileEnvelope.FixUpHeader(stream, correlationId);
                return((object)null);
            },
                ex => { throw new BuildXLException(I($"Failed to write to '{fileName}'"), ex); });
        }
示例#3
0
 private long ComputeMagic(long length, FileEnvelopeId id)
 {
     // HashCodeHelper performs a stable hash code computation.
     // We take into account the other header fields, and the file length.
     return(HashCodeHelper.Combine(
                HashCodeHelper.GetOrdinalHashCode64(m_name),
                HashCodeHelper.GetOrdinalHashCode64(id.Value),
                Version | (long)(((ulong)(uint)m_version) << 32),
                length));
 }
示例#4
0
        /// <summary>
        /// Checks whether actual and expected ids match
        /// </summary>
        /// <exception cref="BuildXLException">Thrown when the file header is corrupted.</exception>
        public static void CheckCorrelationIds(FileEnvelopeId persistedCorrelationId, FileEnvelopeId expectedCorrelationId)
        {
            Contract.Requires(persistedCorrelationId.IsValid);
            Contract.Requires(expectedCorrelationId.IsValid);

            if (persistedCorrelationId.Value != expectedCorrelationId.Value)
            {
                throw new BuildXLException("Correlation ids don't match");
            }
        }
示例#5
0
        /// <summary>
        /// Writes the header, leaving space for some details to be fixed up later
        /// </summary>
        /// <remarks>
        /// This method must be called at the very beginning of the stream construction.
        /// If stream writing was successful, then <see cref="FixUpHeader"/> must be called at the very end of the stream construction.
        /// </remarks>
        public void WriteHeader(Stream stream, FileEnvelopeId correlationId)
        {
            Contract.Requires(stream != null);
            Contract.Requires(correlationId.IsValid);

            if (stream.Position != 0)
            {
                throw new BuildXLException("File beginning mismatch");
            }

            using (var writer = new BinaryWriter(stream, CharUtilities.Utf8NoBomNoThrow, leaveOpen: true))
            {
                writer.Write(m_name.ToCharArray());
                writer.Write(Eol.ToCharArray());
                writer.Write(correlationId.Value.ToCharArray());

                // Things will need get fixed up starting from here.
                WriteHeaderFixUp(writer, DirtyEof, 0, 0, 0, 0);
            }
        }
示例#6
0
        /// <summary>
        /// Reads the file header from the stream.
        /// </summary>
        /// <returns>Persisted correlation id</returns>
        /// <exception cref="BuildXLException">Thrown when the file header is incomplete, outdated, or corrupted.</exception>
        public FileEnvelopeId ReadHeader(Stream stream)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <FileEnvelopeId>().IsValid);

            if (stream.Position != 0)
            {
                throw new BuildXLException("File beginning mismatch");
            }

            try
            {
                using (var reader = new BinaryReader(stream, CharUtilities.Utf8NoBomNoThrow, leaveOpen: true))
                {
                    string persistedName = SafeReadRawString(reader, m_name.Length);
                    if (persistedName != m_name)
                    {
                        throw new BuildXLException("Wrong name");
                    }

                    string persistedEol = SafeReadRawString(reader, Eol.Length);
                    if (persistedEol != Eol)
                    {
                        throw new BuildXLException("Wrong end of line marker");
                    }

                    var    buffer       = new char[MaxIdentifierLength];
                    int    bufferLength = 0;
                    string persistedEof;
                    while (true)
                    {
                        char c = SafeReadChar(reader);
                        if (c == CleanEof[0] || c == DirtyEof[0])
                        {
                            Contract.Assume(CleanEof.Length == DirtyEof.Length);
                            persistedEof = c + SafeReadRawString(reader, CleanEof.Length - 1);
                            break;
                        }

                        if (bufferLength == MaxIdentifierLength)
                        {
                            throw new BuildXLException("Name too long");
                        }

                        buffer[bufferLength++] = c;
                    }

                    var persistedIdString = new string(buffer, 0, bufferLength);
                    if (!IsValidIdentifier(persistedIdString))
                    {
                        throw new BuildXLException("Illegal name");
                    }

                    var persistedId = new FileEnvelopeId(persistedIdString);

                    if (persistedEof == DirtyEof)
                    {
                        throw new BuildXLException("Dirty file!");
                    }

                    if (persistedEof != CleanEof)
                    {
                        throw new BuildXLException("Wrong end of file marker");
                    }

                    var persistedClassVersion = reader.ReadInt32();
                    if (persistedClassVersion != Version)
                    {
                        throw new BuildXLException("Wrong class version");
                    }

                    var persistedInstanceVersion = reader.ReadInt32();
                    if (persistedInstanceVersion != m_version)
                    {
                        throw new BuildXLException("Wrong instance version");
                    }

                    var persistedLength = reader.ReadInt64();
                    var length          = reader.BaseStream.Length;
                    if (persistedLength != length)
                    {
                        throw new BuildXLException("Wrong length");
                    }

                    var persistedMagic = reader.ReadInt64();
                    var actualMagic    = ComputeMagic(length, persistedId);
                    if (persistedMagic != actualMagic)
                    {
                        throw new BuildXLException("Wrong magic number");
                    }

                    return(persistedId);
                }
            }
            catch (IOException ex)
            {
                throw new BuildXLException("Error reading file header", ex);
            }
        }
示例#7
0
        /// <summary>
        /// Reads the file header from the stream.
        /// </summary>
        /// <param name="stream">stream from which to read</param>
        /// <param name="ignoreChecksum">when set, ignores errors and keeps reading all fields written by FileEnvelope's serialization</param>
        /// <returns></returns>
        public Possible <FileEnvelopeId> TryReadHeader(Stream stream, bool ignoreChecksum)
        {
            Contract.Requires(stream != null);
            Contract.Requires(stream.Position == 0);

            string firstError = null;

            void setError(string err)
            {
                if (firstError == null)
                {
                    firstError = err;
                }
            }

            Possible <FileEnvelopeId> getErrorResult() => new Failure <string>(firstError);
            Possible <FileEnvelopeId> error(string err) => new Failure <string>(err);

            try
            {
                using (var reader = new BinaryReader(stream, CharUtilities.Utf8NoBomNoThrow, leaveOpen: true))
                {
                    string persistedName = SafeReadRawString(reader, m_name.Length);
                    if (persistedName != m_name)
                    {
                        return(error($"Wrong name Persisted:'{persistedName}', Expected:'{m_name}'"));
                    }

                    string persistedEol = SafeReadRawString(reader, Eol.Length);
                    if (persistedEol != Eol)
                    {
                        return(error("Wrong end of line marker"));
                    }

                    var    buffer       = new char[MaxIdentifierLength];
                    int    bufferLength = 0;
                    string persistedEof;
                    while (true)
                    {
                        char c = SafeReadChar(reader);
                        if (c == CleanEof[0] || c == DirtyEof[0])
                        {
                            Contract.Assume(CleanEof.Length == DirtyEof.Length);
                            persistedEof = c + SafeReadRawString(reader, CleanEof.Length - 1);
                            break;
                        }

                        if (bufferLength == MaxIdentifierLength)
                        {
                            return(error("Name too long"));
                        }

                        buffer[bufferLength++] = c;
                    }

                    var persistedIdString = new string(buffer, 0, bufferLength);
                    if (!IsValidIdentifier(persistedIdString))
                    {
                        return(error("Illegal name"));
                    }

                    var persistedId = new FileEnvelopeId(persistedIdString);

                    if (persistedEof == DirtyEof)
                    {
                        setError("Dirty file!");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    if (persistedEof != CleanEof)
                    {
                        setError("Wrong end of file marker");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    var persistedClassVersion = reader.ReadInt32();
                    if (persistedClassVersion != Version)
                    {
                        setError("Wrong class version");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    var persistedInstanceVersion = reader.ReadInt32();
                    if (persistedInstanceVersion != m_version)
                    {
                        setError("Wrong instance version");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    var persistedLength = reader.ReadInt64();
                    var length          = reader.BaseStream.Length;
                    if (persistedLength != length)
                    {
                        setError("Wrong length");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    var persistedMagic = reader.ReadInt64();
                    if (persistedMagic != ComputeMagic(length, persistedId))
                    {
                        setError("Wrong magic number");
                        if (!ignoreChecksum)
                        {
                            return(getErrorResult());
                        }
                    }

                    return(firstError != null
                        ? getErrorResult()
                        : persistedId);
                }
            }
            catch (IOException ex)
            {
                return(new Failure <string>("Error reading file header", new Failure <Exception>(ex)));
            }
        }