1:   // TarHeader.cs
2:   // Copyright (C) 2001 Mike Krueger
3:   //
4:   // This program is free software; you can redistribute it and/or
5:   // modify it under the terms of the GNU General Public License
6:   // as published by the Free Software Foundation; either version 2
7:   // of the License, or (at your option) any later version.
8:   //
9:   // This program is distributed in the hope that it will be useful,
10:   // but WITHOUT ANY WARRANTY; without even the implied warranty of
11:   // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12:   // GNU General Public License for more details.
13:   //
14:   // You should have received a copy of the GNU General Public License
15:   // along with this program; if not, write to the Free Software
16:   // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17:   //
18:   // Linking this library statically or dynamically with other modules is
19:   // making a combined work based on this library.  Thus, the terms and
20:   // conditions of the GNU General Public License cover the whole
21:   // combination.
22:   // 
23:   // As a special exception, the copyright holders of this library give you
24:   // permission to link this library with independent modules to produce an
25:   // executable, regardless of the license terms of these independent
26:   // modules, and to copy and distribute the resulting executable under
27:   // terms of your choice, provided that you also meet, for each linked
28:   // independent module, the terms and conditions of the license of that
29:   // module.  An independent module is a module which is not derived from
30:   // or based on this library.  If you modify this library, you may extend
31:   // this exception to your version of the library, but you are not
32:   // obligated to do so.  If you do not wish to do so, delete this
33:   // exception statement from your version.
34:  
35:   using System;
36:   using System.Text;
37:  
38:   namespace ICSharpCode.SharpZipLib.Tar {
39:       
40:       
41:       /// <summary>
42:       /// This class encapsulates the Tar Entry Header used in Tar Archives.
43:       /// The class also holds a number of tar constants, used mostly in headers.
44:       /// </summary>
45:       public class TarHeader : ICloneable
46:       {
47:           /// <summary>
48:           /// The length of the name field in a header buffer.
49:           /// </summary>
50:           public readonly static int NAMELEN 100;
51:           
52:           /// <summary>
53:           /// The length of the mode field in a header buffer.
54:           /// </summary>
55:           public readonly static int MODELEN 8;
56:           
57:           /// <summary>
58:           /// The length of the user id field in a header buffer.
59:           /// </summary>
60:           public readonly static int UIDLEN 8;
61:           
62:           /// <summary>
63:           /// The length of the group id field in a header buffer.
64:           /// </summary>
65:           public readonly static int GIDLEN 8;
66:           
67:           /// <summary>
68:           /// The length of the checksum field in a header buffer.
69:           /// </summary>
70:           public readonly static int CHKSUMLEN 8;
71:           
72:           /// <summary>
73:           /// The length of the size field in a header buffer.
74:           /// </summary>
75:           public readonly static int SIZELEN 12;
76:           
77:           /// <summary>
78:           /// The length of the magic field in a header buffer.
79:           /// </summary>
80:           public readonly static int MAGICLEN 8;
81:           
82:           /// <summary>
83:           /// The length of the modification time field in a header buffer.
84:           /// </summary>
85:           public readonly static int MODTIMELEN 12;
86:           
87:           /// <summary>
88:           /// The length of the user name field in a header buffer.
89:           /// </summary>
90:           public readonly static int UNAMELEN 32;
91:           
92:           /// <summary>
93:           /// The length of the group name field in a header buffer.
94:           /// </summary>
95:           public readonly static int GNAMELEN 32;
96:           
97:           /// <summary>
98:           /// The length of the devices field in a header buffer.
99:           /// </summary>
100:           public readonly static int DEVLEN 8;
101:           
102:           /// <summary>
103:           /// LF_ constants represent the "link flag" of an entry, or more commonly,
104:           /// the "entry type". This is the "old way" of indicating a normal file.
105:           /// </summary>
106:           public readonly static byte    LF_OLDNORM    0;
107:           
108:           /// <summary>
109:           /// Normal file type.
110:           /// </summary>
111:           public readonly static byte    LF_NORMAL    = (byte'0';
112:           
113:           /// <summary>
114:           /// Link file type.
115:           /// </summary>
116:           public readonly static byte    LF_LINK        = (byte'1';
117:           
118:           /// <summary>
119:           /// Symbolic link file type.
120:           /// </summary>
121:           public readonly static byte    LF_SYMLINK    = (byte'2';
122:           
123:           /// <summary>
124:           /// Character device file type.
125:           /// </summary>
126:           public readonly static byte    LF_CHR        = (byte'3';
127:           
128:           /// <summary>
129:           /// Block device file type.
130:           /// </summary>
131:           public readonly static byte    LF_BLK        = (byte'4';
132:           
133:           /// <summary>
134:           /// Directory file type.
135:           /// </summary>
136:           public readonly static byte    LF_DIR        = (byte'5';
137:           
138:           /// <summary>
139:           /// FIFO (pipe) file type.
140:           /// </summary>
141:           public readonly static byte    LF_FIFO        = (byte'6';
142:           
143:           /// <summary>
144:           /// Contiguous file type.
145:           /// </summary>
146:           public readonly static byte    LF_CONTIG    = (byte'7';
147:           
148:           /// <summary>
149:           /// The magic tag representing a POSIX tar archive.
150:           /// </summary>
151:           public readonly static string    TMAGIC        "ustar";
152:           
153:           /// <summary>
154:           /// The magic tag representing a GNU tar archive.
155:           /// </summary>
156:           public readonly static string    GNU_TMAGIC    "ustar  ";
157:           
158:           /// <summary>
159:           /// The entry's name.
160:           /// </summary>
161:           public StringBuilder name;
162:           
163:           /// <summary>
164:           /// The entry's permission mode.
165:           /// </summary>
166:           public int mode;
167:           
168:           /// <summary>
169:           /// The entry's user id.
170:           /// </summary>
171:           public int userId;
172:           
173:           /// <summary>
174:           /// The entry's group id.
175:           /// </summary>
176:           public int groupId;
177:           
178:           /// <summary>
179:           /// The entry's size.
180:           /// </summary>
181:           public long size;
182:           
183:           /// <summary>
184:           /// The entry's modification time.
185:           /// </summary>
186:           public DateTime modTime;
187:           
188:           /// <summary>
189:           /// The entry's checksum.
190:           /// </summary>
191:           public int checkSum;
192:           
193:           /// <summary>
194:           /// The entry's link flag.
195:           /// </summary>
196:           public byte linkFlag;
197:           
198:           /// <summary>
199:           /// The entry's link name.
200:           /// </summary>
201:           public StringBuilder linkName;
202:           
203:           /// <summary>
204:           /// The entry's magic tag.
205:           /// </summary>
206:           public StringBuilder magic;
207:           
208:           /// <summary>
209:           /// The entry's user name.
210:           /// </summary>
211:           public StringBuilder userName;
212:           
213:           /// <summary>
214:           /// The entry's group name.
215:           /// </summary>
216:           public StringBuilder groupName;
217:           
218:           /// <summary>
219:           /// The entry's major device number.
220:           /// </summary>
221:           public int devMajor;
222:           
223:           /// <summary>
224:           /// The entry's minor device number.
225:           /// </summary>
226:           public int devMinor;
227:           
228:           public TarHeader()
229:           {
230:               this.magic new StringBuilder(TarHeader.TMAGIC);
231:               
232:               this.name     new StringBuilder();
233:               this.linkName new StringBuilder();
234:               
235:               string user Environment.UserName;
236:               
237:               if (user.Length 31) {
238:                   user user.Substring(031);
239:               }
240:               
241:               this.userId    0;
242:               this.groupId   0;
243:               this.userName  new StringBuilder(user);
244:               this.groupName new StringBuilder(String.Empty);
245:           }
246:           
247:           /// <summary>
248:           /// TarHeaders can be cloned.
249:           /// </summary>
250:           public object Clone()
251:           {
252:               TarHeader hdr new TarHeader();
253:               
254:               hdr.name      = (this.name == null) ? null new StringBuilder(this.name.ToString());
255:               hdr.mode      this.mode;
256:               hdr.userId    this.userId;
257:               hdr.groupId   this.groupId;
258:               hdr.size      this.size;
259:               hdr.modTime   this.modTime;
260:               hdr.checkSum  this.checkSum;
261:               hdr.linkFlag  this.linkFlag;
262:               hdr.linkName  = (this.linkName == null)  ? null new StringBuilder(this.linkName.ToString());
263:               hdr.magic     = (this.magic == null)     ? null new StringBuilder(this.magic.ToString());
264:               hdr.userName  = (this.userName == null)  ? null new StringBuilder(this.userName.ToString());
265:               hdr.groupName = (this.groupName == null) ? null new StringBuilder(this.groupName.ToString());
266:               hdr.devMajor  this.devMajor;
267:               hdr.devMinor  this.devMinor;
268:               
269:               return hdr;
270:           }
271:           
272:           /// <summary>
273:           /// Get the name of this entry.
274:           /// </summary>
275:           /// <returns>
276:           /// The entry's name.
277:           /// </returns>
278:           public string GetName()
279:           {
280:               return this.name.ToString();
281:           }
282:           
283:           /// <summary>
284:           /// Parse an octal string from a header buffer. This is used for the
285:           /// file permission mode value.
286:           /// </summary>
287:           /// <param name = "header">
288:           /// The header buffer from which to parse.
289:           /// </param>
290:           /// <param name = "offset">
291:           /// The offset into the buffer from which to parse.
292:           /// </param>
293:           /// <param name = "length">
294:           /// The number of header bytes to parse.
295:           /// </param>
296:           /// <returns>
297:           /// The long value of the octal string.
298:           /// </returns>
299:           public static long ParseOctal(byte[] headerint offsetint length)
300:           {
301:               long result 0;
302:               bool stillPadding true;
303:               
304:               int end offset length;
305:               for (int offsetend ; ++i) {
306:                   if (header[i] == 0) {
307:                       break;
308:                   }
309:                   
310:                   if (header[i] == (byte)' ' || header[i] == '0') {
311:                       if (stillPadding) {
312:                           continue;
313:                       }
314:                       
315:                       if (header[i] == (byte)' ') {
316:                           break;
317:                       }
318:                   }
319:                   
320:                   stillPadding false;
321:                   
322:                   result = (result << 3) + (header[i] - '0');
323:               }
324:               
325:               return result;
326:           }
327:           
328:           /// <summary>
329:           /// Parse an entry name from a header buffer.
330:           /// </summary>
331:           /// <param name="header">
332:           /// The header buffer from which to parse.
333:           /// </param>
334:           /// <param name="offset">
335:           /// The offset into the buffer from which to parse.
336:           /// </param>
337:           /// <param name="length">
338:           /// The number of header bytes to parse.
339:           /// </param>
340:           /// <returns>
341:           /// The header's entry name.
342:           /// </returns>
343:           public static StringBuilder ParseName(byte[] headerint offsetint length)
344:           {
345:               StringBuilder result new StringBuilder(length);
346:               
347:               for (int offsetoffset length; ++i) {
348:                   if (header[i] == 0) {
349:                       break;
350:                   }
351:                   result.Append((char)header[i]);
352:               }
353:               
354:               return result;
355:           }
356:           
357:           /// <summary>
358:           /// Determine the number of bytes in an entry name.
359:           /// </summary>
360:           /// <param name="name">
361:           /// </param>
362:           /// <param name="buf">
363:           /// The header buffer from which to parse.
364:           /// </param>
365:           /// <param name="offset">
366:           /// The offset into the buffer from which to parse.
367:           /// </param>
368:           /// <param name="length">
369:           /// The number of header bytes to parse.
370:           /// </param>
371:           /// <returns>
372:           /// The number of bytes in a header's entry name.
373:           /// </returns>
374:           public static int GetNameBytes(StringBuilder namebyte[] bufint offsetint length)
375:           {
376:               int i;
377:               
378:               for (length && name.Length; ++i) {
379:                   buf[offset i] = (byte)name[i];
380:               }
381:               
382:               for (; length ; ++i) {
383:                   buf[offset i] = 0;
384:               }
385:               
386:               return offset length;
387:           }
388:           
389:           /// <summary>
390:           /// Parse an octal integer from a header buffer.
391:           /// </summary>
392:           /// <param name = "val">
393:           /// </param>
394:           /// <param name = "buf">
395:           /// The header buffer from which to parse.
396: