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