Beispiel #1
0
        public async Task CreateEntryAsync(TarEntry entry)
        {
            ValidateWroteAll();

            var paxAttributes = new Dictionary <string, string>();

            // Clear padding.
            for (int i = 0; i < TarCommon.BlockSize; i++)
            {
                _buffer[i] = 0;
            }

            var state   = new TarHeaderView(_buffer, TarCommon.BlockSize, paxAttributes);
            var padding = _remainingPadding;

            _remainingPadding = 0;

            GenerateHeader(ref state, entry, default(ArraySegment <byte>));

            if (paxAttributes.Count > 0)
            {
                padding = await WritePaxEntry(entry, paxAttributes, padding);
            }

            await _stream.WriteAsync(_buffer, TarCommon.BlockSize - padding, TarCommon.BlockSize + padding);

            _remaining        = entry.Length;
            _remainingPadding = TarCommon.Padding(_remaining);
        }
Beispiel #2
0
        private async Task <int> WritePaxEntry(TarEntry entry, Dictionary <string, string> paxAttributes, int padding)
        {
            var paxStream = new MemoryStream();

            // Skip the tar header, then go back and write it later.
            var paxDataOffset = padding + TarCommon.BlockSize;

            paxStream.SetLength(paxDataOffset);
            paxStream.Position = paxDataOffset;

            foreach (var attribute in paxAttributes)
            {
                WritePaxAttribute(paxStream, attribute.Key, attribute.Value);
            }

            var paxEntry = new TarEntry
            {
                Type   = TarCommon.PaxHeaderType,
                Length = paxStream.Length - paxDataOffset,
            };

            ArraySegment <byte> buffer;

            paxStream.TryGetBuffer(out buffer);

            var paxHeader = new TarHeaderView(buffer.Array, buffer.Offset + padding, null);

            GenerateHeader(ref paxHeader, paxEntry, GetPaxName(entry.Name));

            paxStream.Position = 0;
            await paxStream.CopyToAsync(_stream);

            return(TarCommon.Padding(paxEntry.Length));
        }
        public bool TryPutString(string str, TarHeader.HeaderField field)
        {
            if (str == null)
            {
                PutNul(field);
                return(true);
            }

            if (TarCommon.IsASCII(str))
            {
                if (str.Length <= field.Length)
                {
                    for (int i = 0; i < str.Length; i++)
                    {
                        this[field.Offset + i] = (byte)str[i];
                    }

                    PutNul(field.Offset + str.Length, field.Length - str.Length);
                    return(true);
                }
            }

            if (field.PaxAttribute != null && PaxAttributes != null)
            {
                PaxAttributes[field.PaxAttribute] = str;
            }

            PutNul(field);
            return(false);
        }
Beispiel #4
0
        private async Task <TarEntry> ReadHeader(Dictionary <string, string> paxAttributes)
        {
            if (_remaining > 0)
            {
                await Skip(_remaining);

                _remaining = 0;
            }

            var read = await _stream.ReadAsync(_buffer, 0, TarCommon.BlockSize + _remainingPadding);

            var padding = _remainingPadding;

            _remainingPadding = 0;
            if (read <= _remainingPadding)
            {
                // No more entries.
                return(null);
            }
            else if (read - _remainingPadding < TarCommon.BlockSize)
            {
                throw new EndOfStreamException();
            }

            if (IsArrayZero(padding, TarCommon.BlockSize))
            {
                // Verify that the next block is also zero.
                read = await _stream.ReadAsync(_buffer, 0, TarCommon.BlockSize);

                if (read == 0)
                {
                    return(null);
                }
                else if (read < TarCommon.BlockSize)
                {
                    throw new EndOfStreamException();
                }
                else if (IsArrayZero(0, TarCommon.BlockSize))
                {
                    return(null);
                }
                else
                {
                    throw new TarParseException("non-zero header after zero header");
                }
            }

            var header = new TarHeaderView(_buffer, padding, paxAttributes);
            var entry  = ParseHeader(ref header);

            _remaining        = entry.Length;
            _remainingPadding = TarCommon.Padding(_remaining);
            return(entry);
        }
Beispiel #5
0
        // Tries to split a path at a '/' character so that the two pieces will fit into
        // the prefix and name fields.
        private static bool TrySplitPath(string path, out int splitIndex)
        {
            splitIndex = -1;
            if (!TarCommon.IsASCII(path))
            {
                return(false);
            }

            for (int i = 0; i < path.Length; i++)
            {
                if (path[i] == '/')
                {
                    if (i < TarHeader.Prefix.Length && path.Length - i - 1 < TarHeader.Name.Length)
                    {
                        splitIndex = i;
                        return(true);
                    }
                }
            }

            return(false);
        }
Beispiel #6
0
        private static TarEntry ParseHeader(ref TarHeaderView header)
        {
            var entry = new TarEntry
            {
                Name         = header.GetString(TarHeader.Name),
                Mode         = header.GetOctal(TarHeader.Mode),
                UserID       = header.GetOctal(TarHeader.UserID),
                GroupID      = header.GetOctal(TarHeader.GroupID),
                Length       = header.GetOctalLong(TarHeader.Length),
                ModifiedTime = header.GetTime(TarHeader.ModifiedTime)
            };

            var checksum = header.GetOctal(TarHeader.Checksum);
            int signedChecksum;
            var unsignedChecksum = TarCommon.Checksum(header.Field(TarHeader.FullHeader), out signedChecksum);

            if (checksum != signedChecksum && checksum != unsignedChecksum)
            {
                throw new TarParseException("invalid tar checksum");
            }

            var typeFlag = header[TarHeader.TypeFlag.Offset];

            if (typeFlag == 0)
            {
                typeFlag = (byte)'0';
            }

            entry.Type = (TarEntryType)typeFlag;

            entry.LinkTarget = header.GetString(TarHeader.LinkTarget);
            var magic = header.GetString(TarHeader.FullMagic);

            if (magic == TarCommon.PosixMagic || magic == TarCommon.GnuMagic)
            {
                entry.UserName    = header.GetString(TarHeader.UserName);
                entry.GroupName   = header.GetString(TarHeader.GroupName);
                entry.DeviceMajor = header.GetOctal(TarHeader.DeviceMajor);
                entry.DeviceMinor = header.GetOctal(TarHeader.DeviceMinor);
                if (magic == TarCommon.PosixMagic)
                {
                    if (header.PaxAttributes == null || !header.PaxAttributes.ContainsKey(TarHeader.Name.PaxAttribute))
                    {
                        var prefix = header.GetString(TarHeader.Prefix);
                        if (prefix.Length > 0)
                        {
                            entry.Name = prefix + "/" + entry.Name;
                        }
                    }

                    string atime = header.GetPaxValue(TarCommon.PaxAtime);
                    if (atime != null)
                    {
                        entry.AccessTime = TarTime.FromPaxTime(atime);
                    }

                    string ctime = header.GetPaxValue(TarCommon.PaxCtime);
                    if (ctime != null)
                    {
                        entry.ChangeTime = TarTime.FromPaxTime(ctime);
                    }

                    string creationtime = header.GetPaxValue(TarCommon.PaxCreationTime);
                    if (creationtime != null)
                    {
                        entry.CreationTime = TarTime.FromPaxTime(creationtime);
                    }

                    string fileAttributes = header.GetPaxValue(TarCommon.PaxWindowsFileAttributes);
                    if (fileAttributes != null)
                    {
                        entry.FileAttributes = (FileAttributes)Convert.ToUInt32(fileAttributes);
                    }

                    entry.SecurityDescriptor = header.GetPaxValue(TarCommon.PaxWindowsSecurityDescriptor);
                    if (header.GetPaxValue(TarCommon.PaxWindowsMountPoint) != null)
                    {
                        entry.IsMountPoint = true;
                    }
                }
            }

            return(entry);
        }
Beispiel #7
0
        private static void GenerateHeader(ref TarHeaderView header, TarEntry entry, ArraySegment <byte> name)
        {
            var needsPath = false;

            header.PutNul(TarHeader.FullHeader);

            // Try to write the name, but don't write the PAX attribute yet in case we can
            // just write a split name later.
            if (name.Count > 0)
            {
                header.PutBytes(name, TarHeader.Name);
            }
            else if (!header.TryPutString(entry.Name, TarHeader.Name.WithoutPax))
            {
                needsPath = true;
            }

            header.TryPutOctal(entry.Mode, TarHeader.Mode);
            header.TryPutOctal(entry.UserID, TarHeader.UserID);
            header.TryPutOctal(entry.GroupID, TarHeader.GroupID);
            header.TryPutOctal(entry.Length, TarHeader.Length);
            header.TryPutTime(entry.ModifiedTime, TarHeader.ModifiedTime);

            header[TarHeader.ChecksumSpace.Offset] = (byte)' ';

            header[TarHeader.TypeFlag.Offset] = (byte)entry.Type;

            header.TryPutString(entry.LinkTarget, TarHeader.LinkTarget);

            header.TryPutString(TarCommon.PosixMagic, TarHeader.Magic);
            header[TarHeader.Version.Offset]     = (byte)'0';
            header[TarHeader.Version.Offset + 1] = (byte)'0';

            header.TryPutString(entry.UserName, TarHeader.UserName);
            header.TryPutString(entry.GroupName, TarHeader.GroupName);
            header.TryPutOctal(entry.DeviceMajor, TarHeader.DeviceMajor);
            header.TryPutOctal(entry.DeviceMinor, TarHeader.DeviceMinor);

            if (header.PaxAttributes != null)
            {
                if (entry.AccessTime.HasValue)
                {
                    header.PaxAttributes[TarCommon.PaxAtime] = TarTime.ToPaxTime(entry.AccessTime.Value);
                }

                if (entry.ChangeTime.HasValue)
                {
                    header.PaxAttributes[TarCommon.PaxCtime] = TarTime.ToPaxTime(entry.ChangeTime.Value);
                }

                if (entry.CreationTime.HasValue)
                {
                    header.PaxAttributes[TarCommon.PaxCreationTime] = TarTime.ToPaxTime(entry.CreationTime.Value);
                }

                if (entry.FileAttributes.HasValue)
                {
                    header.PaxAttributes[TarCommon.PaxWindowsFileAttributes] = Convert.ToString((uint)entry.FileAttributes.Value);
                }

                if (entry.IsMountPoint)
                {
                    header.PaxAttributes[TarCommon.PaxWindowsMountPoint] = "1";
                }

                if (entry.SecurityDescriptor != null)
                {
                    header.PaxAttributes[TarCommon.PaxWindowsSecurityDescriptor] = entry.SecurityDescriptor;
                }

                if (needsPath)
                {
                    int splitIndex;
                    if (header.PaxAttributes.Count == 0 && TrySplitPath(entry.Name, out splitIndex))
                    {
                        header.TryPutString(entry.Name.Substring(0, splitIndex), TarHeader.Prefix);
                        header.TryPutString(entry.Name.Substring(splitIndex + 1), TarHeader.Name);
                    }
                    else
                    {
                        header.PaxAttributes[TarHeader.Name.PaxAttribute] = entry.Name;
                    }
                }
            }

            int signedChecksum;
            var checksum = TarCommon.Checksum(header.Field(TarHeader.FullHeader), out signedChecksum);

            header.TryPutOctal(checksum, TarHeader.Checksum);
        }