forked from adamhathcock/sharpcompress
/
TarWriter.cs
131 lines (118 loc) · 4.1 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
128
129
130
131
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, false);
}
private void PadTo512(long size, bool forceZeros)
{
int zeros = (int)size % 512;
if (zeros == 0 && !forceZeros)
{
return;
}
zeros = 512 - zeros;
OutputStream.Write(stackalloc byte[zeros]);
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
if (finalizeArchiveOnClose)
{
PadTo512(0, true);
PadTo512(0, true);
}
switch (OutputStream)
{
case BZip2Stream b:
{
b.Finish();
break;
}
case LZipStream l:
{
l.Finish();
break;
}
}
}
base.Dispose(isDisposing);
}
}
}