clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.IO;
30 using System.Reflection;
31 using System.Text;
32 using log4net;
33  
34 namespace OpenSim.Framework.Serialization
35 {
36 /// <summary>
37 /// Temporary code to do the bare minimum required to read a tar archive for our purposes
38 /// </summary>
39 public class TarArchiveReader
40 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42  
43 public enum TarEntryType
44 {
45 TYPE_UNKNOWN = 0,
46 TYPE_NORMAL_FILE = 1,
47 TYPE_HARD_LINK = 2,
48 TYPE_SYMBOLIC_LINK = 3,
49 TYPE_CHAR_SPECIAL = 4,
50 TYPE_BLOCK_SPECIAL = 5,
51 TYPE_DIRECTORY = 6,
52 TYPE_FIFO = 7,
53 TYPE_CONTIGUOUS_FILE = 8,
54 }
55  
56 /// <summary>
57 /// Binary reader for the underlying stream
58 /// </summary>
59 protected BinaryReader m_br;
60  
61 /// <summary>
62 /// Used to trim off null chars
63 /// </summary>
64 protected static char[] m_nullCharArray = new char[] { '\0' };
65 /// <summary>
66 /// Used to trim off space chars
67 /// </summary>
68 protected static char[] m_spaceCharArray = new char[] { ' ' };
69  
70 /// <summary>
71 /// Generate a tar reader which reads from the given stream.
72 /// </summary>
73 /// <param name="s"></param>
74 public TarArchiveReader(Stream s)
75 {
76 m_br = new BinaryReader(s);
77 }
78  
79 /// <summary>
80 /// Read the next entry in the tar file.
81 /// </summary>
82 /// <param name="filePath"></param>
83 /// <returns>the data for the entry. Returns null if there are no more entries</returns>
84 public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
85 {
86 filePath = String.Empty;
87 entryType = TarEntryType.TYPE_UNKNOWN;
88 TarHeader header = ReadHeader();
89  
90 if (null == header)
91 return null;
92  
93 entryType = header.EntryType;
94 filePath = header.FilePath;
95 return ReadData(header.FileSize);
96 }
97  
98 /// <summary>
99 /// Read the next 512 byte chunk of data as a tar header.
100 /// </summary>
101 /// <returns>A tar header struct. null if we have reached the end of the archive.</returns>
102 protected TarHeader ReadHeader()
103 {
104 byte[] header = m_br.ReadBytes(512);
105  
106 // If there are no more bytes in the stream, return null header
107 if (header.Length == 0)
108 return null;
109  
110 // If we've reached the end of the archive we'll be in null block territory, which means
111 // the next byte will be 0
112 if (header[0] == 0)
113 return null;
114  
115 TarHeader tarHeader = new TarHeader();
116  
117 // If we're looking at a GNU tar long link then extract the long name and pull up the next header
118 if (header[156] == (byte)'L')
119 {
120 int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
121 tarHeader.FilePath = Encoding.ASCII.GetString(ReadData(longNameLength));
122 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
123 header = m_br.ReadBytes(512);
124 }
125 else
126 {
127 tarHeader.FilePath = Encoding.ASCII.GetString(header, 0, 100);
128 tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
129 //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath);
130 }
131  
132 tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
133  
134 switch (header[156])
135 {
136 case 0:
137 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
138 break;
139 case (byte)'0':
140 tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
141 break;
142 case (byte)'1':
143 tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK;
144 break;
145 case (byte)'2':
146 tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK;
147 break;
148 case (byte)'3':
149 tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL;
150 break;
151 case (byte)'4':
152 tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL;
153 break;
154 case (byte)'5':
155 tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY;
156 break;
157 case (byte)'6':
158 tarHeader.EntryType = TarEntryType.TYPE_FIFO;
159 break;
160 case (byte)'7':
161 tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE;
162 break;
163 }
164  
165 return tarHeader;
166 }
167  
168 /// <summary>
169 /// Read data following a header
170 /// </summary>
171 /// <param name="fileSize"></param>
172 /// <returns></returns>
173 protected byte[] ReadData(int fileSize)
174 {
175 byte[] data = m_br.ReadBytes(fileSize);
176  
177 //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize);
178  
179 // Read the rest of the empty padding in the 512 byte block
180 if (fileSize % 512 != 0)
181 {
182 int paddingLeft = 512 - (fileSize % 512);
183  
184 //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
185  
186 m_br.ReadBytes(paddingLeft);
187 }
188  
189 return data;
190 }
191  
192 public void Close()
193 {
194 m_br.Close();
195 }
196  
197 /// <summary>
198 /// Convert octal bytes to a decimal representation
199 /// </summary>
200 /// <param name="bytes"></param>
201 /// <returns></returns>
202 public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count)
203 {
204 // Trim leading white space: ancient tars do that instead
205 // of leading 0s :-( don't ask. really.
206 string oString = Encoding.ASCII.GetString(bytes, startIndex, count).TrimStart(m_spaceCharArray);
207  
208 int d = 0;
209  
210 foreach (char c in oString)
211 {
212 d <<= 3;
213 d |= c - '0';
214 }
215  
216 return d;
217 }
218 }
219  
220 public class TarHeader
221 {
222 public string FilePath;
223 public int FileSize;
224 public TarArchiveReader.TarEntryType EntryType;
225 }
226 }