Esempio n. 1
0
        public static HeaderBlock CreateHeaderBlock()
        {
            var hb = new HeaderBlock
            {
                name         = new byte[100],
                mode         = new byte[8],
                uid          = new byte[8],
                gid          = new byte[8],
                size         = new byte[12],
                modifiedTime = new byte[12],
                checkSum     = new byte[8],
                linkName     = new byte[100],
                magic        = new byte[6],
                version      = new byte[2],
                userName     = new byte[32],
                groupName    = new byte[32],
                devMajor     = new byte[8],
                devMinor     = new byte[8],
                prefix       = new byte[155],
                pad          = new byte[12],
            };

            Array.Copy(Encoding.ASCII.GetBytes("ustar "), 0, hb.magic, 0, 6);
            hb.version[0] = hb.version[1] = (byte)TarEntryType.File;

            return(hb);
        }
Esempio n. 2
0
        /// <summary>Adds a file to the tar Archive</summary>
        /// <param name="fullName">The file to add to the archive</param><param name="directory"></param>
        public void AddFile(string fullName, string directory = null)
        {
            if (string.IsNullOrEmpty(directory))
            {
                directory = Path.GetDirectoryName(fullName);
            }

            // is it a symlink (ReparsePoint)?
            FileAttributes a = File.GetAttributes(fullName);

            if ((a & FileAttributes.ReparsePoint) != 0)
            {
                this.AddSymlink(fullName);
                return;
            }

            if (this.TarOptions.StatusWriter != null)
            {
                this.TarOptions.StatusWriter.WriteLine("{0}", fullName);
            }

            HeaderBlock hb = HeaderBlock.CreateHeaderBlock();

            string file = Path.Combine(directory, Path.GetFileName(fullName));

            if (file == fullName)
            {
                file = Path.GetFileName(fullName);
            }

            hb.InsertName(file, fullName);
            hb.TypeFlag = (byte)TarEntryType.File; // 0 + (byte)'0' ;
            var fi = new FileInfo(fullName);

            hb.SetSize((int)fi.Length);
            hb.SetChksum();
            byte[] block = this.Serializer.RawSerialize(hb);
            this.outFS.Write(block, 0, block.Length);

            using (FileStream fs = File.Open(fullName, FileMode.Open, FileAccess.Read))
            {
                Array.Clear(block, 0, block.Length);
                while (fs.Read(block, 0, block.Length) > 0)
                {
                    this.outFS.Write(block, 0, block.Length); // not n!!
                    Array.Clear(block, 0, block.Length);
                }
            }
        }
Esempio n. 3
0
        /// <summary>Adds a symbolic link to a Tar archive</summary>
        /// <param name="name">The filename of the symbolic link</param>
        private void AddSymlink(string name)
        {
            if (this.TarOptions.StatusWriter != null)
            {
                this.TarOptions.StatusWriter.WriteLine("{0}", name);
            }

            // add the block for the symlink, right here.
            HeaderBlock hb = HeaderBlock.CreateHeaderBlock();

            hb.InsertName(name, null);
            hb.InsertLinkName(name);
            hb.TypeFlag = (byte)TarEntryType.SymbolicLink;
            hb.SetSize(0);
            hb.SetChksum();
            byte[] block = this.Serializer.RawSerialize(hb);
            this.outFS.Write(block, 0, block.Length);
        }
Esempio n. 4
0
        /// <summary>Adds a directory to the tar archive</summary>
        /// <param name="dirName">The path to the directory</param><param name="parent"></param>
        public void AddDirectory(string dirName, string parent = null)
        {
            if (parent == null)
            {
                parent = dirName;
            }

            // insure trailing slash
            if (!dirName.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                dirName += Path.DirectorySeparatorChar;
            }

            if (this.TarOptions.StatusWriter != null)
            {
                this.TarOptions.StatusWriter.WriteLine("{0}", dirName);
            }

            string dir = dirName.Replace(parent, null).TrimSlash();

            if (dir != string.Empty)
            {
                // add the block for the dir, right here.
                HeaderBlock hb = HeaderBlock.CreateHeaderBlock();
                hb.InsertName(dir, dirName);
                hb.TypeFlag = 5 + (byte)'0';
                hb.SetSize(0); // some impls use agg size of all files contained
                hb.SetChksum();
                byte[] block = this.Serializer.RawSerialize(hb);
                this.outFS.Write(block, 0, block.Length);
            }

            // add the files:
            string[] filenames = Directory.GetFiles(dirName);
            foreach (string filename in filenames)
            {
                this.AddFile(filename, dir);
            }

            // add the subdirectories:
            string[] dirnames = Directory.GetDirectories(dirName);
            foreach (string d in dirnames)
            {
                // handle reparse points
                FileAttributes a = File.GetAttributes(d);
                if ((a & FileAttributes.ReparsePoint) == 0)
                {
                    // not a symlink
                    this.AddDirectory(d, Path.GetDirectoryName(dirName));
                }
                else if (this.TarOptions.FollowSymLinks)
                {
                    // isa symlink, and we want to follow it
                    this.AddDirectory(d, Path.GetDirectoryName(dirName));
                }
                else
                {
                    // not following symlinks; add it
                    this.AddSymlink(d);
                }
            }
        }
Esempio n. 5
0
        /// <param name="archive"></param><param name="extractDirectory"></param> <param name="wantExtract"></param>
        /// <returns></returns>
        private List <TarEntry> InternalListOrExtract(string archive, string extractDirectory, bool wantExtract)
        {
            var      entryList            = new List <TarEntry>();
            var      block                = new byte[512];
            int      blocksToMunch        = 0;
            int      remainingBytes       = 0;
            Stream   output               = null;
            DateTime mtime                = DateTime.Now;
            string   name                 = null;
            TarEntry entry                = null;
            var      deferredDirTimestamp = new Dictionary <string, DateTime>();

            if (!File.Exists(archive))
            {
                throw new FileNotFoundException("The archive does not exist", archive);
            }

            using (Stream fs = this.InternalGetInputStream(archive))
            {
                while (fs.Read(block, 0, block.Length) > 0)
                {
                    if (blocksToMunch > 0)
                    {
                        if (output != null)
                        {
                            int bytesToWrite = (block.Length < remainingBytes) ? block.Length : remainingBytes;

                            output.Write(block, 0, bytesToWrite);
                            remainingBytes -= bytesToWrite;
                        }

                        blocksToMunch--;

                        if (blocksToMunch == 0)
                        {
                            if (output != null)
                            {
                                if (output is MemoryStream)
                                {
                                    entry.Name =
                                        name   = Encoding.ASCII.GetString((output as MemoryStream).ToArray()).TrimNull();
                                }

                                output.Close();
                                output.Dispose();

                                if (output is FileStream && !this.TarOptions.DoNotSetTime)
                                {
                                    File.SetLastWriteTimeUtc(Path.Combine(extractDirectory, name), mtime);
                                }

                                output = null;
                            }
                        }

                        continue;
                    }

                    HeaderBlock hb = this.Serializer.RawDeserialize(block);

                    if (!hb.VerifyChksum())
                    {
                        throw new Exception("header checksum is invalid.");
                    }

                    // if this is the first entry, or if the prior entry is not a GnuLongName
                    if (entry == null || entry.Type != TarEntryType.GnuLongName)
                    {
                        name = hb.GetName();
                    }

                    if (string.IsNullOrEmpty(name))
                    {
                        break; // EOF
                    }

                    mtime          = hb.GetMtime();
                    remainingBytes = hb.GetSize();

                    if (hb.TypeFlag == 0)
                    {
                        hb.TypeFlag = (byte)'0'; // coerce old-style GNU type to posix tar type
                    }

                    entry = new TarEntry
                    {
                        Name = name, Mtime = mtime, Size = remainingBytes, @Type = (TarEntryType)hb.TypeFlag
                    };

                    if (entry.Type != TarEntryType.GnuLongName)
                    {
                        entryList.Add(entry);
                    }

                    blocksToMunch = (remainingBytes > 0) ? ((remainingBytes - 1) / 512) + 1 : 0;

                    if (entry.Type == TarEntryType.GnuLongName)
                    {
                        if (name != "././@LongLink")
                        {
                            if (wantExtract)
                            {
                                throw new Exception(
                                          string.Format(
                                              "unexpected name for type 'L' (expected '././@LongLink', got '{0}')", name));
                            }
                        }

                        // for GNU long names, we extract the long name info into a memory stream
                        output = new MemoryStream();
                        continue;
                    }

                    if (!wantExtract)
                    {
                    }
                    else
                    {
                        switch (entry.Type)
                        {
                        case TarEntryType.Directory:
                            if (!Directory.Exists(Path.Combine(extractDirectory, name)))
                            {
                                Directory.CreateDirectory(Path.Combine(extractDirectory, name));

                                // cannot set the time on the directory now, or it will be updated
                                // by future file writes.  Defer until after all file writes are done.
                                if (!this.TarOptions.DoNotSetTime)
                                {
                                    deferredDirTimestamp.Add(
                                        Path.Combine(extractDirectory, name).TrimSlash(), mtime);
                                }
                            }
                            else if (this.TarOptions.Overwrite)
                            {
                                if (!this.TarOptions.DoNotSetTime)
                                {
                                    deferredDirTimestamp.Add(
                                        Path.Combine(extractDirectory, name).TrimSlash(), mtime);
                                }
                            }

                            break;

                        case TarEntryType.FileOld:
                        case TarEntryType.File:
                        case TarEntryType.FileContiguous:
                            string p = Path.GetDirectoryName(Path.Combine(extractDirectory, name));
                            if (!string.IsNullOrEmpty(p))
                            {
                                if (!Directory.Exists(p))
                                {
                                    Directory.CreateDirectory(p);
                                }
                            }

                            output = this.InternalGetExtractOutputStream(name, extractDirectory);
                            break;

                        case TarEntryType.GnuVolumeHeader:
                        case TarEntryType.CharSpecial:
                        case TarEntryType.BlockSpecial:

                            // do nothing on extract
                            break;

                        case TarEntryType.SymbolicLink:
                            break;

                        default:
                            throw new Exception(string.Format("unsupported entry type ({0})", hb.TypeFlag));
                        }
                    }
                }
            }

            // apply the deferred timestamps on the directories
            if (deferredDirTimestamp.Count > 0)
            {
                foreach (string key in deferredDirTimestamp.Keys)
                {
                    Directory.SetLastWriteTimeUtc(key, deferredDirTimestamp[key]);
                }
            }

            return(entryList);
        }