Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Tar / TarEntry.cs @ 0eea575a

History | View | Annotate | Download (17.5 kB)

1
// TarEntry.cs
2
//
3
// Copyright (C) 2001 Mike Krueger
4
//
5
// This program is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU General Public License
7
// as published by the Free Software Foundation; either version 2
8
// of the License, or (at your option) any later version.
9
//
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
//
19
// Linking this library statically or dynamically with other modules is
20
// making a combined work based on this library.  Thus, the terms and
21
// conditions of the GNU General Public License cover the whole
22
// combination.
23
// 
24
// As a special exception, the copyright holders of this library give you
25
// permission to link this library with independent modules to produce an
26
// executable, regardless of the license terms of these independent
27
// modules, and to copy and distribute the resulting executable under
28
// terms of your choice, provided that you also meet, for each linked
29
// independent module, the terms and conditions of the license of that
30
// module.  An independent module is a module which is not derived from
31
// or based on this library.  If you modify this library, you may extend
32
// this exception to your version of the library, but you are not
33
// obligated to do so.  If you do not wish to do so, delete this
34
// exception statement from your version.
35

    
36
using System;
37
using System.IO;
38
using System.Linq;
39

    
40
namespace ICSharpCode.SharpZipLib.Silverlight.Tar
41
{
42
    /// <summary>
43
    /// This class represents an entry in a Tar archive. It consists
44
    /// of the entry's _header, as well as the entry's File. Entries
45
    /// can be instantiated in one of three ways, depending on how
46
    /// they are to be used.
47
    /// <p>
48
    /// TarEntries that are created from the _header bytes read from
49
    /// an archive are instantiated with the TarEntry( byte[] )
50
    /// constructor. These entries will be used when extracting from
51
    /// or listing the contents of an archive. These entries have their
52
    /// _header filled in using the _header bytes. They also set the File
53
    /// to null, since they reference an archive entry not a _file.</p>
54
    /// <p>
55
    /// TarEntries that are created from files that are to be written
56
    /// into an archive are instantiated with the CreateEntryFromFile(string)
57
    /// pseudo constructor. These entries have their _header filled in using
58
    /// the File's information. They also keep a reference to the File
59
    /// for convenience when writing entries.</p>
60
    /// <p>
61
    /// Finally, TarEntries can be constructed from nothing but a name.
62
    /// This allows the programmer to construct the entry by hand, for
63
    /// instance when only an InputStream is available for writing to
64
    /// the archive, and the _header information is constructed from
65
    /// other information. In this case the _header fields are set to
66
    /// defaults and the File is set to null.</p>
67
    /// <see cref="TarHeader"/>
68
    /// </summary>
69
    public class TarEntry
70
    {
71
        #region Constructors
72

    
73
        /// <summary>
74
        /// Initialise a default instance of <see cref="TarEntry"/>.
75
        /// </summary>
76
        private TarEntry()
77
        {
78
            _header = new TarHeader();
79
        }
80

    
81
        /// <summary>
82
        /// Construct an entry from an archive's _header bytes. File is set
83
        /// to null.
84
        /// </summary>
85
        /// <param name = "headerBuffer">
86
        /// The _header bytes from a tar archive entry.
87
        /// </param>
88
        public TarEntry(byte[] headerBuffer)
89
        {
90
            _header = new TarHeader();
91
            _header.ParseBuffer(headerBuffer);
92
        }
93

    
94
        /// <summary>
95
        /// Construct a TarEntry using the <paramref name="header">_header</paramref> provided
96
        /// </summary>
97
        /// <param name="header">Header details for entry</param>
98
        public TarEntry(TarHeader header)
99
        {
100
            if (header == null)
101
            {
102
                throw new ArgumentNullException("header");
103
            }
104

    
105
            _header = (TarHeader) header.Clone();
106
        }
107

    
108
        #endregion
109

    
110
        /// <summary>
111
        /// Get this entry's _header.
112
        /// </summary>
113
        /// <returns>
114
        /// This entry's TarHeader.
115
        /// </returns>
116
        public TarHeader TarHeader
117
        {
118
            get { return _header; }
119
        }
120

    
121
        /// <summary>
122
        /// Get/Set this entry's name.
123
        /// </summary>
124
        public string Name
125
        {
126
            get { return _header.Name; }
127
            set { _header.Name = value; }
128
        }
129

    
130
        /// <summary>
131
        /// Get/set this entry's user id.
132
        /// </summary>
133
        public int UserId
134
        {
135
            get { return _header.UserId; }
136
            set { _header.UserId = value; }
137
        }
138

    
139
        /// <summary>
140
        /// Get/set this entry's group id.
141
        /// </summary>
142
        public int GroupId
143
        {
144
            get { return _header.GroupId; }
145
            set { _header.GroupId = value; }
146
        }
147

    
148
        /// <summary>
149
        /// Get/set this entry's user name.
150
        /// </summary>
151
        public string UserName
152
        {
153
            get { return _header.UserName; }
154
            set { _header.UserName = value; }
155
        }
156

    
157
        /// <summary>
158
        /// Get/set this entry's group name.
159
        /// </summary>
160
        public string GroupName
161
        {
162
            get { return _header.GroupName; }
163
            set { _header.GroupName = value; }
164
        }
165

    
166
        /// <summary>
167
        /// Get/Set the modification time for this entry
168
        /// </summary>
169
        public DateTime ModTime
170
        {
171
            get { return _header.ModTime; }
172
            set { _header.ModTime = value; }
173
        }
174

    
175
        /// <summary>
176
        /// Get this entry's _file.
177
        /// </summary>
178
        /// <returns>
179
        /// This entry's _file.
180
        /// </returns>
181
        public string File
182
        {
183
            get { return _file; }
184
        }
185

    
186
        /// <summary>
187
        /// Get/set this entry's recorded _file size.
188
        /// </summary>
189
        public long Size
190
        {
191
            get { return _header.Size; }
192
            set { _header.Size = value; }
193
        }
194

    
195
        /// <summary>
196
        /// Return true if this entry represents a directory, false otherwise
197
        /// </summary>
198
        /// <returns>
199
        /// True if this entry is a directory.
200
        /// </returns>
201
        public bool IsDirectory
202
        {
203
            get
204
            {
205
                if (_file != null)
206
                {
207
                    return Directory.Exists(_file);
208
                }
209

    
210
                if (_header != null)
211
                {
212
                    if ((_header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith("/"))
213
                    {
214
                        return true;
215
                    }
216
                }
217
                return false;
218
            }
219
        }
220

    
221
        /// <summary>
222
        /// Clone this tar entry.
223
        /// </summary>
224
        /// <returns>Returns a clone of this entry.</returns>
225
        public object Clone()
226
        {
227
            var entry = new TarEntry{_file = _file, _header = ((TarHeader) _header.Clone()), Name = Name};
228
            return entry;
229
        }
230

    
231
        /// <summary>
232
        /// Construct an entry with only a <paramref name="name">name</paramref>.
233
        /// This allows the programmer to construct the entry's _header "by hand". 
234
        /// </summary>
235
        /// <param name="name">The name to use for the entry</param>
236
        /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
237
        public static TarEntry CreateTarEntry(string name)
238
        {
239
            var entry = new TarEntry();
240
            NameTarHeader(entry._header, name);
241
            return entry;
242
        }
243

    
244
        /// <summary>
245
        /// Construct an entry for a _file. File is set to _file, and the
246
        /// _header is constructed from information from the _file.
247
        /// </summary>
248
        /// <param name = "fileName">The _file name that the entry represents.</param>
249
        /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
250
        public static TarEntry CreateEntryFromFile(string fileName)
251
        {
252
            var entry = new TarEntry();
253
            entry.GetFileTarHeader(entry._header, fileName);
254
            return entry;
255
        }
256

    
257
        /// <summary>
258
        /// Determine if the two entries are equal. Equality is determined
259
        /// by the _header names being equal.
260
        /// </summary>
261
        /// <param name="obj">The <see cref="object"/> to compare with the current Object.</param>
262
        /// <returns>
263
        /// True if the entries are equal; false if not.
264
        /// </returns>
265
        public override bool Equals(object obj)
266
        {
267
            var localEntry = obj as TarEntry;
268

    
269
            if (localEntry != null)
270
            {
271
                return Name.Equals(localEntry.Name);
272
            }
273
            return false;
274
        }
275

    
276
        /// <summary>
277
        /// Derive a Hash value for the current <see cref="object"/>
278
        /// </summary>
279
        /// <returns>A Hash code for the current <see cref="object"/></returns>
280
        public override int GetHashCode()
281
        {
282
            return Name.GetHashCode();
283
        }
284

    
285
        /// <summary>
286
        /// Determine if the given entry is a descendant of this entry.
287
        /// Descendancy is determined by the name of the descendant
288
        /// starting with this entry's name.
289
        /// </summary>
290
        /// <param name = "toTest">
291
        /// Entry to be checked as a descendent of this.
292
        /// </param>
293
        /// <returns>
294
        /// True if entry is a descendant of this.
295
        /// </returns>
296
        public bool IsDescendent(TarEntry toTest)
297
        {
298
            if (toTest == null)
299
            {
300
                throw new ArgumentNullException("toTest");
301
            }
302

    
303
            return toTest.Name.StartsWith(Name);
304
        }
305

    
306
        /// <summary>
307
        /// Convenience method to set this entry's group and user ids.
308
        /// </summary>
309
        /// <param name="userId">
310
        /// This entry's new user id.
311
        /// </param>
312
        /// <param name="groupId">
313
        /// This entry's new group id.
314
        /// </param>
315
        public void SetIds(int userId, int groupId)
316
        {
317
            UserId = userId;
318
            GroupId = groupId;
319
        }
320

    
321
        /// <summary>
322
        /// Convenience method to set this entry's group and user names.
323
        /// </summary>
324
        /// <param name="userName">
325
        /// This entry's new user name.
326
        /// </param>
327
        /// <param name="groupName">
328
        /// This entry's new group name.
329
        /// </param>
330
        public void SetNames(string userName, string groupName)
331
        {
332
            UserName = userName;
333
            GroupName = groupName;
334
        }
335

    
336
        /// <summary>
337
        /// Fill in a TarHeader with information from a File.
338
        /// </summary>
339
        /// <param name="header">
340
        /// The TarHeader to fill in.
341
        /// </param>
342
        /// <param name="file">
343
        /// The _file from which to get the _header information.
344
        /// </param>
345
        public void GetFileTarHeader(TarHeader header, string file)
346
        {
347
            if (header == null)
348
            {
349
                throw new ArgumentNullException("header");
350
            }
351

    
352
            if (file == null)
353
            {
354
                throw new ArgumentNullException("file");
355
            }
356

    
357
            _file = file;
358

    
359
            // bugfix from torhovl from #D forum:
360
            var name = file;
361

    
362
            // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
363
            if (name.IndexOf(Environment.CurrentDirectory) == 0)
364
            {
365
                name = name.Substring(Environment.CurrentDirectory.Length);
366
            }
367
/*
368
			if (Path.DirectorySeparatorChar == '\\') 
369
			{
370
				// check if the OS is Windows
371
				// Strip off drive letters!
372
				if (name.Length > 2) 
373
				{
374
					char ch1 = name[0];
375
					char ch2 = name[1];
376
					
377
					if (ch2 == ':' && Char.IsLetter(ch1)) 
378
					{
379
						name = name.Substring(2);
380
					}
381
				}
382
			}
383
*/
384

    
385
            name = name.Replace(Path.DirectorySeparatorChar, '/');
386

    
387
            // No absolute pathnames
388
            // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
389
            // so we loop on starting /'s.
390
            while (name.StartsWith("/"))
391
            {
392
                name = name.Substring(1);
393
            }
394

    
395
            header.LinkName = String.Empty;
396
            header.Name = name;
397

    
398
            if (Directory.Exists(file))
399
            {
400
                header.Mode = 1003; // Magic number for security access for a UNIX filesystem
401
                header.TypeFlag = TarHeader.LF_DIR;
402
                if ((header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/')
403
                {
404
                    header.Name = header.Name + "/";
405
                }
406

    
407
                header.Size = 0;
408
            }
409
            else
410
            {
411
                header.Mode = 33216; // Magic number for security access for a UNIX filesystem
412
                header.TypeFlag = TarHeader.LF_NORMAL;
413
                header.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
414
            }
415

    
416
            header.ModTime =
417
                System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime();
418
            header.DevMajor = 0;
419
            header.DevMinor = 0;
420
        }
421

    
422
        /// <summary>
423
        /// Get entries for all files present in this entries directory.
424
        /// If this entry doesnt represent a directory zero entries are returned.
425
        /// </summary>
426
        /// <returns>
427
        /// An array of TarEntry's for this entry's children.
428
        /// </returns>
429
        public TarEntry[] GetDirectoryEntries()
430
        {
431
            if ((_file == null) || !Directory.Exists(_file))
432
            {
433
                return new TarEntry[0];
434
            }
435

    
436
#if !SL4
437
            var list = Directory.GetFileSystemEntries(_file);
438
#else
439
            var list = Directory.EnumerateFileSystemEntries(_file).ToArray();
440
#endif
441
            var result = new TarEntry[list.Length];
442

    
443
            for (var i = 0; i < list.Length; ++i)
444
            {
445
                result[i] = CreateEntryFromFile(list[i]);
446
            }
447

    
448
            return result;
449
        }
450

    
451
        /// <summary>
452
        /// Write an entry's _header information to a _header buffer.
453
        /// </summary>
454
        /// <param name = "outBuffer">
455
        /// The tar entry _header buffer to fill in.
456
        /// </param>
457
        public void WriteEntryHeader(byte[] outBuffer)
458
        {
459
            _header.WriteHeader(outBuffer);
460
        }
461

    
462
        /// <summary>
463
        /// Convenience method that will modify an entry's name directly
464
        /// in place in an entry _header buffer byte array.
465
        /// </summary>
466
        /// <param name="buffer">
467
        /// The buffer containing the entry _header to modify.
468
        /// </param>
469
        /// <param name="newName">
470
        /// The new name to place into the _header buffer.
471
        /// </param>
472
        public static void AdjustEntryName(byte[] buffer, string newName)
473
        {
474
            var offset = 0;
475
            TarHeader.GetNameBytes(newName, buffer, offset, TarHeader.NAMELEN);
476
        }
477

    
478
        /// <summary>
479
        /// Fill in a TarHeader given only the entry's name.
480
        /// </summary>
481
        /// <param name="header">
482
        /// The TarHeader to fill in.
483
        /// </param>
484
        /// <param name="name">
485
        /// The tar entry name.
486
        /// </param>
487
        public static void NameTarHeader(TarHeader header, string name)
488
        {
489
            if (header == null)
490
            {
491
                throw new ArgumentNullException("header");
492
            }
493

    
494
            if (name == null)
495
            {
496
                throw new ArgumentNullException("name");
497
            }
498

    
499
            var isDir = name.EndsWith("/");
500

    
501
            header.Name = name;
502
            header.Mode = isDir ? 1003 : 33216;
503
            header.UserId = 0;
504
            header.GroupId = 0;
505
            header.Size = 0;
506

    
507
            header.ModTime = DateTime.UtcNow;
508

    
509
            header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
510

    
511
            header.LinkName = String.Empty;
512
            header.UserName = String.Empty;
513
            header.GroupName = String.Empty;
514

    
515
            header.DevMajor = 0;
516
            header.DevMinor = 0;
517
        }
518

    
519
        #region Instance Fields
520

    
521
        /// <summary>
522
        /// The name of the _file this entry represents or null if the entry is not based on a _file.
523
        /// </summary>
524
        private string _file;
525

    
526
        /// <summary>
527
        /// The entry's _header information.
528
        /// </summary>
529
        private TarHeader _header;
530

    
531
        #endregion
532
    }
533
}
534

    
535
/* The original Java file had this header:
536
	*
537
	** Authored by Timothy Gerard Endres
538
	** <mailto:time@gjt.org>  <http://www.trustice.com>
539
	**
540
	** This work has been placed into the public domain.
541
	** You may use this work in any way and for any purpose you wish.
542
	**
543
	** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
544
	** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
545
	** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
546
	** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
547
	** REDISTRIBUTION OF THIS SOFTWARE.
548
	**
549
	*/