TarWriter.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. using System;
  2. using System.IO;
  3. using SharpCompress.Common;
  4. using SharpCompress.Common.Tar.Headers;
  5. using SharpCompress.Compressors;
  6. using SharpCompress.Compressors.BZip2;
  7. using SharpCompress.Compressors.Deflate;
  8. using SharpCompress.Compressors.LZMA;
  9. using SharpCompress.IO;
  10. namespace SharpCompress.Writers.Tar
  11. {
  12. public class TarWriter : AbstractWriter
  13. {
  14. private readonly bool finalizeArchiveOnClose;
  15. public TarWriter(Stream destination, TarWriterOptions options)
  16. : base(ArchiveType.Tar, options)
  17. {
  18. finalizeArchiveOnClose = options.FinalizeArchiveOnClose;
  19. if (!destination.CanWrite)
  20. {
  21. throw new ArgumentException("Tars require writable streams.");
  22. }
  23. if (WriterOptions.LeaveStreamOpen)
  24. {
  25. destination = new NonDisposingStream(destination);
  26. }
  27. switch (options.CompressionType)
  28. {
  29. case CompressionType.None:
  30. break;
  31. case CompressionType.BZip2:
  32. {
  33. destination = new BZip2Stream(destination, CompressionMode.Compress, false);
  34. }
  35. break;
  36. case CompressionType.GZip:
  37. {
  38. destination = new GZipStream(destination, CompressionMode.Compress);
  39. }
  40. break;
  41. case CompressionType.LZip:
  42. {
  43. destination = new LZipStream(destination, CompressionMode.Compress);
  44. }
  45. break;
  46. default:
  47. {
  48. throw new InvalidFormatException("Tar does not support compression: " + options.CompressionType);
  49. }
  50. }
  51. InitalizeStream(destination);
  52. }
  53. public override void Write(string filename, Stream source, DateTime? modificationTime)
  54. {
  55. Write(filename, source, modificationTime, null);
  56. }
  57. private string NormalizeFilename(string filename)
  58. {
  59. filename = filename.Replace('\\', '/');
  60. int pos = filename.IndexOf(':');
  61. if (pos >= 0)
  62. {
  63. filename = filename.Remove(0, pos + 1);
  64. }
  65. return filename.Trim('/');
  66. }
  67. public void Write(string filename, Stream source, DateTime? modificationTime, long? size)
  68. {
  69. if (!source.CanSeek && size == null)
  70. {
  71. throw new ArgumentException("Seekable stream is required if no size is given.");
  72. }
  73. long realSize = size ?? source.Length;
  74. TarHeader header = new TarHeader(WriterOptions.ArchiveEncoding);
  75. header.LastModifiedTime = modificationTime ?? TarHeader.EPOCH;
  76. header.Name = NormalizeFilename(filename);
  77. header.Size = realSize;
  78. header.Write(OutputStream);
  79. size = source.TransferTo(OutputStream);
  80. PadTo512(size.Value, false);
  81. }
  82. private void PadTo512(long size, bool forceZeros)
  83. {
  84. int zeros = (int)size % 512;
  85. if (zeros == 0 && !forceZeros)
  86. {
  87. return;
  88. }
  89. zeros = 512 - zeros;
  90. OutputStream.Write(new byte[zeros], 0, zeros);
  91. }
  92. protected override void Dispose(bool isDisposing)
  93. {
  94. if (isDisposing)
  95. {
  96. if (finalizeArchiveOnClose) {
  97. PadTo512(0, true);
  98. PadTo512(0, true);
  99. }
  100. switch (OutputStream)
  101. {
  102. case BZip2Stream b:
  103. {
  104. b.Finish();
  105. break;
  106. }
  107. case LZipStream l:
  108. {
  109. l.Finish();
  110. break;
  111. }
  112. }
  113. }
  114. base.Dispose(isDisposing);
  115. }
  116. }
  117. }