OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
TarArchiveWriter.cs
Go to the documentation of this file.
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.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using System.Text;
33 using log4net;
34 
35 namespace OpenSim.Framework.Serialization
36 {
40  public class TarArchiveWriter
41  {
42 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 
47  protected BinaryWriter m_bw;
48 
49  public TarArchiveWriter(Stream s)
50  {
51  m_bw = new BinaryWriter(s);
52  }
53 
58  public void WriteDir(string dirName)
59  {
60  // Directories are signalled by a final /
61  if (!dirName.EndsWith("/"))
62  dirName += "/";
63 
64  WriteFile(dirName, new byte[0]);
65  }
66 
72  public void WriteFile(string filePath, string data)
73  {
74  WriteFile(filePath, Util.UTF8NoBomEncoding.GetBytes(data));
75  }
76 
82  public void WriteFile(string filePath, byte[] data)
83  {
84  if (filePath.Length > 100)
85  WriteEntry("././@LongLink", Encoding.ASCII.GetBytes(filePath), 'L');
86 
87  char fileType;
88 
89  if (filePath.EndsWith("/"))
90  {
91  fileType = '5';
92  }
93  else
94  {
95  fileType = '0';
96  }
97 
98  WriteEntry(filePath, data, fileType);
99  }
100 
106  public void Close()
107  {
108  //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks");
109 
110  // Write two consecutive 0 blocks to end the archive
111  byte[] finalZeroPadding = new byte[1024];
112 
113  lock (m_bw)
114  {
115  m_bw.Write(finalZeroPadding);
116 
117  m_bw.Flush();
118  m_bw.Close();
119  }
120  }
121 
122  public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding)
123  {
124  string oString = "";
125 
126  while (d > 0)
127  {
128  oString = Convert.ToString((byte)'0' + d & 7) + oString;
129  d >>= 3;
130  }
131 
132  while (oString.Length < padding)
133  {
134  oString = "0" + oString;
135  }
136 
137  byte[] oBytes = Encoding.ASCII.GetBytes(oString);
138 
139  return oBytes;
140  }
141 
148  protected void WriteEntry(string filePath, byte[] data, char fileType)
149  {
150 // m_log.DebugFormat(
151 // "[TAR ARCHIVE WRITER]: Data for {0} is {1} bytes", filePath, (null == data ? "null" : data.Length.ToString()));
152 
153  byte[] header = new byte[512];
154 
155  // file path field (100)
156  byte[] nameBytes = Encoding.ASCII.GetBytes(filePath);
157  int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
158  Array.Copy(nameBytes, header, nameSize);
159 
160  // file mode (8)
161  byte[] modeBytes = Encoding.ASCII.GetBytes("0000777");
162  Array.Copy(modeBytes, 0, header, 100, 7);
163 
164  // owner user id (8)
165  byte[] ownerIdBytes = Encoding.ASCII.GetBytes("0000764");
166  Array.Copy(ownerIdBytes, 0, header, 108, 7);
167 
168  // group user id (8)
169  byte[] groupIdBytes = Encoding.ASCII.GetBytes("0000764");
170  Array.Copy(groupIdBytes, 0, header, 116, 7);
171 
172  // file size in bytes (12)
173  int fileSize = data.Length;
174  //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
175 
176  byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
177 
178  Array.Copy(fileSizeBytes, 0, header, 124, 11);
179 
180  // last modification time (12)
181  byte[] lastModTimeBytes = Encoding.ASCII.GetBytes("11017037332");
182  Array.Copy(lastModTimeBytes, 0, header, 136, 11);
183 
184  // entry type indicator (1)
185  header[156] = Encoding.ASCII.GetBytes(new char[] { fileType })[0];
186 
187  Array.Copy(Encoding.ASCII.GetBytes("0000000"), 0, header, 329, 7);
188  Array.Copy(Encoding.ASCII.GetBytes("0000000"), 0, header, 337, 7);
189 
190  // check sum for header block (8) [calculated last]
191  Array.Copy(Encoding.ASCII.GetBytes(" "), 0, header, 148, 8);
192 
193  int checksum = 0;
194  foreach (byte b in header)
195  {
196  checksum += b;
197  }
198 
199  //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
200 
201  byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
202 
203  Array.Copy(checkSumBytes, 0, header, 148, 6);
204 
205  header[154] = 0;
206 
207  lock (m_bw)
208  {
209  // Write out header
210  m_bw.Write(header);
211 
212  // Write out data
213  // An IOException occurs if we try to write out an empty array in Mono 2.6
214  if (data.Length > 0)
215  m_bw.Write(data);
216 
217  if (data.Length % 512 != 0)
218  {
219  int paddingRequired = 512 - (data.Length % 512);
220 
221  //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
222 
223  byte[] padding = new byte[paddingRequired];
224  m_bw.Write(padding);
225  }
226  }
227  }
228  }
229 }
void WriteEntry(string filePath, byte[] data, char fileType)
Write a particular entry
Temporary code to produce a tar archive in tar v7 format
BinaryWriter m_bw
Binary writer for the underlying stream
static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding)
void WriteFile(string filePath, string data)
Write a file to the tar archive
void WriteFile(string filePath, byte[] data)
Write a file to the tar archive
void Close()
Finish writing the raw tar archive data to a stream. The stream will be closed on completion...
void WriteDir(string dirName)
Write a directory entry to the tar archive. We can only handle one path level right now! ...