Fixed naming conventions
This commit is contained in:
@@ -13,11 +13,9 @@ namespace AMWD.Common.Packing.Ar
|
||||
{
|
||||
// Source: http://en.wikipedia.org/wiki/Ar_%28Unix%29
|
||||
|
||||
private readonly Stream inStream;
|
||||
private readonly List<ArFileInfoExtended> files = new();
|
||||
private readonly long streamStartPosition;
|
||||
|
||||
private static readonly DateTime unixEpoch = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
private readonly Stream _inStream;
|
||||
private readonly List<ArFileInfoExtended> _files = new();
|
||||
private readonly long _streamStartPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArReader"/> class.
|
||||
@@ -28,8 +26,8 @@ namespace AMWD.Common.Packing.Ar
|
||||
if (!inStream.CanRead || !inStream.CanSeek)
|
||||
throw new ArgumentException("Stream not readable or seekable", nameof(inStream));
|
||||
|
||||
streamStartPosition = inStream.Position;
|
||||
this.inStream = inStream;
|
||||
_streamStartPosition = inStream.Position;
|
||||
_inStream = inStream;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
@@ -38,9 +36,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
/// Returns a list with all filenames of the archive.
|
||||
/// </summary>
|
||||
public IEnumerable<string> GetFileList()
|
||||
{
|
||||
return files.Select(fi => fi.FileName).ToList();
|
||||
}
|
||||
=> _files.Select(fi => fi.FileName).ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file info of a specific file in the archive.
|
||||
@@ -48,7 +44,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
/// <param name="fileName">The name of the specific file.</param>
|
||||
public ArFileInfo GetFileInfo(string fileName)
|
||||
{
|
||||
return files
|
||||
return _files
|
||||
.Where(fi => fi.FileName == fileName)
|
||||
.Select(fi => new ArFileInfo
|
||||
{
|
||||
@@ -72,23 +68,23 @@ namespace AMWD.Common.Packing.Ar
|
||||
if (!outStream.CanWrite)
|
||||
throw new ArgumentException("Stream not writable", nameof(outStream));
|
||||
|
||||
var info = files.Where(fi => fi.FileName == fileName).FirstOrDefault();
|
||||
var info = _files.Where(fi => fi.FileName == fileName).FirstOrDefault();
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
long bytesToRead = info.FileSize;
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
|
||||
inStream.Seek(info.DataPosition, SeekOrigin.Begin);
|
||||
_inStream.Seek(info.DataPosition, SeekOrigin.Begin);
|
||||
while (bytesToRead > 0)
|
||||
{
|
||||
int readCount = (int)Math.Min(bytesToRead, buffer.Length);
|
||||
inStream.Read(buffer, 0, readCount);
|
||||
_inStream.Read(buffer, 0, readCount);
|
||||
outStream.Write(buffer, 0, readCount);
|
||||
|
||||
bytesToRead -= readCount;
|
||||
}
|
||||
inStream.Seek(streamStartPosition, SeekOrigin.Begin);
|
||||
_inStream.Seek(_streamStartPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,7 +94,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
/// <param name="destinationPath">The destination path on disk.</param>
|
||||
public void ReadFile(string fileName, string destinationPath)
|
||||
{
|
||||
var info = files.Where(fi => fi.FileName == fileName).FirstOrDefault();
|
||||
var info = _files.Where(fi => fi.FileName == fileName).FirstOrDefault();
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
@@ -112,7 +108,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
private void Initialize()
|
||||
{
|
||||
// Reset stream
|
||||
inStream.Seek(streamStartPosition, SeekOrigin.Begin);
|
||||
_inStream.Seek(_streamStartPosition, SeekOrigin.Begin);
|
||||
|
||||
// Read header
|
||||
string header = ReadAsciiString(8);
|
||||
@@ -120,33 +116,33 @@ namespace AMWD.Common.Packing.Ar
|
||||
throw new FormatException("The file stream is no archive");
|
||||
|
||||
// Create file list
|
||||
while (inStream.Position < inStream.Length)
|
||||
while (_inStream.Position < _inStream.Length)
|
||||
{
|
||||
var info = ReadFileHeader();
|
||||
files.Add(info);
|
||||
_files.Add(info);
|
||||
|
||||
// Move stream behind file content
|
||||
inStream.Seek(info.FileSize, SeekOrigin.Current);
|
||||
_inStream.Seek(info.FileSize, SeekOrigin.Current);
|
||||
|
||||
// Align to even offsets (padded with LF bytes)
|
||||
if (inStream.Position % 2 != 0)
|
||||
inStream.Seek(1, SeekOrigin.Current);
|
||||
if (_inStream.Position % 2 != 0)
|
||||
_inStream.Seek(1, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// Reset stream
|
||||
inStream.Seek(streamStartPosition, SeekOrigin.Begin);
|
||||
_inStream.Seek(_streamStartPosition, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
private string ReadAsciiString(int byteCount)
|
||||
{
|
||||
byte[] buffer = new byte[byteCount];
|
||||
inStream.Read(buffer, 0, byteCount);
|
||||
_inStream.Read(buffer, 0, byteCount);
|
||||
return Encoding.ASCII.GetString(buffer);
|
||||
}
|
||||
|
||||
private ArFileInfoExtended ReadFileHeader()
|
||||
{
|
||||
long startPosition = inStream.Position;
|
||||
long startPosition = _inStream.Position;
|
||||
|
||||
string fileName = ReadAsciiString(16).Trim();
|
||||
|
||||
@@ -159,7 +155,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
|
||||
// file magic
|
||||
byte[] magic = new byte[2];
|
||||
inStream.Read(magic, 0, magic.Length);
|
||||
_inStream.Read(magic, 0, magic.Length);
|
||||
|
||||
if (magic[0] != 0x60 || magic[1] != 0x0A) // `\n
|
||||
throw new FormatException("Invalid file magic");
|
||||
@@ -167,9 +163,9 @@ namespace AMWD.Common.Packing.Ar
|
||||
return new ArFileInfoExtended
|
||||
{
|
||||
HeaderPosition = startPosition,
|
||||
DataPosition = inStream.Position,
|
||||
DataPosition = _inStream.Position,
|
||||
FileName = fileName,
|
||||
ModifyTime = unixEpoch.AddSeconds(unixTimestamp),
|
||||
ModifyTime = DateTimeOffset.FromUnixTimeSeconds(unixTimestamp).DateTime,
|
||||
UserId = userId,
|
||||
GroupId = groupId,
|
||||
Mode = mode,
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
{
|
||||
// Source: http://en.wikipedia.org/wiki/Ar_%28Unix%29
|
||||
|
||||
private readonly Stream outStream;
|
||||
private static readonly DateTime unixEpoch = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
private readonly Stream _outStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new instance of the <see cref="ArWriter"/> class.
|
||||
@@ -26,7 +25,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
if (!outStream.CanWrite)
|
||||
throw new ArgumentException("Stream not writable", nameof(outStream));
|
||||
|
||||
this.outStream = outStream;
|
||||
_outStream = outStream;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
@@ -60,13 +59,13 @@ namespace AMWD.Common.Packing.Ar
|
||||
WriteFileHeader(fileName, modifyTime, userId, groupId, mode, stream.Length);
|
||||
|
||||
// Write file contents
|
||||
stream.CopyTo(outStream);
|
||||
stream.CopyTo(_outStream);
|
||||
|
||||
// Align to even offsets, pad with LF bytes
|
||||
if ((outStream.Position % 2) != 0)
|
||||
if ((_outStream.Position % 2) != 0)
|
||||
{
|
||||
byte[] bytes = new byte[] { 0x0A };
|
||||
outStream.Write(bytes, 0, 1);
|
||||
_outStream.Write(bytes, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +89,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
WriteAsciiString(fileName.PadRight(16, ' '));
|
||||
|
||||
// File modification timestamp
|
||||
int unixTime = (int)(modifyTime - unixEpoch).TotalSeconds;
|
||||
long unixTime = ((DateTimeOffset)DateTime.SpecifyKind(modifyTime, DateTimeKind.Utc)).ToUnixTimeSeconds();
|
||||
WriteAsciiString(unixTime.ToString().PadRight(12, ' '));
|
||||
|
||||
// User ID
|
||||
@@ -131,7 +130,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
|
||||
// File magic
|
||||
byte[] bytes = new byte[] { 0x60, 0x0A };
|
||||
outStream.Write(bytes, 0, 2);
|
||||
_outStream.Write(bytes, 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -141,7 +140,7 @@ namespace AMWD.Common.Packing.Ar
|
||||
private void WriteAsciiString(string str)
|
||||
{
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(str);
|
||||
outStream.Write(bytes, 0, bytes.Length);
|
||||
_outStream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using AMWD.Common.Packing.Tar.Interfaces;
|
||||
using AMWD.Common.Packing.Tar.Utils;
|
||||
|
||||
@@ -16,10 +14,10 @@ namespace AMWD.Common.Packing.Tar
|
||||
/// </remarks>
|
||||
public class TarReader
|
||||
{
|
||||
private readonly byte[] dataBuffer = new byte[512];
|
||||
private readonly UsTarHeader header;
|
||||
private readonly Stream inStream;
|
||||
private long remainingBytesInFile;
|
||||
private readonly byte[] _dataBuffer = new byte[512];
|
||||
private readonly UsTarHeader _header;
|
||||
private readonly Stream _inStream;
|
||||
private long _remainingBytesInFile;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs TarReader object to read data from `tarredData` stream
|
||||
@@ -27,14 +25,11 @@ namespace AMWD.Common.Packing.Tar
|
||||
/// <param name="tarredData">A stream to read tar archive from</param>
|
||||
public TarReader(Stream tarredData)
|
||||
{
|
||||
inStream = tarredData;
|
||||
header = new UsTarHeader();
|
||||
_inStream = tarredData;
|
||||
_header = new UsTarHeader();
|
||||
}
|
||||
|
||||
public ITarHeader FileInfo
|
||||
{
|
||||
get { return header; }
|
||||
}
|
||||
public ITarHeader FileInfo => _header;
|
||||
|
||||
/// <summary>
|
||||
/// Read all files from an archive to a directory. It creates some child directories to
|
||||
@@ -49,7 +44,7 @@ namespace AMWD.Common.Packing.Tar
|
||||
/// to your business logic.
|
||||
public void ReadToEnd(string destDirectory)
|
||||
{
|
||||
while (MoveNext(false))
|
||||
while (MoveNext(skipData: false))
|
||||
{
|
||||
string fileNameFromArchive = FileInfo.FileName;
|
||||
string totalPath = destDirectory + Path.DirectorySeparatorChar + fileNameFromArchive;
|
||||
@@ -59,70 +54,72 @@ namespace AMWD.Common.Packing.Tar
|
||||
Directory.CreateDirectory(totalPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If record is a file
|
||||
string fileName = Path.GetFileName(totalPath);
|
||||
string directory = totalPath.Remove(totalPath.Length - fileName.Length);
|
||||
Directory.CreateDirectory(directory);
|
||||
using (FileStream file = File.Create(totalPath))
|
||||
{
|
||||
|
||||
using FileStream file = File.Create(totalPath);
|
||||
Read(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from a current file to a Stream.
|
||||
/// </summary>
|
||||
/// <param name="dataDestanation">A stream to read data to</param>
|
||||
///
|
||||
/// <seealso cref="MoveNext"/>
|
||||
public void Read(Stream dataDestanation)
|
||||
{
|
||||
Debug.WriteLine("tar stream position Read in: " + inStream.Position);
|
||||
Debug.WriteLine("tar stream position Read in: " + _inStream.Position);
|
||||
|
||||
int readBytes;
|
||||
byte[] read;
|
||||
while ((readBytes = Read(out read)) != -1)
|
||||
while ((readBytes = Read(out byte[] read)) != -1)
|
||||
{
|
||||
Debug.WriteLine("tar stream position Read while(...) : " + inStream.Position);
|
||||
Debug.WriteLine("tar stream position Read while(...) : " + _inStream.Position);
|
||||
dataDestanation.Write(read, 0, readBytes);
|
||||
}
|
||||
Debug.WriteLine("tar stream position Read out: " + inStream.Position);
|
||||
|
||||
Debug.WriteLine("tar stream position Read out: " + _inStream.Position);
|
||||
}
|
||||
|
||||
protected int Read(out byte[] buffer)
|
||||
{
|
||||
if (remainingBytesInFile == 0)
|
||||
if (_remainingBytesInFile == 0)
|
||||
{
|
||||
buffer = null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int align512 = -1;
|
||||
long toRead = remainingBytesInFile - 512;
|
||||
long toRead = _remainingBytesInFile - 512;
|
||||
|
||||
if (toRead > 0)
|
||||
{
|
||||
toRead = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
align512 = 512 - (int)remainingBytesInFile;
|
||||
toRead = remainingBytesInFile;
|
||||
align512 = 512 - (int)_remainingBytesInFile;
|
||||
toRead = _remainingBytesInFile;
|
||||
}
|
||||
|
||||
int bytesRead = _inStream.Read(_dataBuffer, 0, (int)toRead);
|
||||
_remainingBytesInFile -= bytesRead;
|
||||
|
||||
int bytesRead = inStream.Read(dataBuffer, 0, (int)toRead);
|
||||
remainingBytesInFile -= bytesRead;
|
||||
|
||||
if (inStream.CanSeek && align512 > 0)
|
||||
if (_inStream.CanSeek && align512 > 0)
|
||||
{
|
||||
inStream.Seek(align512, SeekOrigin.Current);
|
||||
_inStream.Seek(align512, SeekOrigin.Current);
|
||||
}
|
||||
else
|
||||
while (align512 > 0)
|
||||
{
|
||||
inStream.ReadByte();
|
||||
_inStream.ReadByte();
|
||||
--align512;
|
||||
}
|
||||
|
||||
buffer = dataBuffer;
|
||||
buffer = _dataBuffer;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
@@ -135,7 +132,8 @@ namespace AMWD.Common.Packing.Tar
|
||||
{
|
||||
foreach (byte b in buffer)
|
||||
{
|
||||
if (b != 0) return false;
|
||||
if (b != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -154,56 +152,52 @@ namespace AMWD.Common.Packing.Tar
|
||||
/// <seealso cref="Read(Stream)"/>
|
||||
public bool MoveNext(bool skipData)
|
||||
{
|
||||
Debug.WriteLine("tar stream position MoveNext in: " + inStream.Position);
|
||||
if (remainingBytesInFile > 0)
|
||||
Debug.WriteLine("tar stream position MoveNext in: " + _inStream.Position);
|
||||
if (_remainingBytesInFile > 0)
|
||||
{
|
||||
if (!skipData)
|
||||
{
|
||||
throw new TarException(
|
||||
"You are trying to change file while not all the data from the previous one was read. If you do want to skip files use skipData parameter set to true.");
|
||||
}
|
||||
|
||||
// Skip to the end of file.
|
||||
if (inStream.CanSeek)
|
||||
if (_inStream.CanSeek)
|
||||
{
|
||||
long remainer = (remainingBytesInFile % 512);
|
||||
inStream.Seek(remainingBytesInFile + (512 - (remainer == 0 ? 512 : remainer)), SeekOrigin.Current);
|
||||
long remainer = _remainingBytesInFile % 512;
|
||||
_inStream.Seek(_remainingBytesInFile + (512 - (remainer == 0 ? 512 : remainer)), SeekOrigin.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] buffer;
|
||||
while (Read(out buffer) != -1)
|
||||
{
|
||||
}
|
||||
while (Read(out _) != -1) ;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = header.GetBytes();
|
||||
byte[] bytes = _header.GetBytes();
|
||||
|
||||
int headerRead = inStream.Read(bytes, 0, header.HeaderSize);
|
||||
int headerRead = _inStream.Read(bytes, 0, _header.HeaderSize);
|
||||
if (headerRead < 512)
|
||||
{
|
||||
throw new TarException("Can not read header");
|
||||
}
|
||||
|
||||
if (IsEmpty(bytes))
|
||||
{
|
||||
headerRead = inStream.Read(bytes, 0, header.HeaderSize);
|
||||
headerRead = _inStream.Read(bytes, 0, _header.HeaderSize);
|
||||
if (headerRead == 512 && IsEmpty(bytes))
|
||||
{
|
||||
Debug.WriteLine("tar stream position MoveNext out(false): " + inStream.Position);
|
||||
Debug.WriteLine("tar stream position MoveNext out(false): " + _inStream.Position);
|
||||
return false;
|
||||
}
|
||||
throw new TarException("Broken archive");
|
||||
}
|
||||
|
||||
if (header.UpdateHeaderFromBytes())
|
||||
if (_header.UpdateHeaderFromBytes())
|
||||
{
|
||||
throw new TarException("Checksum check failed");
|
||||
}
|
||||
|
||||
remainingBytesInFile = header.SizeInBytes;
|
||||
_remainingBytesInFile = _header.SizeInBytes;
|
||||
|
||||
Debug.WriteLine("tar stream position MoveNext out(true): " + inStream.Position);
|
||||
Debug.WriteLine("tar stream position MoveNext out(true): " + _inStream.Position);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace AMWD.Common.Packing.Tar
|
||||
// https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarWriter.cs
|
||||
public class TarWriter : LegacyTarWriter
|
||||
{
|
||||
public TarWriter(Stream outStream) : base(outStream)
|
||||
{
|
||||
}
|
||||
public TarWriter(Stream outStream)
|
||||
: base(outStream)
|
||||
{ }
|
||||
|
||||
protected override void WriteHeader(string name, DateTime lastModificationTime, long count, int userId, int groupId, int mode, EntryType entryType)
|
||||
{
|
||||
|
||||
@@ -5,39 +5,39 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
internal class DataWriter : IArchiveDataWriter
|
||||
{
|
||||
private readonly long size;
|
||||
private long remainingBytes;
|
||||
private readonly Stream stream;
|
||||
private readonly long _size;
|
||||
private long _remainingBytes;
|
||||
private readonly Stream _stream;
|
||||
|
||||
public DataWriter(Stream data, long dataSizeInBytes)
|
||||
{
|
||||
size = dataSizeInBytes;
|
||||
remainingBytes = size;
|
||||
stream = data;
|
||||
_size = dataSizeInBytes;
|
||||
_remainingBytes = _size;
|
||||
_stream = data;
|
||||
}
|
||||
|
||||
public bool CanWrite { get; private set; } = true;
|
||||
|
||||
public int Write(byte[] buffer, int count)
|
||||
{
|
||||
if (remainingBytes == 0)
|
||||
if (_remainingBytes == 0)
|
||||
{
|
||||
CanWrite = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesToWrite;
|
||||
if (remainingBytes - count < 0)
|
||||
if (_remainingBytes - count < 0)
|
||||
{
|
||||
bytesToWrite = (int)remainingBytes;
|
||||
bytesToWrite = (int)_remainingBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesToWrite = count;
|
||||
}
|
||||
|
||||
stream.Write(buffer, 0, bytesToWrite);
|
||||
remainingBytes -= bytesToWrite;
|
||||
_stream.Write(buffer, 0, bytesToWrite);
|
||||
_remainingBytes -= bytesToWrite;
|
||||
|
||||
return bytesToWrite;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,13 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
/// </remarks>
|
||||
public class LegacyTarWriter : IDisposable
|
||||
{
|
||||
private readonly Stream outStream;
|
||||
private readonly Stream _outStream;
|
||||
private bool _isClosed;
|
||||
|
||||
/// <summary>
|
||||
/// The buffer for writing.
|
||||
/// </summary>
|
||||
protected byte[] buffer = new byte[1024];
|
||||
private bool isClosed;
|
||||
public bool ReadOnZero = true;
|
||||
|
||||
/// <summary>
|
||||
/// Writes tar (see GNU tar) archive to a stream
|
||||
@@ -25,16 +28,25 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
/// <param name="outStream">stream to write archive to</param>
|
||||
public LegacyTarWriter(Stream outStream)
|
||||
{
|
||||
this.outStream = outStream;
|
||||
_outStream = outStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to read on zero.
|
||||
/// </summary>
|
||||
public bool ReadOnZero { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output stream.
|
||||
/// </summary>
|
||||
protected virtual Stream OutStream
|
||||
{
|
||||
get { return outStream; }
|
||||
get { return _outStream; }
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
@@ -85,13 +97,13 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
WriteDirectoryEntry(directory, 0, 0, 0755);
|
||||
|
||||
string[] files = Directory.GetFiles(directory);
|
||||
foreach (var fileName in files)
|
||||
foreach (string fileName in files)
|
||||
{
|
||||
Write(fileName);
|
||||
}
|
||||
|
||||
string[] directories = Directory.GetDirectories(directory);
|
||||
foreach (var dirName in directories)
|
||||
foreach (string dirName in directories)
|
||||
{
|
||||
WriteDirectoryEntry(dirName, 0, 0, 0755);
|
||||
if (doRecursive)
|
||||
@@ -134,10 +146,9 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
AlignTo512(dataSizeInBytes, false);
|
||||
}
|
||||
|
||||
public virtual void Write(Stream data, long dataSizeInBytes, string name, int userId, int groupId, int mode,
|
||||
DateTime lastModificationTime)
|
||||
public virtual void Write(Stream data, long dataSizeInBytes, string name, int userId, int groupId, int mode, DateTime lastModificationTime)
|
||||
{
|
||||
if (isClosed)
|
||||
if (_isClosed)
|
||||
throw new TarException("Can not write to the closed writer");
|
||||
|
||||
// handle long file names (> 99 characters)
|
||||
@@ -172,7 +183,7 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
private void WriteLongName(string name, int userId, int groupId, int mode, DateTime lastModificationTime)
|
||||
{
|
||||
// must include a trailing \0
|
||||
var nameLength = Encoding.UTF8.GetByteCount(name);
|
||||
int nameLength = Encoding.UTF8.GetByteCount(name);
|
||||
byte[] entryName = new byte[nameLength + 1];
|
||||
|
||||
Encoding.UTF8.GetBytes(name, 0, name.Length, entryName, 0);
|
||||
@@ -238,7 +249,7 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
|
||||
public void AlignTo512(long size, bool acceptZero)
|
||||
{
|
||||
size = size % 512;
|
||||
size %= 512;
|
||||
if (size == 0 && !acceptZero) return;
|
||||
while (size < 512)
|
||||
{
|
||||
@@ -249,10 +260,13 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
if (isClosed) return;
|
||||
if (_isClosed)
|
||||
return;
|
||||
|
||||
AlignTo512(0, true);
|
||||
AlignTo512(0, true);
|
||||
isClosed = true;
|
||||
|
||||
_isClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using AMWD.Common.Packing.Tar.Interfaces;
|
||||
@@ -7,8 +8,11 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
internal class TarHeader : ITarHeader
|
||||
{
|
||||
private readonly byte[] buffer = new byte[512];
|
||||
private long headerChecksum;
|
||||
private static readonly byte[] _spaces = Encoding.ASCII.GetBytes(" ");
|
||||
private readonly byte[] _buffer = new byte[512];
|
||||
|
||||
private string _fileName;
|
||||
private long _headerChecksum;
|
||||
|
||||
public TarHeader()
|
||||
{
|
||||
@@ -18,63 +22,51 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
GroupId = 61; // 101 dec
|
||||
}
|
||||
|
||||
private string fileName;
|
||||
protected readonly DateTime TheEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
public EntryType EntryType { get; set; }
|
||||
private static byte[] spaces = Encoding.ASCII.GetBytes(" ");
|
||||
|
||||
public virtual string FileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return fileName.Replace("\0", string.Empty);
|
||||
}
|
||||
get => _fileName.Replace("\0", string.Empty);
|
||||
set
|
||||
{
|
||||
if (value.Length > 100)
|
||||
{
|
||||
throw new TarException("A file name can not be more than 100 chars long");
|
||||
}
|
||||
fileName = value;
|
||||
|
||||
_fileName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Mode { get; set; }
|
||||
|
||||
public string ModeString
|
||||
{
|
||||
get { return Convert.ToString(Mode, 8).PadLeft(7, '0'); }
|
||||
}
|
||||
=> Convert.ToString(Mode, 8).PadLeft(7, '0');
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public virtual string UserName
|
||||
{
|
||||
get { return UserId.ToString(); }
|
||||
set { UserId = Int32.Parse(value); }
|
||||
get => UserId.ToString();
|
||||
set => UserId = int.Parse(value);
|
||||
}
|
||||
|
||||
public string UserIdString
|
||||
{
|
||||
get { return Convert.ToString(UserId, 8).PadLeft(7, '0'); }
|
||||
}
|
||||
=> Convert.ToString(UserId, 8).PadLeft(7, '0');
|
||||
|
||||
public int GroupId { get; set; }
|
||||
|
||||
public virtual string GroupName
|
||||
{
|
||||
get { return GroupId.ToString(); }
|
||||
set { GroupId = Int32.Parse(value); }
|
||||
get => GroupId.ToString();
|
||||
set => GroupId = int.Parse(value);
|
||||
}
|
||||
|
||||
public string GroupIdString
|
||||
{
|
||||
get { return Convert.ToString(GroupId, 8).PadLeft(7, '0'); }
|
||||
}
|
||||
=> Convert.ToString(GroupId, 8).PadLeft(7, '0');
|
||||
|
||||
public long SizeInBytes { get; set; }
|
||||
|
||||
public string SizeString
|
||||
{
|
||||
get { return Convert.ToString(SizeInBytes, 8).PadLeft(11, '0'); }
|
||||
}
|
||||
=> Convert.ToString(SizeInBytes, 8).PadLeft(11, '0');
|
||||
|
||||
public DateTime LastModification { get; set; }
|
||||
|
||||
@@ -82,71 +74,63 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.ToString((long)(LastModification - TheEpoch).TotalSeconds, 8).PadLeft(11, '0');
|
||||
long unixTime = ((DateTimeOffset)DateTime.SpecifyKind(LastModification, DateTimeKind.Utc)).ToUnixTimeSeconds();
|
||||
return Convert.ToString(unixTime, 8).PadLeft(11, '0');
|
||||
}
|
||||
}
|
||||
|
||||
public string HeaderChecksumString
|
||||
{
|
||||
get { return Convert.ToString(headerChecksum, 8).PadLeft(6, '0'); }
|
||||
}
|
||||
=> Convert.ToString(_headerChecksum, 8).PadLeft(6, '0');
|
||||
|
||||
public virtual int HeaderSize
|
||||
{
|
||||
get { return 512; }
|
||||
}
|
||||
public virtual int HeaderSize => 512;
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
public byte[] GetBytes() => _buffer.ToArray();
|
||||
|
||||
public virtual bool UpdateHeaderFromBytes()
|
||||
{
|
||||
FileName = Encoding.ASCII.GetString(buffer, 0, 100);
|
||||
// thanks to Shasha Alperocivh. Trimming nulls.
|
||||
Mode = Convert.ToInt32(Encoding.ASCII.GetString(buffer, 100, 7).Trim(), 8);
|
||||
UserId = Convert.ToInt32(Encoding.ASCII.GetString(buffer, 108, 7).Trim(), 8);
|
||||
GroupId = Convert.ToInt32(Encoding.ASCII.GetString(buffer, 116, 7).Trim(), 8);
|
||||
FileName = Encoding.ASCII.GetString(_buffer, 0, 100);
|
||||
|
||||
EntryType = (EntryType)buffer[156];
|
||||
// Thanks to Shasha Alperocivh. Trimming nulls.
|
||||
Mode = Convert.ToInt32(Encoding.ASCII.GetString(_buffer, 100, 7).Trim(), 8);
|
||||
UserId = Convert.ToInt32(Encoding.ASCII.GetString(_buffer, 108, 7).Trim(), 8);
|
||||
GroupId = Convert.ToInt32(Encoding.ASCII.GetString(_buffer, 116, 7).Trim(), 8);
|
||||
|
||||
if ((buffer[124] & 0x80) == 0x80) // if size in binary
|
||||
EntryType = (EntryType)_buffer[156];
|
||||
|
||||
if ((_buffer[124] & 0x80) == 0x80) // if size in binary
|
||||
{
|
||||
long sizeBigEndian = BitConverter.ToInt64(buffer, 0x80);
|
||||
long sizeBigEndian = BitConverter.ToInt64(_buffer, 0x80);
|
||||
SizeInBytes = IPAddress.NetworkToHostOrder(sizeBigEndian);
|
||||
}
|
||||
else
|
||||
{
|
||||
SizeInBytes = Convert.ToInt64(Encoding.ASCII.GetString(buffer, 124, 11), 8);
|
||||
SizeInBytes = Convert.ToInt64(Encoding.ASCII.GetString(_buffer, 124, 11), 8);
|
||||
}
|
||||
long unixTimeStamp = Convert.ToInt64(Encoding.ASCII.GetString(buffer, 136, 11), 8);
|
||||
LastModification = TheEpoch.AddSeconds(unixTimeStamp);
|
||||
long unixTimeStamp = Convert.ToInt64(Encoding.ASCII.GetString(_buffer, 136, 11), 8);
|
||||
LastModification = DateTimeOffset.FromUnixTimeSeconds(unixTimeStamp).DateTime;
|
||||
|
||||
var storedChecksum = Convert.ToInt32(Encoding.ASCII.GetString(buffer, 148, 6));
|
||||
RecalculateChecksum(buffer);
|
||||
if (storedChecksum == headerChecksum)
|
||||
{
|
||||
int storedChecksum = Convert.ToInt32(Encoding.ASCII.GetString(_buffer, 148, 6));
|
||||
RecalculateChecksum(_buffer);
|
||||
if (storedChecksum == _headerChecksum)
|
||||
return true;
|
||||
}
|
||||
|
||||
RecalculateAltChecksum(buffer);
|
||||
return storedChecksum == headerChecksum;
|
||||
RecalculateAltChecksum(_buffer);
|
||||
return storedChecksum == _headerChecksum;
|
||||
}
|
||||
|
||||
private void RecalculateAltChecksum(byte[] buf)
|
||||
{
|
||||
spaces.CopyTo(buf, 148);
|
||||
headerChecksum = 0;
|
||||
_spaces.CopyTo(buf, 148);
|
||||
_headerChecksum = 0;
|
||||
foreach (byte b in buf)
|
||||
{
|
||||
if ((b & 0x80) == 0x80)
|
||||
{
|
||||
headerChecksum -= b ^ 0x80;
|
||||
_headerChecksum -= b ^ 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
headerChecksum += b;
|
||||
_headerChecksum += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,41 +138,42 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
public virtual byte[] GetHeaderValue()
|
||||
{
|
||||
// Clean old values
|
||||
Array.Clear(buffer, 0, buffer.Length);
|
||||
Array.Clear(_buffer, 0, _buffer.Length);
|
||||
|
||||
if (string.IsNullOrEmpty(FileName)) throw new TarException("FileName can not be empty.");
|
||||
if (FileName.Length >= 100) throw new TarException("FileName is too long. It must be less than 100 bytes.");
|
||||
if (string.IsNullOrEmpty(FileName))
|
||||
throw new TarException("FileName can not be empty.");
|
||||
|
||||
if (FileName.Length >= 100)
|
||||
throw new TarException("FileName is too long. It must be less than 100 bytes.");
|
||||
|
||||
// Fill header
|
||||
Encoding.ASCII.GetBytes(FileName.PadRight(100, '\0')).CopyTo(buffer, 0);
|
||||
Encoding.ASCII.GetBytes(ModeString).CopyTo(buffer, 100);
|
||||
Encoding.ASCII.GetBytes(UserIdString).CopyTo(buffer, 108);
|
||||
Encoding.ASCII.GetBytes(GroupIdString).CopyTo(buffer, 116);
|
||||
Encoding.ASCII.GetBytes(SizeString).CopyTo(buffer, 124);
|
||||
Encoding.ASCII.GetBytes(LastModificationString).CopyTo(buffer, 136);
|
||||
Encoding.ASCII.GetBytes(FileName.PadRight(100, '\0')).CopyTo(_buffer, 0);
|
||||
Encoding.ASCII.GetBytes(ModeString).CopyTo(_buffer, 100);
|
||||
Encoding.ASCII.GetBytes(UserIdString).CopyTo(_buffer, 108);
|
||||
Encoding.ASCII.GetBytes(GroupIdString).CopyTo(_buffer, 116);
|
||||
Encoding.ASCII.GetBytes(SizeString).CopyTo(_buffer, 124);
|
||||
Encoding.ASCII.GetBytes(LastModificationString).CopyTo(_buffer, 136);
|
||||
|
||||
// buffer[156] = 20;
|
||||
buffer[156] = ((byte)EntryType);
|
||||
_buffer[156] = ((byte)EntryType);
|
||||
|
||||
RecalculateChecksum(buffer);
|
||||
RecalculateChecksum(_buffer);
|
||||
|
||||
// Write checksum
|
||||
Encoding.ASCII.GetBytes(HeaderChecksumString).CopyTo(buffer, 148);
|
||||
Encoding.ASCII.GetBytes(HeaderChecksumString).CopyTo(_buffer, 148);
|
||||
|
||||
return buffer;
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
protected virtual void RecalculateChecksum(byte[] buf)
|
||||
{
|
||||
// Set default value for checksum. That is 8 spaces.
|
||||
spaces.CopyTo(buf, 148);
|
||||
_spaces.CopyTo(buf, 148);
|
||||
|
||||
// Calculate checksum
|
||||
headerChecksum = 0;
|
||||
_headerChecksum = 0;
|
||||
foreach (byte b in buf)
|
||||
{
|
||||
headerChecksum += b;
|
||||
}
|
||||
_headerChecksum += b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,59 +9,48 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
/// </summary>
|
||||
internal class UsTarHeader : TarHeader
|
||||
{
|
||||
private const string magic = "ustar";
|
||||
private const string version = " ";
|
||||
private string groupName;
|
||||
private const string Magic = "ustar";
|
||||
private const string Version = " ";
|
||||
|
||||
private string namePrefix = string.Empty;
|
||||
private string userName;
|
||||
private string _groupName;
|
||||
|
||||
private string _namePrefix = string.Empty;
|
||||
private string _userName;
|
||||
|
||||
public override string UserName
|
||||
{
|
||||
get
|
||||
{
|
||||
return userName.Replace("\0", string.Empty);
|
||||
}
|
||||
get => _userName.Replace("\0", string.Empty);
|
||||
set
|
||||
{
|
||||
if (value.Length > 32)
|
||||
{
|
||||
throw new TarException("user name can not be longer than 32 chars");
|
||||
}
|
||||
userName = value;
|
||||
|
||||
_userName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GroupName
|
||||
{
|
||||
get
|
||||
{
|
||||
return groupName.Replace("\0", string.Empty);
|
||||
}
|
||||
get => _groupName.Replace("\0", string.Empty);
|
||||
set
|
||||
{
|
||||
if (value.Length > 32)
|
||||
{
|
||||
throw new TarException("group name can not be longer than 32 chars");
|
||||
}
|
||||
groupName = value;
|
||||
|
||||
_groupName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override string FileName
|
||||
{
|
||||
get
|
||||
{
|
||||
return namePrefix.Replace("\0", string.Empty) + base.FileName.Replace("\0", string.Empty);
|
||||
}
|
||||
get => _namePrefix.Replace("\0", string.Empty) + base.FileName.Replace("\0", string.Empty);
|
||||
set
|
||||
{
|
||||
if (value.Length > 100)
|
||||
{
|
||||
if (value.Length > 255)
|
||||
{
|
||||
throw new TarException("UsTar fileName can not be longer thatn 255 chars");
|
||||
}
|
||||
|
||||
int position = value.Length - 100;
|
||||
|
||||
// Find first path separator in the remaining 100 chars of the file name
|
||||
@@ -75,7 +64,8 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
}
|
||||
if (position == value.Length)
|
||||
position = value.Length - 100;
|
||||
namePrefix = value.Substring(0, position);
|
||||
_namePrefix = value.Substring(0, position);
|
||||
|
||||
base.FileName = value.Substring(position, value.Length - position);
|
||||
}
|
||||
else
|
||||
@@ -88,26 +78,26 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
public override bool UpdateHeaderFromBytes()
|
||||
{
|
||||
byte[] bytes = GetBytes();
|
||||
|
||||
UserName = Encoding.ASCII.GetString(bytes, 0x109, 32);
|
||||
GroupName = Encoding.ASCII.GetString(bytes, 0x129, 32);
|
||||
namePrefix = Encoding.ASCII.GetString(bytes, 347, 157);
|
||||
_namePrefix = Encoding.ASCII.GetString(bytes, 347, 157);
|
||||
|
||||
return base.UpdateHeaderFromBytes();
|
||||
}
|
||||
|
||||
internal static bool IsPathSeparator(char ch)
|
||||
{
|
||||
return (ch == '\\' || ch == '/' || ch == '|'); // All the path separators I ever met.
|
||||
}
|
||||
=> ch == '\\' || ch == '/' || ch == '|'; // All the path separators I ever met.
|
||||
|
||||
public override byte[] GetHeaderValue()
|
||||
{
|
||||
byte[] header = base.GetHeaderValue();
|
||||
|
||||
Encoding.ASCII.GetBytes(magic).CopyTo(header, 0x101); // Mark header as ustar
|
||||
Encoding.ASCII.GetBytes(version).CopyTo(header, 0x106);
|
||||
Encoding.ASCII.GetBytes(Magic).CopyTo(header, 0x101); // Mark header as ustar
|
||||
Encoding.ASCII.GetBytes(Version).CopyTo(header, 0x106);
|
||||
Encoding.ASCII.GetBytes(UserName).CopyTo(header, 0x109);
|
||||
Encoding.ASCII.GetBytes(GroupName).CopyTo(header, 0x129);
|
||||
Encoding.ASCII.GetBytes(namePrefix).CopyTo(header, 347);
|
||||
Encoding.ASCII.GetBytes(_namePrefix).CopyTo(header, 347);
|
||||
|
||||
if (SizeInBytes >= 0x1FFFFFFFF)
|
||||
{
|
||||
@@ -117,6 +107,7 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
|
||||
RecalculateChecksum(header);
|
||||
Encoding.ASCII.GetBytes(HeaderChecksumString).CopyTo(header, 148);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
@@ -128,7 +119,7 @@ namespace AMWD.Common.Packing.Tar.Utils
|
||||
|
||||
private static byte[] AlignTo12(byte[] bytes)
|
||||
{
|
||||
var retVal = new byte[12];
|
||||
byte[] retVal = new byte[12];
|
||||
bytes.CopyTo(retVal, 12 - bytes.Length);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
###### Diffs
|
||||
|
||||
- [AMWD.Common](https://git.am-wd.de/AM.WD/common/compare/v2.0.1...main)
|
||||
- [AMWD.Common.AspNetCore](https://git.am-wd.de/AM.WD/common/compare/asp/v3.0.0...main)
|
||||
- [AMWD.Common.EntityFrameworkCore](https://git.am-wd.de/AM.WD/common/compare/efc/v3.0.0...main)
|
||||
- [AMWD.Common.Test](https://git.am-wd.de/AM.WD/common/compare/test/v2.1.1...main)
|
||||
- [AMWD.Common](https://git.am-wd.de/AM.WD/common/compare/v2.0.1...HEAD)
|
||||
- [AMWD.Common.AspNetCore](https://git.am-wd.de/AM.WD/common/compare/asp/v3.0.0...HEAD)
|
||||
- [AMWD.Common.EntityFrameworkCore](https://git.am-wd.de/AM.WD/common/compare/efc/v3.0.0...HEAD)
|
||||
- [AMWD.Common.Test](https://git.am-wd.de/AM.WD/common/compare/test/v2.1.1...HEAD)
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
<ItemGroup Condition="'$(CI)' == 'true'">
|
||||
<SourceLinkGitLabHost Include="$(CI_SERVER_HOST)" Version="$(CI_SERVER_VERSION)" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitLab" Version="1.1.1" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitLab" Version="8.0.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AMWD.NetRevisionTask" Version="1.1.0">
|
||||
<PackageReference Include="AMWD.NetRevisionTask" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
Reference in New Issue
Block a user