root/trunk/Updater/ICSharpCode.SharpZipLib/Tar/TarEntry.cs @ 597

Wersja 597, 15.3 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
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
36using System;
37using System.IO;
38using System.Text;
39
40namespace ICSharpCode.SharpZipLib.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 : ICloneable
70        {
71                #region Constructors
72                /// <summary>
73                /// Initialise a default instance of <see cref="TarEntry"/>.
74                /// </summary>
75                private TarEntry()
76                {
77                        header = new TarHeader();
78                }
79               
80                /// <summary>
81                /// Construct an entry from an archive's header bytes. File is set
82                /// to null.
83                /// </summary>
84                /// <param name = "headerBuffer">
85                /// The header bytes from a tar archive entry.
86                /// </param>
87                public TarEntry(byte[] headerBuffer)
88                {
89                        header = new TarHeader();
90                        header.ParseBuffer(headerBuffer);
91                }
92               
93                /// <summary>
94                /// Construct a TarEntry using the <paramref name="header">header</paramref> provided
95                /// </summary>
96                /// <param name="header">Header details for entry</param>
97                public TarEntry(TarHeader header)
98                {
99                        if ( header == null )
100                        {
101                                throw new ArgumentNullException("header");
102                        }
103
104                        this.header = (TarHeader)header.Clone();
105                }
106                #endregion
107
108                #region ICloneable Members
109                /// <summary>
110                /// Clone this tar entry.
111                /// </summary>
112                /// <returns>Returns a clone of this entry.</returns>
113                public object Clone()
114                {
115                        TarEntry entry = new TarEntry();
116                        entry.file = file;
117                        entry.header = (TarHeader)header.Clone();
118                        entry.Name = Name;
119                        return entry;
120                }
121                #endregion
122
123                /// <summary>
124                /// Construct an entry with only a <paramref name="name">name</paramref>.
125                /// This allows the programmer to construct the entry's header "by hand".
126                /// </summary>
127                /// <param name="name">The name to use for the entry</param>
128                /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
129                public static TarEntry CreateTarEntry(string name)
130                {
131                        TarEntry entry = new TarEntry();
132                        TarEntry.NameTarHeader(entry.header, name);
133                        return entry;
134                }
135               
136                /// <summary>
137                /// Construct an entry for a file. File is set to file, and the
138                /// header is constructed from information from the file.
139                /// </summary>
140                /// <param name = "fileName">The file name that the entry represents.</param>
141                /// <returns>Returns the newly created <see cref="TarEntry"/></returns>
142                public static TarEntry CreateEntryFromFile(string fileName)
143                {
144                        TarEntry entry = new TarEntry();
145                        entry.GetFileTarHeader(entry.header, fileName);
146                        return entry;
147                }
148               
149                /// <summary>
150                /// Determine if the two entries are equal. Equality is determined
151                /// by the header names being equal.
152                /// </summary>
153                /// <param name="obj">The <see cref="Object"/> to compare with the current Object.</param>
154                /// <returns>
155                /// True if the entries are equal; false if not.
156                /// </returns>
157                public override bool Equals(object obj)
158                {
159                        TarEntry localEntry = obj as TarEntry;
160
161                        if ( localEntry != null )
162                        {
163                                return Name.Equals(localEntry.Name);
164                        }
165                        return false;
166                }
167               
168                /// <summary>
169                /// Derive a Hash value for the current <see cref="Object"/>
170                /// </summary>
171                /// <returns>A Hash code for the current <see cref="Object"/></returns>
172                public override int GetHashCode()
173                {
174                        return Name.GetHashCode();
175                }
176               
177                /// <summary>
178                /// Determine if the given entry is a descendant of this entry.
179                /// Descendancy is determined by the name of the descendant
180                /// starting with this entry's name.
181                /// </summary>
182                /// <param name = "toTest">
183                /// Entry to be checked as a descendent of this.
184                /// </param>
185                /// <returns>
186                /// True if entry is a descendant of this.
187                /// </returns>
188                public bool IsDescendent(TarEntry toTest)
189                {
190                        if ( toTest == null ) {
191                                throw new ArgumentNullException("toTest");
192                        }
193
194                        return toTest.Name.StartsWith(Name);
195                }
196               
197                /// <summary>
198                /// Get this entry's header.
199                /// </summary>
200                /// <returns>
201                /// This entry's TarHeader.
202                /// </returns>
203                public TarHeader TarHeader
204                {
205                        get {
206                                return header;
207                        }
208                }
209               
210                /// <summary>
211                /// Get/Set this entry's name.
212                /// </summary>
213                public string Name
214                {
215                        get {
216                                return header.Name;
217                        }
218                        set {
219                                header.Name = value;
220                        }
221                }
222               
223                /// <summary>
224                /// Get/set this entry's user id.
225                /// </summary>
226                public int UserId
227                {
228                        get {
229                                return header.UserId;
230                        }
231                        set {
232                                header.UserId = value;
233                        }
234                }
235               
236                /// <summary>
237                /// Get/set this entry's group id.
238                /// </summary>
239                public int GroupId
240                {
241                        get {
242                                return header.GroupId;
243                        }
244                        set {
245                                header.GroupId = value;
246                        }
247                }
248               
249                /// <summary>
250                /// Get/set this entry's user name.
251                /// </summary>
252                public string UserName
253                {
254                        get {
255                                return header.UserName;
256                        }
257                        set {
258                                header.UserName = value;
259                        }
260                }
261               
262                /// <summary>
263                /// Get/set this entry's group name.
264                /// </summary>
265                public string GroupName
266                {
267                        get {
268                                return header.GroupName;
269                        }
270                        set {
271                                header.GroupName = value;
272                        }
273                }
274               
275                /// <summary>
276                /// Convenience method to set this entry's group and user ids.
277                /// </summary>
278                /// <param name="userId">
279                /// This entry's new user id.
280                /// </param>
281                /// <param name="groupId">
282                /// This entry's new group id.
283                /// </param>
284                public void SetIds(int userId, int groupId)
285                {
286                        UserId  = userId;
287                        GroupId = groupId;
288                }
289               
290                /// <summary>
291                /// Convenience method to set this entry's group and user names.
292                /// </summary>
293                /// <param name="userName">
294                /// This entry's new user name.
295                /// </param>
296                /// <param name="groupName">
297                /// This entry's new group name.
298                /// </param>
299                public void SetNames(string userName, string groupName)
300                {
301                        UserName  = userName;
302                        GroupName = groupName;
303                }
304
305                /// <summary>
306                /// Get/Set the modification time for this entry
307                /// </summary>
308                public DateTime ModTime {
309                        get {
310                                return header.ModTime;
311                        }
312                        set {
313                                header.ModTime = value;
314                        }
315                }
316               
317                /// <summary>
318                /// Get this entry's file.
319                /// </summary>
320                /// <returns>
321                /// This entry's file.
322                /// </returns>
323                public string File {
324                        get {
325                                return file;
326                        }
327                }
328               
329                /// <summary>
330                /// Get/set this entry's recorded file size.
331                /// </summary>
332                public long Size {
333                        get {
334                                return header.Size;
335                        }
336                        set {
337                                header.Size = value;
338                        }
339                }
340               
341                /// <summary>
342                /// Return true if this entry represents a directory, false otherwise
343                /// </summary>
344                /// <returns>
345                /// True if this entry is a directory.
346                /// </returns>
347                public bool IsDirectory {
348                        get {
349                                if (file != null) {
350                                        return Directory.Exists(file);
351                                }
352                               
353                                if (header != null) {
354                                        if ((header.TypeFlag == TarHeader.LF_DIR) || Name.EndsWith( "/" )) {
355                                                return true;
356                                        }
357                                }
358                                return false;
359                        }
360                }
361               
362                /// <summary>
363                /// Fill in a TarHeader with information from a File.
364                /// </summary>
365                /// <param name="header">
366                /// The TarHeader to fill in.
367                /// </param>
368                /// <param name="file">
369                /// The file from which to get the header information.
370                /// </param>
371                public void GetFileTarHeader(TarHeader header, string file)
372                {
373                        if ( header == null ) {
374                                throw new ArgumentNullException("header");
375                        }
376
377                        if ( file == null ) {
378                                throw new ArgumentNullException("file");
379                        }
380
381                        this.file = file;
382
383                        // bugfix from torhovl from #D forum:
384                        string name = file;
385
386#if !NETCF_1_0 && !NETCF_2_0
387                        // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
388                        if (name.IndexOf(Environment.CurrentDirectory) == 0) {
389                                name = name.Substring(Environment.CurrentDirectory.Length);
390                        }
391#endif
392                       
393/*
394                        if (Path.DirectorySeparatorChar == '\\')
395                        {
396                                // check if the OS is Windows
397                                // Strip off drive letters!
398                                if (name.Length > 2)
399                                {
400                                        char ch1 = name[0];
401                                        char ch2 = name[1];
402                                       
403                                        if (ch2 == ':' && Char.IsLetter(ch1))
404                                        {
405                                                name = name.Substring(2);
406                                        }
407                                }
408                        }
409*/
410
411                        name = name.Replace(Path.DirectorySeparatorChar, '/');
412
413                        // No absolute pathnames
414                        // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
415                        // so we loop on starting /'s.
416                        while (name.StartsWith("/")) {
417                                name = name.Substring(1);
418                        }
419
420                        header.LinkName = String.Empty;
421                        header.Name     = name;
422                       
423                        if (Directory.Exists(file)) {
424                                header.Mode     = 1003; // Magic number for security access for a UNIX filesystem
425                                header.TypeFlag = TarHeader.LF_DIR;
426                                if ( (header.Name.Length == 0) || header.Name[header.Name.Length - 1] != '/') {
427                                        header.Name = header.Name + "/";
428                                }
429                               
430                                header.Size     = 0;
431                        } else {
432                                header.Mode     = 33216; // Magic number for security access for a UNIX filesystem
433                                header.TypeFlag = TarHeader.LF_NORMAL;
434                                header.Size     = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
435                        }
436
437                        header.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime();
438                        header.DevMajor = 0;
439                        header.DevMinor = 0;
440                }
441               
442                /// <summary>
443                /// Get entries for all files present in this entries directory.
444                /// If this entry doesnt represent a directory zero entries are returned.
445                /// </summary>
446                /// <returns>
447                /// An array of TarEntry's for this entry's children.
448                /// </returns>
449                public TarEntry[] GetDirectoryEntries()
450                {
451                        if ( (file == null) || !Directory.Exists(file)) {
452                                return new TarEntry[0];
453                        }
454                       
455                        string[]   list   = Directory.GetFileSystemEntries(file);
456                        TarEntry[] result = new TarEntry[list.Length];
457
458                        for (int i = 0; i < list.Length; ++i) {
459                                result[i] = TarEntry.CreateEntryFromFile(list[i]);
460                        }
461                       
462                        return result;
463                }
464               
465                /// <summary>
466                /// Write an entry's header information to a header buffer.
467                /// </summary>
468                /// <param name = "outBuffer">
469                /// The tar entry header buffer to fill in.
470                /// </param>
471                public void WriteEntryHeader(byte[] outBuffer)
472                {
473                        header.WriteHeader(outBuffer);
474                }
475               
476                /// <summary>
477                /// Convenience method that will modify an entry's name directly
478                /// in place in an entry header buffer byte array.
479                /// </summary>
480                /// <param name="buffer">
481                /// The buffer containing the entry header to modify.
482                /// </param>
483                /// <param name="newName">
484                /// The new name to place into the header buffer.
485                /// </param>
486                static public void AdjustEntryName(byte[] buffer, string newName)
487                {
488                        int offset = 0;
489                        TarHeader.GetNameBytes(newName, buffer, offset, TarHeader.NAMELEN);
490                }
491               
492                /// <summary>
493                /// Fill in a TarHeader given only the entry's name.
494                /// </summary>
495                /// <param name="header">
496                /// The TarHeader to fill in.
497                /// </param>
498                /// <param name="name">
499                /// The tar entry name.
500                /// </param>
501                static public void NameTarHeader(TarHeader header, string name)
502                {
503                        if ( header == null ) {
504                                throw new ArgumentNullException("header");
505                        }
506
507                        if ( name == null ) {
508                                throw new ArgumentNullException("name");
509                        }
510
511                        bool isDir = name.EndsWith("/");
512                       
513                        header.Name = name;
514                        header.Mode = isDir ? 1003 : 33216;
515                        header.UserId   = 0;
516                        header.GroupId  = 0;
517                        header.Size     = 0;
518                       
519                        header.ModTime  = DateTime.UtcNow;
520                       
521                        header.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
522                       
523                        header.LinkName  = String.Empty;
524                        header.UserName  = String.Empty;
525                        header.GroupName = String.Empty;
526                       
527                        header.DevMajor = 0;
528                        header.DevMinor = 0;
529                }
530
531                #region Instance Fields
532                /// <summary>
533                /// The name of the file this entry represents or null if the entry is not based on a file.
534                /// </summary>
535                string file;
536               
537                /// <summary>
538                /// The entry's header information.
539                /// </summary>
540                TarHeader       header;
541                #endregion
542        }
543}
544
545
546
547/* The original Java file had this header:
548        *
549        ** Authored by Timothy Gerard Endres
550        ** <mailto:time@gjt.org>  <http://www.trustice.com>
551        **
552        ** This work has been placed into the public domain.
553        ** You may use this work in any way and for any purpose you wish.
554        **
555        ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
556        ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
557        ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
558        ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
559        ** REDISTRIBUTION OF THIS SOFTWARE.
560        **
561        */
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.