From b57497fd41ad4cc56af40139ba940b5a4bbd47a6 Mon Sep 17 00:00:00 2001
From: Justin Clarke Casey
Date: Wed, 4 Mar 2009 18:33:05 +0000
Subject: * Add gnu tar format long file name support to tar reading and
writing. * Not actually tested yet though existing code which doesn't require
long file names looks fine
---
.../World/Archiver/ArchiveReadRequest.cs | 4 +-
.../CoreModules/World/Archiver/TarArchiveReader.cs | 22 ++-
.../CoreModules/World/Archiver/TarArchiveWriter.cs | 185 ++++++++++++---------
3 files changed, 126 insertions(+), 85 deletions(-)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index fe1c42b..3525e04 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -111,8 +111,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
{
- m_log.WarnFormat("[ARCHIVER]: Ignoring directory entry {0}",
- filePath);
+ m_log.WarnFormat(
+ "[ARCHIVER]: Ignoring directory entry {0}", filePath);
}
else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
{
diff --git a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs
index a1884d5..afe5938 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveReader.cs
@@ -27,7 +27,9 @@
using System;
using System.IO;
+using System.Reflection;
using System.Text;
+using log4net;
namespace OpenSim.Region.CoreModules.World.Archiver
{
@@ -36,7 +38,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
///
public class TarArchiveReader
{
- //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public enum TarEntryType
{
@@ -116,12 +118,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// If we've reached the end of the archive we'll be in null block territory, which means
// the next byte will be 0
if (header[0] == 0)
- return null;
+ return null;
TarHeader tarHeader = new TarHeader();
- tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
- tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
+ // If we're looking at a GNU tar long link then extract the long name and pull up the next header
+ if (header[156] == (byte)'L')
+ {
+ int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
+ tarHeader.FilePath = m_asciiEncoding.GetString(m_br.ReadBytes(longNameLength));
+ m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
+ header = m_br.ReadBytes(512);
+ }
+ else
+ {
+ tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
+ tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
+ }
+
tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
switch (header[156])
diff --git a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs
index f8e649e..09ea7ec 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/TarArchiveWriter.cs
@@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
{
m_files[filePath] = data;
}
-
+
///
/// Write the raw tar archive data to a stream. The stream will be closed on completion.
///
@@ -87,84 +87,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
foreach (string filePath in m_files.Keys)
{
- byte[] header = new byte[512];
- byte[] data = m_files[filePath];
-
- // file path field (100)
- byte[] nameBytes = m_asciiEncoding.GetBytes(filePath);
- int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
- Array.Copy(nameBytes, header, nameSize);
-
- // file mode (8)
- byte[] modeBytes = m_asciiEncoding.GetBytes("0000777");
- Array.Copy(modeBytes, 0, header, 100, 7);
-
- // owner user id (8)
- byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764");
- Array.Copy(ownerIdBytes, 0, header, 108, 7);
-
- // group user id (8)
- byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764");
- Array.Copy(groupIdBytes, 0, header, 116, 7);
-
- // file size in bytes (12)
- int fileSize = data.Length;
- //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
-
- byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
-
- Array.Copy(fileSizeBytes, 0, header, 124, 11);
-
- // last modification time (12)
- byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332");
- Array.Copy(lastModTimeBytes, 0, header, 136, 11);
-
- // link indicator (1)
- //header[156] = m_asciiEncoding.GetBytes("0")[0];
- if (filePath.EndsWith("/"))
- {
- header[156] = m_asciiEncoding.GetBytes("5")[0];
- }
- else
- {
- header[156] = 0;
- }
-
- Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7);
- Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7);
-
- // check sum for header block (8) [calculated last]
- Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8);
-
- int checksum = 0;
- foreach (byte b in header)
- {
- checksum += b;
- }
-
- //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
-
- byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
-
- Array.Copy(checkSumBytes, 0, header, 148, 6);
-
- header[154] = 0;
-
- // Write out header
- bw.Write(header);
-
- // Write out data
- bw.Write(data);
-
- if (data.Length % 512 != 0)
- {
- int paddingRequired = 512 - (data.Length % 512);
-
- //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
-
- byte[] padding = new byte[paddingRequired];
- bw.Write(padding);
- }
+ WriteFile(bw, filePath, m_files[filePath]);
}
//m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks");
@@ -195,6 +118,110 @@ namespace OpenSim.Region.CoreModules.World.Archiver
byte[] oBytes = m_asciiEncoding.GetBytes(oString);
return oBytes;
+ }
+
+ ///
+ /// Write a particular file of data
+ ///
+ ///
+ ///
+ protected void WriteFile(BinaryWriter bw, string filePath, byte[] data)
+ {
+ if (filePath.Length > 100)
+ WriteEntry(bw, "././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L');
+
+ char fileType;
+
+ if (filePath.EndsWith("/"))
+ {
+ fileType = '5';
+ }
+ else
+ {
+ fileType = '0';
+ }
+
+ WriteEntry(bw, filePath, data, fileType);
}
+
+ ///
+ /// Write a particular file of data
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void WriteEntry(BinaryWriter bw, string filePath, byte[] data, char fileType)
+ {
+ byte[] header = new byte[512];
+
+ // file path field (100)
+ byte[] nameBytes = m_asciiEncoding.GetBytes(filePath);
+ int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
+ Array.Copy(nameBytes, header, nameSize);
+
+ // file mode (8)
+ byte[] modeBytes = m_asciiEncoding.GetBytes("0000777");
+ Array.Copy(modeBytes, 0, header, 100, 7);
+
+ // owner user id (8)
+ byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764");
+ Array.Copy(ownerIdBytes, 0, header, 108, 7);
+
+ // group user id (8)
+ byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764");
+ Array.Copy(groupIdBytes, 0, header, 116, 7);
+
+ // file size in bytes (12)
+ int fileSize = data.Length;
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
+
+ byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
+
+ Array.Copy(fileSizeBytes, 0, header, 124, 11);
+
+ // last modification time (12)
+ byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332");
+ Array.Copy(lastModTimeBytes, 0, header, 136, 11);
+
+ // entry type indicator (1)
+ header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0];
+
+ Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7);
+ Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7);
+
+ // check sum for header block (8) [calculated last]
+ Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8);
+
+ int checksum = 0;
+ foreach (byte b in header)
+ {
+ checksum += b;
+ }
+
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
+
+ byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
+
+ Array.Copy(checkSumBytes, 0, header, 148, 6);
+
+ header[154] = 0;
+
+ // Write out header
+ bw.Write(header);
+
+ // Write out data
+ bw.Write(data);
+
+ if (data.Length % 512 != 0)
+ {
+ int paddingRequired = 512 - (data.Length % 512);
+
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
+
+ byte[] padding = new byte[paddingRequired];
+ bw.Write(padding);
+ }
+ }
}
}
--
cgit v1.1