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