Ejemplo n.º 1
0
        /// <summary>
        /// Put an entry on the output stream. This writes the entry's
        /// header and positions the output stream for writing
        /// the contents of the entry. Once this method is called, the
        /// stream is ready for calls to write() to write the entry's
        /// contents. Once the contents are written, closeEntry()
        /// <B>MUST</B> be called to ensure that all buffered data
        /// is completely written to the output stream.
        /// </summary>
        /// <param name="entry">
        /// The TarEntry to be written to the archive.
        /// </param>
        public void PutNextEntry(TarEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN)
            {
                var longHeader = new TarHeader{TypeFlag = TarHeader.LF_GNU_LONGNAME};
                longHeader.Name = longHeader.Name + "././@LongLink";
                longHeader.UserId = 0;
                longHeader.GroupId = 0;
                longHeader.GroupName = String.Empty;
                longHeader.UserName = String.Empty;
                longHeader.LinkName = String.Empty;

                longHeader.Size = entry.TarHeader.Name.Length;

                longHeader.WriteHeader(blockBuffer);
                _buffer.WriteBlock(blockBuffer); // Add special long filename header block

                var nameCharIndex = 0;

                while (nameCharIndex < entry.TarHeader.Name.Length)
                {
                    Array.Clear(blockBuffer, 0, blockBuffer.Length);
                    TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, blockBuffer, 0, TarBuffer.BlockSize);
                    nameCharIndex += TarBuffer.BlockSize;
                    _buffer.WriteBlock(blockBuffer);
                }
            }

            entry.WriteEntryHeader(blockBuffer);
            _buffer.WriteBlock(blockBuffer);

            currBytes = 0;

            currSize = entry.IsDirectory ? 0 : entry.Size;
        }
Ejemplo n.º 2
0
		void EntryCounter(TarArchive archive, TarEntry entry, string message)
		{
			entryCount++;
		}
Ejemplo n.º 3
0
		public void CloningAndUniqueness()
		{
			// Partial test of cloning for TarHeader and TarEntry
			TarEntry e = TarEntry.CreateTarEntry("ohsogood");
			e.GroupId = 47;
			e.GroupName = "GroupName";
			e.ModTime = DateTime.Now;
			e.Size = 123234;

			TarHeader headerE = e.TarHeader;

			headerE.DevMajor = 99;
			headerE.DevMinor = 98;
			headerE.LinkName = "LanceLink";

			TarEntry d = (TarEntry)e.Clone();

			Assert.AreEqual(d.File, e.File);
			Assert.AreEqual(d.GroupId, e.GroupId);
			Assert.AreEqual(d.GroupName, e.GroupName);
			Assert.AreEqual(d.IsDirectory, e.IsDirectory);
			Assert.AreEqual(d.ModTime, e.ModTime);
			Assert.AreEqual(d.Size, e.Size);

			TarHeader headerD = d.TarHeader;

			Assert.AreEqual(headerE.Checksum, headerD.Checksum);
			Assert.AreEqual(headerE.LinkName, headerD.LinkName);

			Assert.AreEqual(99, headerD.DevMajor);
			Assert.AreEqual(98, headerD.DevMinor);

			Assert.AreEqual("LanceLink", headerD.LinkName);

			TarEntry entryf = new TarEntry(headerD);

			headerD.LinkName = "Something different";

			Assert.AreNotEqual(headerD.LinkName, entryf.TarHeader.LinkName, "Entry headers should be unique");
		}
Ejemplo n.º 4
0
        /// <summary>
        /// Write an entry to the archive. This method will call the putNextEntry
        /// and then write the contents of the entry, and finally call closeEntry()
        /// for entries that are files. For directories, it will call putNextEntry(),
        /// and then, if the recurse flag is true, process each entry that is a
        /// child of the directory.
        /// </summary>
        /// <param name="sourceEntry">
        /// The TarEntry representing the entry to write to the archive.
        /// </param>
        /// <param name="recurse">
        /// If true, process the children of directory entries.
        /// </param>
        private void InternalWriteEntry(TarEntry sourceEntry, bool recurse)
        {
            string tempFileName = null;
            var entryFilename = sourceEntry.File;

            var entry = (TarEntry) sourceEntry.Clone();

            if (_applyUserInfoOverrides)
            {
                entry.GroupId = _groupId;
                entry.GroupName = _groupName;
                entry.UserId = _userId;
                entry.UserName = _userName;
            }

            OnProgressMessageEvent(entry, null);

            if (_asciiTranslate && !entry.IsDirectory)
            {
                var asciiTrans = !IsBinary(entryFilename);

                if (asciiTrans)
                {
                    tempFileName = Path.GetTempFileName();

                    using (var inStream = File.OpenText(entryFilename))
                    {
                        using (Stream outStream = File.Create(tempFileName))
                        {
                            while (true)
                            {
                                var line = inStream.ReadLine();
                                if (line == null)
                                {
                                    break;
                                }
                                var data = Encoding.UTF8.GetBytes(line);
                                outStream.Write(data, 0, data.Length);
                                outStream.WriteByte((byte) '\n');
                            }

                            outStream.Flush();
                        }
                    }

                    entry.Size = new FileInfo(tempFileName).Length;
                    entryFilename = tempFileName;
                }
            }

            string newName = null;

            if (rootPath != null)
            {
                if (entry.Name.StartsWith(rootPath))
                {
                    newName = entry.Name.Substring(rootPath.Length + 1);
                }
            }

            if (pathPrefix != null)
            {
                newName = (newName == null) ? string.Format("{0}/{1}", pathPrefix, entry.Name) : pathPrefix + "/" + newName;
            }

            if (newName != null)
            {
                entry.Name = newName;
            }

            tarOut.PutNextEntry(entry);

            if (entry.IsDirectory)
            {
                if (recurse)
                {
                    var list = entry.GetDirectoryEntries();
                    for (var i = 0; i < list.Length; ++i)
                    {
                        InternalWriteEntry(list[i], recurse);
                    }
                }
            }
            else
            {
                using (Stream inputStream = File.OpenRead(entryFilename))
                {
                    var localBuffer = new byte[32*1024];
                    while (true)
                    {
                        var numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);

                        if (numRead <= 0)
                        {
                            break;
                        }

                        tarOut.Write(localBuffer, 0, numRead);
                    }
                }

                if (!string.IsNullOrEmpty(tempFileName))
                {
                    File.Delete(tempFileName);
                }

                tarOut.CloseEntry();
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Get the next entry in this tar archive. This will skip
        /// over any remaining data in the current entry, if there
        /// is one, and place the input stream at the header of the
        /// next entry, and read the header and instantiate a new
        /// TarEntry from the header bytes and return that entry.
        /// If there are no more entries in the archive, null will
        /// be returned to indicate that the end of the archive has
        /// been reached.
        /// </summary>
        /// <returns>
        /// The next TarEntry in the archive, or null.
        /// </returns>
        public TarEntry GetNextEntry()
        {
            if (hasHitEOF)
            {
                return null;
            }

            if (currentEntry != null)
            {
                SkipToNextEntry();
            }

            var headerBuf = _buffer.ReadBlock();

            if (headerBuf == null)
            {
                hasHitEOF = true;
            }
            else if (_buffer.IsEOFBlock(headerBuf))
            {
                hasHitEOF = true;
            }

            if (hasHitEOF)
            {
                currentEntry = null;
            }
            else
            {
                try
                {
                    var header = new TarHeader();
                    header.ParseBuffer(headerBuf);
                    if (!header.IsChecksumValid)
                    {
                        throw new TarException("Header checksum is invalid");
                    }
                    entryOffset = 0;
                    entrySize = header.Size;

                    StringBuilder longName = null;

                    if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME)
                    {
                        var nameBuffer = new byte[TarBuffer.BlockSize];
                        var numToRead = entrySize;

                        longName = new StringBuilder();

                        while (numToRead > 0)
                        {
                            var numRead = Read(nameBuffer, 0,
                                               (numToRead > nameBuffer.Length ? nameBuffer.Length : (int) numToRead));

                            if (numRead == -1)
                            {
                                throw new InvalidHeaderException("Failed to read long name entry");
                            }

                            longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
                            numToRead -= numRead;
                        }

                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GHDR)
                    {
                        // POSIX global extended header 
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_XHDR)
                    {
                        // POSIX extended header
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR)
                    {
                        // TODO: could show volume name when verbose
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag != TarHeader.LF_NORMAL &&
                             header.TypeFlag != TarHeader.LF_OLDNORM &&
                             header.TypeFlag != TarHeader.LF_DIR)
                    {
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }

                    if (entryFactory == null)
                    {
                        currentEntry = new TarEntry(headerBuf);
                        if (longName != null)
                        {
                            currentEntry.Name = longName.ToString();
                        }
                    }
                    else
                    {
                        currentEntry = entryFactory.CreateEntry(headerBuf);
                    }

                    // Magic was checked here for 'ustar' but there are multiple valid possibilities
                    // so this is not done anymore.

                    entryOffset = 0;

                    // TODO: Review How do we resolve this discrepancy?!
                    entrySize = currentEntry.Size;
                }
                catch (InvalidHeaderException ex)
                {
                    entrySize = 0;
                    entryOffset = 0;
                    currentEntry = null;
                    var errorText = string.Format("Bad header in record {0} block {1} {2}",
                                                  _buffer.CurrentRecord, _buffer.CurrentBlock, ex.Message);
                    throw new InvalidHeaderException(errorText);
                }
            }
            return currentEntry;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Extract an entry from the archive. This method assumes that the
        /// tarIn stream has been properly set with a call to GetNextEntry().
        /// </summary>
        /// <param name="destDir">
        /// The destination directory into which to extract.
        /// </param>
        /// <param name="entry">
        /// The TarEntry returned by tarIn.GetNextEntry().
        /// </param>
        private void ExtractEntry(string destDir, TarEntry entry)
        {
            OnProgressMessageEvent(entry, null);

            var name = entry.Name;

            if (Path.IsPathRooted(name))
            {
                // NOTE:
                // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
                name = name.Substring(Path.GetPathRoot(name).Length);
            }

            name = name.Replace('/', Path.DirectorySeparatorChar);

            var destFile = Path.Combine(destDir, name);

            if (entry.IsDirectory)
            {
                EnsureDirectoryExists(destFile);
            }
            else
            {
                var parentDirectory = Path.GetDirectoryName(destFile);
                EnsureDirectoryExists(parentDirectory);

                var process = true;
                var fileInfo = new FileInfo(destFile);
                if (fileInfo.Exists)
                {
                    if (_keepOldFiles)
                    {
                        OnProgressMessageEvent(entry, "Destination file already exists");
                        process = false;
                    }
                    else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0)
                    {
                        OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
                        process = false;
                    }
                }

                if (process)
                {
                    var asciiTrans = false;

                    Stream outputStream = File.Create(destFile);
                    if (_asciiTranslate)
                    {
                        asciiTrans = !IsBinary(destFile);
                    }

                    StreamWriter outw = null;
                    if (asciiTrans)
                    {
                        outw = new StreamWriter(outputStream);
                    }

                    var rdbuf = new byte[32*1024];

                    while (true)
                    {
                        var numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);

                        if (numRead <= 0)
                        {
                            break;
                        }

                        if (asciiTrans)
                        {
                            for (int off = 0, b = 0; b < numRead; ++b)
                            {
                                if (rdbuf[b] == 10)
                                {
                                    var s = Encoding.UTF8.GetString(rdbuf, off, (b - off));
                                    outw.WriteLine(s);
                                    off = b + 1;
                                }
                            }
                        }
                        else
                        {
                            outputStream.Write(rdbuf, 0, numRead);
                        }
                    }

                    if (asciiTrans)
                    {
                        outw.Close();
                    }
                    else
                    {
                        outputStream.Close();
                    }
                }
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Write an entry to the archive. This method will call the putNextEntry
        /// and then write the contents of the entry, and finally call closeEntry()
        /// for entries that are files. For directories, it will call putNextEntry(),
        /// and then, if the recurse flag is true, process each entry that is a
        /// child of the directory.
        /// </summary>
        /// <param name="sourceEntry">
        /// The TarEntry representing the entry to write to the archive.
        /// </param>
        /// <param name="recurse">
        /// If true, process the children of directory entries.
        /// </param>
        public void WriteEntry(TarEntry sourceEntry, bool recurse)
        {
            if (sourceEntry == null)
            {
                throw new ArgumentNullException("sourceEntry");
            }

            if (isDisposed)
            {
                throw new ObjectDisposedException("TarArchive");
            }

            try
            {
                if (recurse)
                {
                    TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
                                               sourceEntry.GroupId, sourceEntry.GroupName);
                }
                InternalWriteEntry(sourceEntry, recurse);
            }
            finally
            {
                if (recurse)
                {
                    TarHeader.RestoreSetValues();
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Get entries for all files present in this entries directory.
        /// If this entry doesnt represent a directory zero entries are returned.
        /// </summary>
        /// <returns>
        /// An array of TarEntry's for this entry's children.
        /// </returns>
        public TarEntry[] GetDirectoryEntries()
        {
            if ((_file == null) || !Directory.Exists(_file))
            {
                return new TarEntry[0];
            }

#if !SL4
            var list = Directory.GetFileSystemEntries(_file);
#else
            var list = Directory.EnumerateFileSystemEntries(_file).ToArray();
#endif
            var result = new TarEntry[list.Length];

            for (var i = 0; i < list.Length; ++i)
            {
                result[i] = CreateEntryFromFile(list[i]);
            }

            return result;
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Raises the ProgressMessage event
 /// </summary>
 /// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
 /// <param name="message">message for this event.  Null is no message</param>
 protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
 {
     if (ProgressMessageEvent != null)
     {
         ProgressMessageEvent(this, entry, message);
     }
 }
Ejemplo n.º 10
0
 /// <summary>
 /// Construct an entry for a _file. File is set to _file, and the
 /// _header is constructed from information from the _file.
 /// </summary>
 /// <param name = "fileName">The _file name that the entry represents.</param>
 /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
 public static TarEntry CreateEntryFromFile(string fileName)
 {
     var entry = new TarEntry();
     entry.GetFileTarHeader(entry._header, fileName);
     return entry;
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Determine if the given entry is a descendant of this entry.
        /// Descendancy is determined by the name of the descendant
        /// starting with this entry's name.
        /// </summary>
        /// <param name = "toTest">
        /// Entry to be checked as a descendent of this.
        /// </param>
        /// <returns>
        /// True if entry is a descendant of this.
        /// </returns>
        public bool IsDescendent(TarEntry toTest)
        {
            if (toTest == null)
            {
                throw new ArgumentNullException("toTest");
            }

            return toTest.Name.StartsWith(Name);
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Construct an entry with only a <paramref name="name">name</paramref>.
 /// This allows the programmer to construct the entry's _header "by hand". 
 /// </summary>
 /// <param name="name">The name to use for the entry</param>
 /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
 public static TarEntry CreateTarEntry(string name)
 {
     var entry = new TarEntry();
     NameTarHeader(entry._header, name);
     return entry;
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Clone this tar entry.
 /// </summary>
 /// <returns>Returns a clone of this entry.</returns>
 public object Clone()
 {
     var entry = new TarEntry{_file = _file, _header = ((TarHeader) _header.Clone()), Name = Name};
     return entry;
 }
Ejemplo n.º 14
0
 /// <summary>
 /// Create a tar entry with details obtained from <paramref name="fileName">file</paramref>
 /// </summary>
 /// <param name="fileName">The name of the file to retrieve details from.</param>
 /// <returns>A new <see cref="TarEntry"/></returns>
 public TarEntry CreateEntryFromFile(string fileName)
 {
     return(TarEntry.CreateEntryFromFile(fileName));
 }
Ejemplo n.º 15
0
 /// <summary>
 /// Create a <see cref="TarEntry"/> based on named
 /// </summary>
 /// <param name="name">The name to use for the entry</param>
 /// <returns>A new <see cref="TarEntry"/></returns>
 public TarEntry CreateEntry(string name)
 {
     return(TarEntry.CreateTarEntry(name));
 }
Ejemplo n.º 16
0
        /// <summary>
        /// Get the next entry in this tar archive. This will skip
        /// over any remaining data in the current entry, if there
        /// is one, and place the input stream at the header of the
        /// next entry, and read the header and instantiate a new
        /// TarEntry from the header bytes and return that entry.
        /// If there are no more entries in the archive, null will
        /// be returned to indicate that the end of the archive has
        /// been reached.
        /// </summary>
        /// <returns>
        /// The next TarEntry in the archive, or null.
        /// </returns>
        public TarEntry GetNextEntry()
        {
            if (hasHitEOF)
            {
                return(null);
            }

            if (currentEntry != null)
            {
                SkipToNextEntry();
            }

            var headerBuf = _buffer.ReadBlock();

            if (headerBuf == null)
            {
                hasHitEOF = true;
            }
            else if (_buffer.IsEOFBlock(headerBuf))
            {
                hasHitEOF = true;
            }

            if (hasHitEOF)
            {
                currentEntry = null;
            }
            else
            {
                try
                {
                    var header = new TarHeader();
                    header.ParseBuffer(headerBuf);
                    if (!header.IsChecksumValid)
                    {
                        throw new TarException("Header checksum is invalid");
                    }
                    entryOffset = 0;
                    entrySize   = header.Size;

                    StringBuilder longName = null;

                    if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME)
                    {
                        var nameBuffer = new byte[TarBuffer.BlockSize];
                        var numToRead  = entrySize;

                        longName = new StringBuilder();

                        while (numToRead > 0)
                        {
                            var numRead = Read(nameBuffer, 0,
                                               (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead));

                            if (numRead == -1)
                            {
                                throw new InvalidHeaderException("Failed to read long name entry");
                            }

                            longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
                            numToRead -= numRead;
                        }

                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GHDR)
                    {
                        // POSIX global extended header
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_XHDR)
                    {
                        // POSIX extended header
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR)
                    {
                        // TODO: could show volume name when verbose
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }
                    else if (header.TypeFlag != TarHeader.LF_NORMAL &&
                             header.TypeFlag != TarHeader.LF_OLDNORM &&
                             header.TypeFlag != TarHeader.LF_DIR)
                    {
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = _buffer.ReadBlock();
                    }

                    if (entryFactory == null)
                    {
                        currentEntry = new TarEntry(headerBuf);
                        if (longName != null)
                        {
                            currentEntry.Name = longName.ToString();
                        }
                    }
                    else
                    {
                        currentEntry = entryFactory.CreateEntry(headerBuf);
                    }

                    // Magic was checked here for 'ustar' but there are multiple valid possibilities
                    // so this is not done anymore.

                    entryOffset = 0;

                    // TODO: Review How do we resolve this discrepancy?!
                    entrySize = currentEntry.Size;
                }
                catch (InvalidHeaderException ex)
                {
                    entrySize    = 0;
                    entryOffset  = 0;
                    currentEntry = null;
                    var errorText = string.Format("Bad header in record {0} block {1} {2}",
                                                  _buffer.CurrentRecord, _buffer.CurrentBlock, ex.Message);
                    throw new InvalidHeaderException(errorText);
                }
            }
            return(currentEntry);
        }