/// <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; }
/// <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); }