mirror of
https://github.com/quamotion/dotnet-packaging.git
synced 2026-02-04 05:35:40 +00:00
Support writing tar archives with file names > 99 characters
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using Packaging.Targets.IO;
|
||||
using Packaging.Targets.IO;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace Packaging.Targets.Tests.IO
|
||||
@@ -52,6 +53,56 @@ namespace Packaging.Targets.Tests.IO
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTarWithLongFilenameTest()
|
||||
{
|
||||
using (Stream expected = File.OpenRead(@"IO/largefilename.tar"))
|
||||
using (Stream actual = new MemoryStream())
|
||||
using (Stream output = new ValidatingCompositeStream(null, actual, expected))
|
||||
{
|
||||
var directories = new string[]
|
||||
{
|
||||
"./",
|
||||
"./usr/",
|
||||
"./usr/lib/",
|
||||
"./usr/lib/mono/",
|
||||
"./usr/lib/mono/gac/",
|
||||
"./usr/lib/mono/gac/System.Runtime.InteropServices.RuntimeInformation/",
|
||||
"./usr/lib/mono/gac/System.Runtime.InteropServices.RuntimeInformation/4.0.0.0__b03f5f7f11d50a3a/",
|
||||
};
|
||||
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
TarFileCreator.WriteEntry(
|
||||
output,
|
||||
new ArchiveEntry()
|
||||
{
|
||||
Mode = LinuxFileMode.S_IXOTH | LinuxFileMode.S_IROTH | LinuxFileMode.S_IXGRP | LinuxFileMode.S_IRGRP | LinuxFileMode.S_IXUSR | LinuxFileMode.S_IWUSR | LinuxFileMode.S_IRUSR | LinuxFileMode.S_IFDIR,
|
||||
TargetPath = directory,
|
||||
Group = "root",
|
||||
Owner = "root",
|
||||
Modified = new DateTimeOffset(2016, 12, 15, 10, 58, 56, TimeSpan.Zero)
|
||||
},
|
||||
null);
|
||||
}
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes("This file has a very long name.")))
|
||||
{
|
||||
TarFileCreator.WriteEntry(
|
||||
output,
|
||||
new ArchiveEntry()
|
||||
{
|
||||
Mode = (LinuxFileMode)0x81FF,
|
||||
TargetPath = "./usr/lib/mono/gac/System.Runtime.InteropServices.RuntimeInformation/4.0.0.0__b03f5f7f11d50a3a/System.Runtime.InteropServices.RuntimeInformation.txt",
|
||||
Modified = new DateTimeOffset(2017, 11, 11, 12, 37, 58, TimeSpan.Zero)
|
||||
},
|
||||
stream);
|
||||
}
|
||||
|
||||
TarFileCreator.WriteTrailer(output);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTarFileTest()
|
||||
{
|
||||
|
||||
BIN
Packaging.Targets.Tests/IO/largefilename.tar
Normal file
BIN
Packaging.Targets.Tests/IO/largefilename.tar
Normal file
Binary file not shown.
@@ -41,6 +41,9 @@
|
||||
<None Update="Deb\libplist3_1.12-3.1_amd64.deb">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="IO\largefilename.tar">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="IO\test.cpio">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -103,5 +103,15 @@ namespace Packaging.Targets.IO
|
||||
/// The file is a Unix socket.
|
||||
/// </summary>
|
||||
S_IFSOCK = 0xC000 // 0140000 in octal
|
||||
|
||||
/// <summary>
|
||||
/// A flag to get all permissions applied to this file.
|
||||
/// </summary>
|
||||
PermissionsMask = 0x0FFF,
|
||||
|
||||
/// <summary>
|
||||
/// A flag to get the file type.
|
||||
/// </summary>
|
||||
FileTypeMask = 0xF000,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
|
||||
namespace Packaging.Targets.IO
|
||||
{
|
||||
@@ -55,14 +53,55 @@ namespace Packaging.Targets.IO
|
||||
targetPath = "." + targetPath;
|
||||
}
|
||||
|
||||
// Handle long file names (> 99 characters). If this is the case, add a "././@LongLink" pseudo-entry
|
||||
// which contains the full name.
|
||||
if (targetPath.Length > 99)
|
||||
{
|
||||
// Must include a trailing \0
|
||||
var nameLength = Encoding.UTF8.GetByteCount(targetPath);
|
||||
byte[] entryName = new byte[nameLength + 1];
|
||||
|
||||
Encoding.UTF8.GetBytes(targetPath, 0, targetPath.Length, entryName, 0);
|
||||
|
||||
ArchiveEntry nameEntry = new ArchiveEntry()
|
||||
{
|
||||
Mode = entry.Mode,
|
||||
Modified = entry.Modified,
|
||||
TargetPath = "././@LongLink",
|
||||
Owner = entry.Owner,
|
||||
Group = entry.Group
|
||||
};
|
||||
|
||||
using (MemoryStream nameStream = new MemoryStream(entryName))
|
||||
{
|
||||
WriteEntry(stream, nameEntry, nameStream);
|
||||
}
|
||||
|
||||
targetPath = targetPath.Substring(0, 99);
|
||||
}
|
||||
|
||||
var isDir = entry.Mode.HasFlag(LinuxFileMode.S_IFDIR);
|
||||
var isLink = !isDir && !string.IsNullOrWhiteSpace(entry.LinkTo);
|
||||
var isFile = !isDir && !isLink;
|
||||
var type = isFile
|
||||
? TarTypeFlag.RegType
|
||||
: isDir
|
||||
? TarTypeFlag.DirType
|
||||
: TarTypeFlag.LnkType;
|
||||
|
||||
TarTypeFlag type;
|
||||
|
||||
if (entry.TargetPath == "././@LongLink")
|
||||
{
|
||||
type = TarTypeFlag.LongName;
|
||||
}
|
||||
else if (isFile)
|
||||
{
|
||||
type = TarTypeFlag.RegType;
|
||||
}
|
||||
else if (isDir)
|
||||
{
|
||||
type = TarTypeFlag.DirType;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = TarTypeFlag.LnkType;
|
||||
}
|
||||
|
||||
bool dispose = false;
|
||||
if (data == null)
|
||||
@@ -82,7 +121,8 @@ namespace Packaging.Targets.IO
|
||||
{
|
||||
var hdr = new TarHeader()
|
||||
{
|
||||
FileMode = entry.Mode,
|
||||
// No need to set the file type, the tar header has a special field for that.
|
||||
FileMode = entry.Mode & LinuxFileMode.PermissionsMask,
|
||||
DevMajor = null,
|
||||
DevMinor = null,
|
||||
FileName = targetPath,
|
||||
|
||||
Reference in New Issue
Block a user