diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index fe1c42bb7d..3525e043b4 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 a1884d598a..afe59382d1 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 f8e649ec81..09ea7eced3 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); + } + } } }