// This test would not pass for the V7 and Ustar formats in some OSs like MacCatalyst, tvOSSimulator and OSX, because the TempDirectory gets created in
        // a folder with a path longer than 100 bytes, and those tar formats have no way of handling pathnames and linknames longer than that length.
        // The rest of the OSs create the TempDirectory in a path that does not surpass the 100 bytes, so the 'subfolder' parameter gives a chance to extend
        // the base directory past that length, to ensure this scenario is tested everywhere.
        private async Task Extract_LinkEntry_TargetInsideDirectory_Internal_Async(TarEntryType entryType, TarEntryFormat format, string subfolder)
        {
            using (TempDirectory root = new TempDirectory())
            {
                string baseDir = string.IsNullOrEmpty(subfolder) ? root.Path : Path.Join(root.Path, subfolder);
                Directory.CreateDirectory(baseDir);

                string linkName   = "link";
                string targetName = "target";
                string targetPath = Path.Join(baseDir, targetName);

                File.Create(targetPath).Dispose();

                await using (MemoryStream archive = new MemoryStream())
                {
                    await using (TarWriter writer = new TarWriter(archive, format, leaveOpen: true))
                    {
                        TarEntry entry = InvokeTarEntryCreationConstructor(format, entryType, linkName);
                        entry.LinkName = targetPath;
                        await writer.WriteEntryAsync(entry);
                    }

                    archive.Seek(0, SeekOrigin.Begin);

                    await TarFile.ExtractToDirectoryAsync(archive, baseDir, overwriteFiles : false);

                    Assert.Equal(2, Directory.GetFileSystemEntries(baseDir).Count());
                }
            }
        }
Exemple #2
0
        // Writes the current header as a GNU entry into the archive stream.
        internal void WriteAsGnuInternal(Stream archiveStream, Span <byte> buffer)
        {
            // Unused GNU fields: offset, longnames, unused, sparse struct, isextended and realsize
            // If this header came from another archive, it will have a value
            // If it was constructed by the user, it will be an empty array
            _gnuUnusedBytes ??= new byte[FieldLengths.AllGnuUnused];

            long         actualLength    = GetTotalDataBytesToWrite();
            TarEntryType actualEntryType = GetCorrectTypeFlagForFormat(TarEntryFormat.Gnu);

            int checksum = WriteName(buffer, out _);

            checksum += WriteCommonFields(buffer, actualLength, actualEntryType);
            checksum += WriteGnuMagicAndVersion(buffer);
            checksum += WritePosixAndGnuSharedFields(buffer);
            checksum += WriteGnuFields(buffer);
            WriteChecksum(checksum, buffer);

            archiveStream.Write(buffer);

            if (_dataStream != null)
            {
                WriteData(archiveStream, _dataStream, actualLength);
            }
        }
Exemple #3
0
        public async Task Write_LongName_And_LongLinkName_Async(TarEntryType entryType)
        {
            // Both the Name and LinkName fields in header only fit 100 bytes
            string longName     = new string('a', 101);
            string longLinkName = new string('a', 101);

            await using (MemoryStream archiveStream = new MemoryStream())
            {
                await using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Gnu, leaveOpen: true))
                {
                    GnuTarEntry entry = new GnuTarEntry(entryType, longName);
                    entry.LinkName = longLinkName;
                    await writer.WriteEntryAsync(entry);
                }

                archiveStream.Position = 0;
                await using (TarReader reader = new TarReader(archiveStream))
                {
                    GnuTarEntry entry = await reader.GetNextEntryAsync() as GnuTarEntry;

                    Assert.Equal(entryType, entry.EntryType);
                    Assert.Equal(longName, entry.Name);
                    Assert.Equal(longLinkName, entry.LinkName);
                }
            }
        }
Exemple #4
0
        // Constructor called when creating a new 'TarEntry*' instance that can be passed to a TarWriter.
        internal TarEntry(TarEntryType entryType, string entryName, TarFormat format)
        {
            ArgumentException.ThrowIfNullOrEmpty(entryName);

            // Throws if format is unknown or out of range
            TarHelpers.VerifyEntryTypeIsSupported(entryType, format, forWriting: false);

            _readerOfOrigin = null;

            _header = default;

            _header._extendedAttributes = new Dictionary <string, string>();

            _header._name     = entryName;
            _header._linkName = string.Empty;
            _header._typeFlag = entryType;
            _header._mode     = (int)TarHelpers.DefaultMode;

            _header._gName = string.Empty;
            _header._uName = string.Empty;

            DateTimeOffset now = DateTimeOffset.Now;

            _header._mTime = now;
            _header._aTime = now;
            _header._cTime = now;
        }
Exemple #5
0
 // Constructor called when the user creates a TarEntry instance from scratch.
 internal PosixTarEntry(TarEntryType entryType, string entryName, TarEntryFormat format, bool isGea)
     : base(entryType, entryName, format, isGea)
 {
     _header._uName    = string.Empty;
     _header._gName    = string.Empty;
     _header._devMajor = 0;
     _header._devMinor = 0;
 }
Exemple #6
0
        /// <summary>
        /// Initializes a new <see cref="PaxTarEntry"/> instance with the specified entry type, entry name, and the default extended attributes.
        /// </summary>
        /// <param name="entryType">The type of the entry.</param>
        /// <param name="entryName">A string with the path and file name of this entry.</param>
        /// <exception cref="ArgumentException"><paramref name="entryName"/> is null or empty.</exception>
        /// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
        /// <remarks><para>When creating an instance using the <see cref="PaxTarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported:</para>
        /// <list type="bullet">
        /// <item>In all platforms: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/>, <see cref="TarEntryType.RegularFile"/>.</item>
        /// <item>In Unix platforms only: <see cref="TarEntryType.BlockDevice"/>, <see cref="TarEntryType.CharacterDevice"/> and <see cref="TarEntryType.Fifo"/>.</item>
        /// </list>
        /// <para>Use the <see cref="PaxTarEntry(TarEntryType, string, IEnumerable{KeyValuePair{string, string}})"/> constructor to include additional extended attributes when creating the entry.</para>
        /// <para>The following entries are always found in the Extended Attributes dictionary of any PAX entry:</para>
        /// <list type="bullet">
        /// <item>Modification time, under the name <c>mtime</c>, as a <see cref="double"/> number.</item>
        /// <item>Access time, under the name <c>atime</c>, as a <see cref="double"/> number.</item>
        /// <item>Change time, under the name <c>ctime</c>, as a <see cref="double"/> number.</item>
        /// <item>Path, under the name <c>path</c>, as a string.</item>
        /// </list>
        /// <para>The following entries are only found in the Extended Attributes dictionary of a PAX entry if certain conditions are met:</para>
        /// <list type="bullet">
        /// <item>Group name, under the name <c>gname</c>, as a string, if it is larger than 32 bytes.</item>
        /// <item>User name, under the name <c>uname</c>, as a string, if it is larger than 32 bytes.</item>
        /// <item>File length, under the name <c>size</c>, as an <see cref="int"/>, if the string representation of the number is larger than 12 bytes.</item>
        /// </list>
        /// </remarks>
        public PaxTarEntry(TarEntryType entryType, string entryName)
            : base(entryType, entryName, TarEntryFormat.Pax, isGea: false)
        {
            _header._prefix = string.Empty;

            Debug.Assert(_header._mTime != default);
            AddNewAccessAndChangeTimestampsIfNotExist(useMTime: true);
        }
Exemple #7
0
 // Constructor called when creating an entry with default common fields.
 internal TarHeader(TarEntryFormat format, string name = "", int mode = 0, DateTimeOffset mTime = default, TarEntryType typeFlag = TarEntryType.RegularFile)
 {
     _format   = format;
     _name     = name;
     _mode     = mode;
     _mTime    = mTime;
     _typeFlag = typeFlag;
     _magic    = GetMagicForFormat(format);
     _version  = GetVersionForFormat(format);
 }
Exemple #8
0
        protected void VerifyCommonRegularFile(TarEntry regularFile, bool isFromWriter, bool isV7RegularFile = false)
        {
            Assert.NotNull(regularFile);
            TarEntryType entryType = isV7RegularFile ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;

            Assert.Equal(entryType, regularFile.EntryType);
            VerifyCommonProperties(regularFile);
            VerifyUnsupportedLinkProperty(regularFile);
            VerifyDataStream(regularFile, isFromWriter);
        }
Exemple #9
0
        public async Task Extract_SpecialFiles_Async(TarEntryFormat format, TarEntryType entryType)
        {
            using TempDirectory root = new TempDirectory();

            (string entryName, string destination, PosixTarEntry entry) = Prepare_Extract_SpecialFiles(root, format, entryType);

            await entry.ExtractToFileAsync(destination, overwrite : true);

            Verify_Extract_SpecialFiles(destination, entry, entryType);
        }
Exemple #10
0
        public void Extract(TarEntryFormat format, TarEntryType entryType)
        {
            using TempDirectory root = new TempDirectory();

            (string entryName, string destination, TarEntry entry) = Prepare_Extract(root, format, entryType);

            entry.ExtractToFile(destination, overwrite: true);

            Verify_Extract(destination, entry, entryType);
        }
Exemple #11
0
 // Constructor called when creating an entry using the common fields from another entry.
 // The *TarEntry constructor calling this should take care of setting any format-specific fields.
 internal TarHeader(TarEntryFormat format, TarEntryType typeFlag, TarHeader other)
     : this(format, other._name, other._mode, other._mTime, typeFlag)
 {
     _uid        = other._uid;
     _gid        = other._gid;
     _size       = other._size;
     _checksum   = other._checksum;
     _linkName   = other._linkName;
     _dataStream = other._dataStream;
 }
Exemple #12
0
        // Creates and returns a GNU long metadata header, with the specified long text written into its data stream.
        private static TarHeader GetGnuLongMetadataHeader(TarEntryType entryType, string longText)
        {
            TarHeader longMetadataHeader = GetDefaultGnuLongMetadataHeader(longText.Length, entryType);

            Debug.Assert(longMetadataHeader._dataStream != null);

            longMetadataHeader._dataStream.Write(Encoding.UTF8.GetBytes(longText));
            longMetadataHeader._dataStream.Seek(0, SeekOrigin.Begin); // Ensure it gets written into the archive from the beginning

            return(longMetadataHeader);
        }
Exemple #13
0
        protected void SetCommonRegularFile(TarEntry regularFile, bool isV7RegularFile = false)
        {
            Assert.NotNull(regularFile);
            TarEntryType entryType = isV7RegularFile ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;

            Assert.Equal(entryType, regularFile.EntryType);
            SetCommonProperties(regularFile);

            // Data stream
            Assert.Null(regularFile.DataStream);
        }
Exemple #14
0
        /// <summary>
        /// Initializes a new <see cref="PaxTarEntry"/> instance with the specified entry type, entry name and Extended Attributes enumeration.
        /// </summary>
        /// <param name="entryType">The type of the entry.</param>
        /// <param name="entryName">A string with the path and file name of this entry.</param>
        /// <param name="extendedAttributes">An enumeration of string key-value pairs that represents the metadata to include in the Extended Attributes entry that precedes the current entry.</param>
        /// <exception cref="ArgumentNullException"><paramref name="extendedAttributes"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException"><paramref name="entryName"/> is null or empty.</exception>
        /// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
        /// <remarks>When creating an instance using the <see cref="PaxTarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported:
        /// <list type="bullet">
        /// <item>In all platforms: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/>, <see cref="TarEntryType.RegularFile"/>.</item>
        /// <item>In Unix platforms only: <see cref="TarEntryType.BlockDevice"/>, <see cref="TarEntryType.CharacterDevice"/> and <see cref="TarEntryType.Fifo"/>.</item>
        /// </list>
        /// The specified <paramref name="extendedAttributes"/> get appended to the default attributes, unless the specified enumeration overrides any of them.
        /// <para>The following entries are always found in the Extended Attributes dictionary of any PAX entry:</para>
        /// <list type="bullet">
        /// <item>Modification time, under the name <c>mtime</c>, as a <see cref="double"/> number.</item>
        /// <item>Access time, under the name <c>atime</c>, as a <see cref="double"/> number.</item>
        /// <item>Change time, under the name <c>ctime</c>, as a <see cref="double"/> number.</item>
        /// <item>Path, under the name <c>path</c>, as a string.</item>
        /// </list>
        /// <para>The following entries are only found in the Extended Attributes dictionary of a PAX entry if certain conditions are met:</para>
        /// <list type="bullet">
        /// <item>Group name, under the name <c>gname</c>, as a string, if it is larger than 32 bytes.</item>
        /// <item>User name, under the name <c>uname</c>, as a string, if it is larger than 32 bytes.</item>
        /// <item>File length, under the name <c>size</c>, as an <see cref="int"/>, if the string representation of the number is larger than 12 bytes.</item>
        /// </list>
        /// </remarks>
        public PaxTarEntry(TarEntryType entryType, string entryName, IEnumerable <KeyValuePair <string, string> > extendedAttributes)
            : base(entryType, entryName, TarEntryFormat.Pax, isGea: false)
        {
            ArgumentNullException.ThrowIfNull(extendedAttributes);

            _header._prefix             = string.Empty;
            _header._extendedAttributes = new Dictionary <string, string>(extendedAttributes);

            Debug.Assert(_header._mTime != default);
            AddNewAccessAndChangeTimestampsIfNotExist(useMTime: true);
        }
Exemple #15
0
        // Writes the V7 header fields to the specified buffer, calculates and writes the checksum, then returns the final data length.
        private long WriteV7FieldsToBuffer(Span <byte> buffer)
        {
            long         actualLength    = GetTotalDataBytesToWrite();
            TarEntryType actualEntryType = TarHelpers.GetCorrectTypeFlagForFormat(TarEntryFormat.V7, _typeFlag);

            int tmpChecksum = WriteName(buffer, out _);

            tmpChecksum += WriteCommonFields(buffer, actualLength, actualEntryType);
            _checksum    = WriteChecksum(tmpChecksum, buffer);

            return(actualLength);
        }
Exemple #16
0
        /// <summary>
        /// Parsing a tar header from the <code>BaseStream</code>.
        /// And set properties to this instance.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="TarHeaderParsingException"></exception>
        private void Parse()
        {
            bool         isCompleted = false;
            TarEntryType currentType = TarEntryType.Incompleted;

            Dump("Start Parsing");
            do
            {
                switch (currentType)
                {
                case TarEntryType.GNU_LongName:
                    Dump("Parsing GNU_LongName");
                    Name        = ParseString(ReadHeader((int)Size), 0, (int)Size);
                    currentType = TarEntryType.Incompleted;
                    break;

                case TarEntryType.GNU_LongLink:
                    Dump("Parsing GNU_LongLink");
                    LinkName    = ParseString(ReadHeader((int)Size), 0, (int)Size);
                    currentType = TarEntryType.Incompleted;
                    break;

                case TarEntryType.Incompleted:
                    currentType = ParseStandardHeader();
                    break;
                }

                switch (currentType)
                {
                case TarEntryType.Incompleted:
                case TarEntryType.GNU_LongName:
                case TarEntryType.GNU_LongLink:
                    isCompleted = false;
                    break;

                case TarEntryType.Unkown:
                    throw new TarHeaderParsingException(
                              string.Format("Unkown tar header type: {0}", Type));

                case TarEntryType.EndOfEntry:
                    Type        = currentType;
                    isCompleted = true;
                    return;

                default:
                    isCompleted = true;
                    break;
                }
            } while (!isCompleted);
            Dump("End Parsing");
            Dump(ToString());
        }
Exemple #17
0
        private TarEntry GetFirstEntry(MemoryStream dataStream, TarEntryType entryType, TarEntryFormat format)
        {
            TarEntry firstEntry = InvokeTarEntryCreationConstructor(format, entryType, "file.txt");

            firstEntry.Gid  = TestGid;
            firstEntry.Uid  = TestUid;
            firstEntry.Mode = TestMode;
            // Modification Time is set to 'DateTimeOffset.UtcNow' in the constructor

            if (entryType is TarEntryType.V7RegularFile or TarEntryType.RegularFile)
            {
                firstEntry.DataStream = dataStream;
            }
Exemple #18
0
        /// <summary>
        /// Read the next entry in the tar file.
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns>the data for the entry.  Returns null if there are no more entries</returns>
        public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
        {
            filePath = String.Empty;
            entryType = TarEntryType.TYPE_UNKNOWN;
            TarHeader header = ReadHeader();

            if (null == header)
                return null;

            entryType = header.EntryType;
            filePath = header.FilePath;
            return ReadData(header.FileSize);
        }
Exemple #19
0
        // Writes the Ustar header fields to the specified buffer, calculates and writes the checksum, then returns the final data length.
        private long WriteUstarFieldsToBuffer(Span <byte> buffer)
        {
            long         actualLength    = GetTotalDataBytesToWrite();
            TarEntryType actualEntryType = TarHelpers.GetCorrectTypeFlagForFormat(TarEntryFormat.Ustar, _typeFlag);

            int tmpChecksum = WritePosixName(buffer);

            tmpChecksum += WriteCommonFields(buffer, actualLength, actualEntryType);
            tmpChecksum += WritePosixMagicAndVersion(buffer);
            tmpChecksum += WritePosixAndGnuSharedFields(buffer);
            _checksum    = WriteChecksum(tmpChecksum, buffer);

            return(actualLength);
        }
        public void Read_Archive_Many_Small_Files(TarFormat format, TestTarFormat testFormat)
        {
            string testCaseName = "many_small_files";

            using MemoryStream ms = GetTarMemoryStream(CompressionMethod.Uncompressed, testFormat, testCaseName);

            using TarReader reader = new TarReader(ms);
            if (testFormat == TestTarFormat.pax_gea)
            {
                // The GEA are collected after reading the first entry, not on the constructor
                Assert.Null(reader.GlobalExtendedAttributes);
            }

            // Format is determined after reading the first entry, not on the constructor
            Assert.Equal(TarFormat.Unknown, reader.Format);

            List <TarEntry> entries = new List <TarEntry>();
            TarEntry        entry;
            bool            isFirstEntry = true;

            while ((entry = reader.GetNextEntry()) != null)
            {
                if (isFirstEntry)
                {
                    Assert.Equal(format, reader.Format);
                    if (testFormat == TestTarFormat.pax_gea)
                    {
                        Assert.NotNull(reader.GlobalExtendedAttributes);
                        Assert.True(reader.GlobalExtendedAttributes.Any());
                        Assert.Contains(AssetPaxGeaKey, reader.GlobalExtendedAttributes);
                        Assert.Equal(AssetPaxGeaValue, reader.GlobalExtendedAttributes[AssetPaxGeaKey]);
                    }

                    isFirstEntry = false;
                }
                entries.Add(entry);
            }

            int directoriesCount = entries.Count(e => e.EntryType == TarEntryType.Directory);

            Assert.Equal(10, directoriesCount);

            TarEntryType regularFileEntryType = format == TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;

            for (int i = 0; i < 10; i++)
            {
                int filesCount = entries.Count(e => e.EntryType == regularFileEntryType && e.Name.StartsWith($"{i}/"));
                Assert.Equal(10, filesCount);
            }
        }
Exemple #21
0
        // Asynchronously creates and returns a GNU long metadata header, with the specified long text written into its data stream.
        private static async Task <TarHeader> GetGnuLongMetadataHeaderAsync(TarEntryType entryType, string longText, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            TarHeader longMetadataHeader = GetDefaultGnuLongMetadataHeader(longText.Length, entryType);

            Debug.Assert(longMetadataHeader._dataStream != null);

            await longMetadataHeader._dataStream.WriteAsync(Encoding.UTF8.GetBytes(longText), cancellationToken).ConfigureAwait(false);

            longMetadataHeader._dataStream.Seek(0, SeekOrigin.Begin); // Ensure it gets written into the archive from the beginning

            return(longMetadataHeader);
        }
Exemple #22
0
        // Constructor called when the user creates a TarEntry instance from scratch.
        internal TarEntry(TarEntryType entryType, string entryName, TarEntryFormat format, bool isGea)
        {
            ArgumentException.ThrowIfNullOrEmpty(entryName);

            Debug.Assert(!isGea || entryType is TarEntryType.GlobalExtendedAttributes);

            if (!isGea)
            {
                TarHelpers.ThrowIfEntryTypeNotSupported(entryType, format);
            }

            // Default values for fields shared by all supported formats
            _header = new TarHeader(format, entryName, TarHelpers.GetDefaultMode(entryType), DateTimeOffset.UtcNow, entryType);
        }
Exemple #23
0
        protected void TestConstructionConversion(
            TarEntryType originalEntryType,
            TarEntryFormat firstFormat,
            TarEntryFormat formatToConvert)
        {
            DateTimeOffset now = DateTimeOffset.UtcNow;

            using MemoryStream dataStream = new MemoryStream();

            TarEntryType actualEntryType = GetTarEntryTypeForTarEntryFormat(originalEntryType, firstFormat);

            TarEntry firstEntry = GetFirstEntry(dataStream, actualEntryType, firstFormat);
            TarEntry otherEntry = ConvertAndVerifyEntry(firstEntry, originalEntryType, formatToConvert, now);
        }
Exemple #24
0
        // Constructor called when converting an entry to the selected format.
        internal TarEntry(TarEntry other, TarEntryFormat format)
        {
            if (other is PaxGlobalExtendedAttributesTarEntry)
            {
                throw new InvalidOperationException(SR.TarCannotConvertPaxGlobalExtendedAttributesEntry);
            }

            TarEntryType compatibleEntryType = TarHelpers.GetCorrectTypeFlagForFormat(format, other.EntryType);

            TarHelpers.ThrowIfEntryTypeNotSupported(compatibleEntryType, format);

            _readerOfOrigin = other._readerOfOrigin;

            _header = new TarHeader(format, compatibleEntryType, other._header);
        }
        /// <summary>
        /// Read the next entry in the tar file.
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns>the data for the entry.  Returns null if there are no more entries</returns>
        public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
        {
            filePath  = String.Empty;
            entryType = TarEntryType.TYPE_UNKNOWN;
            TarHeader header = ReadHeader();

            if (null == header)
            {
                return(null);
            }

            entryType = header.EntryType;
            filePath  = header.FilePath;
            return(ReadData(header.FileSize));
        }
Exemple #26
0
        private TarEntryType ParseStandardHeader()
        {
            var type = TarEntryType.Incompleted;

            var buffer = ReadHeader();

            if (buffer[0] == 0) // reached end of tar data.
            {
                Dump("this block is the end of tar data.");
                return(TarEntryType.EndOfEntry);
            }
            var offset = 0;

            if (!Type.HasFlag(TarEntryType.GNU_LongName))
            {
                Name = ParseString(buffer, offset, NAME_LENGTH);
            }
            offset    += NAME_LENGTH;
            Permission = (int)ParseOctet(buffer, offset, MODE_LENGTH);
            offset    += MODE_LENGTH;
            Uid        = (int)ParseOctet(buffer, offset, UID_LENGTH);
            offset    += UID_LENGTH;
            Gid        = (int)ParseOctet(buffer, offset, GID_LENGTH);
            offset    += GID_LENGTH;
            Size       = ParseOctet(buffer, offset, SIZE_LENGTH);
            offset    += SIZE_LENGTH;
            Mtime      = Epoch2Date(ParseOctet(buffer, offset, MTIME_ELNGTH));
            offset    += MTIME_ELNGTH;
            Checksum   = (int)ParseOctet(buffer, offset, CHECKSUM_LENGTH);
            offset    += CHECKSUM_LENGTH;
            type       = GetEntryType(buffer[offset++]);
            Type      |= type;
            if (!Type.HasFlag(TarEntryType.GNU_LongLink))
            {
                LinkName = ParseString(buffer, offset, LINKNAME_LENGTH);
            }
            offset += LINKNAME_LENGTH;
            Magic   = ParseString(buffer, offset, MAGIC_LENGTH).Trim();
            offset += MAGIC_LENGTH;
            Version = ParseString(buffer, offset, VERSION_LENGTH);
            offset += VERSION_LENGTH;
            Uname   = ParseString(buffer, offset, UNAME_LENGTH);
            offset += UNAME_LENGTH;
            Gname   = ParseString(buffer, offset, GNAME_LENGTH);
            offset += GNAME_LENGTH;

            return(type);
        }
Exemple #27
0
        public void ExtractToFile_Link_Throws(TarEntryType entryType)
        {
            using TempDirectory root = new TempDirectory();
            string fileName = "mylink";
            string fullPath = Path.Join(root.Path, fileName);

            string linkTarget = PlatformDetection.IsWindows ? @"C:\Windows\system32\notepad.exe" : "/usr/bin/nano";

            UstarTarEntry entry = new UstarTarEntry(entryType, fileName);

            entry.LinkName = linkTarget;

            Assert.Throws <InvalidOperationException>(() => entry.ExtractToFile(fileName, overwrite: false));

            Assert.Equal(0, Directory.GetFileSystemEntries(root.Path).Count());
        }
Exemple #28
0
        protected void TestConstructionConversionBackAndForth(
            TarEntryType originalEntryType,
            TarEntryFormat firstAndLastFormat,
            TarEntryFormat formatToConvert)
        {
            DateTimeOffset now = DateTimeOffset.UtcNow;

            using MemoryStream dataStream = new MemoryStream();

            TarEntryType firstAndLastEntryType = GetTarEntryTypeForTarEntryFormat(originalEntryType, firstAndLastFormat);

            TarEntry       firstEntry = GetFirstEntry(dataStream, firstAndLastEntryType, firstAndLastFormat);
            TarEntry       otherEntry = ConvertAndVerifyEntry(firstEntry, originalEntryType, formatToConvert, now); // First conversion
            DateTimeOffset secondNow  = DateTimeOffset.UtcNow;

            ConvertAndVerifyEntry(otherEntry, firstAndLastEntryType, firstAndLastFormat, secondNow); // Convert back to original format
        }
        private void Verify_Archive_RegularFile(TarEntry file, TarFormat format, IReadOnlyDictionary <string, string> gea, string expectedFileName, string expectedContents)
        {
            Assert.NotNull(file);

            Assert.True(file.Checksum > 0);
            Assert.NotNull(file.DataStream);
            Assert.True(file.DataStream.Length > 0);
            Assert.True(file.DataStream.CanRead);
            Assert.True(file.DataStream.CanSeek);
            file.DataStream.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(file.DataStream, leaveOpen: true))
            {
                string contents = reader.ReadLine();
                Assert.Equal(expectedContents, contents);
            }

            TarEntryType expectedEntryType = format == TarFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;

            Assert.Equal(expectedEntryType, file.EntryType);

            Assert.Equal(AssetGid, file.Gid);
            Assert.Equal(file.Length, file.DataStream.Length);
            Assert.Equal(DefaultLinkName, file.LinkName);
            Assert.Equal(AssetMode, file.Mode);
            Assert.True(file.ModificationTime > DateTimeOffset.UnixEpoch);
            Assert.Equal(expectedFileName, file.Name);
            Assert.Equal(AssetUid, file.Uid);

            if (file is PosixTarEntry posix)
            {
                Assert.Equal(DefaultDeviceMajor, posix.DeviceMajor);
                Assert.Equal(DefaultDeviceMinor, posix.DeviceMinor);
                Assert.Equal(AssetGName, posix.GroupName);
                Assert.Equal(AssetUName, posix.UserName);

                if (posix is PaxTarEntry pax)
                {
                    VerifyAssetExtendedAttributes(pax, gea);
                }
                else if (posix is GnuTarEntry gnu)
                {
                    Assert.True(gnu.AccessTime >= DateTimeOffset.UnixEpoch);
                    Assert.True(gnu.ChangeTime >= DateTimeOffset.UnixEpoch);
                }
            }
        }
Exemple #30
0
        public async Task Add_File_Async(TarEntryFormat format)
        {
            using (TempDirectory root = new TempDirectory())
            {
                string fileName     = "file.txt";
                string filePath     = Path.Join(root.Path, fileName);
                string fileContents = "Hello world";

                using (StreamWriter streamWriter = File.CreateText(filePath))
                {
                    streamWriter.Write(fileContents);
                }

                await using (MemoryStream archive = new MemoryStream())
                {
                    await using (TarWriter writer = new TarWriter(archive, format, leaveOpen: true))
                    {
                        await writer.WriteEntryAsync(fileName : filePath, entryName : fileName);
                    }

                    archive.Seek(0, SeekOrigin.Begin);
                    await using (TarReader reader = new TarReader(archive))
                    {
                        TarEntry entry = await reader.GetNextEntryAsync();

                        Assert.NotNull(entry);
                        Assert.Equal(format, entry.Format);
                        Assert.Equal(fileName, entry.Name);
                        TarEntryType expectedEntryType = format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile;
                        Assert.Equal(expectedEntryType, entry.EntryType);
                        Assert.True(entry.Length > 0);
                        Assert.NotNull(entry.DataStream);

                        entry.DataStream.Seek(0, SeekOrigin.Begin);
                        using StreamReader dataReader = new StreamReader(entry.DataStream);
                        string dataContents = dataReader.ReadLine();

                        Assert.Equal(fileContents, dataContents);

                        VerifyPlatformSpecificMetadata(filePath, entry);

                        Assert.Null(await reader.GetNextEntryAsync());
                    }
                }
            }
        }
        public async Task ExtractToFile_Link_Throws_Async(TarEntryFormat format, TarEntryType entryType)
        {
            using (TempDirectory root = new TempDirectory())
            {
                string fileName = "mylink";
                string fullPath = Path.Join(root.Path, fileName);

                string linkTarget = PlatformDetection.IsWindows ? @"C:\Windows\system32\notepad.exe" : "/usr/bin/nano";

                TarEntry entry = InvokeTarEntryCreationConstructor(format, entryType, fileName);
                entry.LinkName = linkTarget;

                await Assert.ThrowsAsync <InvalidOperationException>(() => entry.ExtractToFileAsync(fileName, overwrite: false));

                Assert.Equal(0, Directory.GetFileSystemEntries(root.Path).Count());
            }
        }