1
0

Fixed naming conventions

This commit is contained in:
2024-01-10 09:33:51 +01:00
parent 68dd0839eb
commit 9cd1344266
11 changed files with 218 additions and 241 deletions

View File

@@ -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,

View File

@@ -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);
} }
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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)
{ {

View File

@@ -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;
} }

View File

@@ -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;
} }
} }
} }

View File

@@ -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
{ {

View File

@@ -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;
}
} }
} }
} }

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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>