Merge pull request #52 from sander2/tar-long-name-support

Tar long name support
This commit is contained in:
Adam Hathcock
2015-04-09 13:39:21 +01:00
2 changed files with 80 additions and 27 deletions

View File

@@ -44,6 +44,44 @@ namespace SharpCompress.Test
}
}
[TestMethod]
public void Tar_VeryLongFilepathReadback()
{
string archive = "Tar_VeryLongFilepathReadback.tar";
ResetScratch();
// create a very long filename
string longFilename = "";
for (int i = 0; i < 600; i = longFilename.Length)
longFilename += i.ToString("D10") + "-";
longFilename += ".txt";
// Step 1: create a tar file containing a file with a long name
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
using (var writer = SharpCompress.Writer.WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
using (Stream inputStream = new MemoryStream())
{
StreamWriter sw = new StreamWriter(inputStream);
sw.Write("dummy filecontent");
sw.Flush();
inputStream.Position = 0;
writer.Write(longFilename, inputStream, null);
}
// Step 2: check if the written tar file can be read correctly
string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive);
using (var archive2 = TarArchive.Open(unmodified))
{
Assert.AreEqual(1, archive2.Entries.Count);
Assert.IsTrue(archive2.Entries.Any(entry => entry.Key == longFilename));
foreach (var entry in archive2.Entries)
Assert.AreEqual("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine());
}
}
[TestMethod]
public void Tar_UstarArchivePathReadLongName()
{

View File

@@ -40,48 +40,64 @@ namespace SharpCompress.Common.Tar.Headers
internal void Write(Stream output)
{
if (Name.Length > 255)
{
throw new InvalidFormatException("UsTar fileName can not be longer than 255 chars");
}
byte[] buffer = new byte[512];
string name = Name;
if (name.Length > 100)
{
name = Name.Substring(0, 100);
}
WriteStringBytes(name, buffer, 0, 100);
WriteOctalBytes(511, buffer, 100, 8);
WriteOctalBytes(0, buffer, 108, 8);
WriteOctalBytes(0, buffer, 116, 8);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long) (LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
buffer[156] = (byte) EntryType;
WriteOctalBytes(511, buffer, 100, 8); // file mode
WriteOctalBytes(0, buffer, 108, 8); // owner ID
WriteOctalBytes(0, buffer, 116, 8); // group ID
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
if (Name.Length > 100)
{
name = Name.Substring(101, Name.Length);
ArchiveEncoding.Default.GetBytes(name).CopyTo(buffer, 345);
// Set mock filename and filetype to indicate the next block is the actual name of the file
WriteStringBytes("././@LongLink", buffer, 0, 100);
buffer[156] = (byte)EntryType.LongName;
WriteOctalBytes(Name.Length + 1, buffer, 124, 12);
}
if (Size >= 0x1FFFFFFFF)
else
{
WriteStringBytes(Name, buffer, 0, 100);
WriteOctalBytes(Size, buffer, 124, 12);
var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds;
WriteOctalBytes(time, buffer, 136, 12);
buffer[156] = (byte)EntryType;
if (Size >= 0x1FFFFFFFF)
{
#if PORTABLE || NETFX_CORE
byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size));
#else
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size));
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size));
#endif
var bytes12 = new byte[12];
bytes.CopyTo(bytes12, 12 - bytes.Length);
bytes12[0] |= 0x80;
bytes12.CopyTo(buffer, 124);
var bytes12 = new byte[12];
bytes.CopyTo(bytes12, 12 - bytes.Length);
bytes12[0] |= 0x80;
bytes12.CopyTo(buffer, 124);
}
}
int crc = RecalculateChecksum(buffer);
WriteOctalBytes(crc, buffer, 148, 8);
output.Write(buffer, 0, buffer.Length);
if (Name.Length > 100)
{
WriteLongFilenameHeader(output);
Name = Name.Substring(0, 100);
Write(output);
}
}
private void WriteLongFilenameHeader(Stream output)
{
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
output.Write(nameBytes, 0, nameBytes.Length);
// pad to multiple of 512 bytes, and make sure a terminating null is added
int numPaddingBytes = 512 - (nameBytes.Length % 512);
if (numPaddingBytes == 0)
numPaddingBytes = 512;
output.Write(new byte[numPaddingBytes], 0, numPaddingBytes);
}
internal bool Read(BinaryReader reader)
@@ -163,7 +179,6 @@ namespace SharpCompress.Common.Tar.Headers
{
buffer[offset + i + shift] = (byte) val[i];
}
buffer[offset + length] = 0;
}
private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count)