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

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

re #165

RevLine 
[597]1// TarArchive.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        /// Used to advise clients of 'events' while processing archives
44        /// </summary>
45        public delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message);
46
47        /// <summary>
48        /// The TarArchive class implements the concept of a
49        /// 'Tape Archive'. A tar archive is a series of entries, each of
50        /// which represents a file system object. Each entry in
51        /// the archive consists of a header block followed by 0 or more data blocks.
52        /// Directory entries consist only of the header block, and are followed by entries
53        /// for the directory's contents. File entries consist of a
54        /// header followed by the number of blocks needed to
55        /// contain the file's contents. All entries are written on
56        /// block boundaries. Blocks are 512 bytes long.
57        ///
58        /// TarArchives are instantiated in either read or write mode,
59        /// based upon whether they are instantiated with an InputStream
60        /// or an OutputStream. Once instantiated TarArchives read/write
61        /// mode can not be changed.
62        ///
63        /// There is currently no support for random access to tar archives.
64        /// However, it seems that subclassing TarArchive, and using the
65        /// TarBuffer.CurrentRecord and TarBuffer.CurrentBlock
66        /// properties, this would be rather trivial.
67        /// </summary>
68        public class TarArchive : IDisposable
69        {
70                /// <summary>
71                /// Client hook allowing detailed information to be reported during processing
72                /// </summary>
73                public event ProgressMessageHandler ProgressMessageEvent;
74               
75                /// <summary>
76                /// Raises the ProgressMessage event
77                /// </summary>
78                /// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
79                /// <param name="message">message for this event.  Null is no message</param>
80                protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
81                {
82                        if (ProgressMessageEvent != null) {
83                                ProgressMessageEvent(this, entry, message);
84                        }
85                }
86               
87                #region Constructors
88                /// <summary>
89                /// Constructor for a default <see cref="TarArchive"/>.
90                /// </summary>
91                protected TarArchive()
92                {
93                }
94               
95                /// <summary>
96                /// Initalise a TarArchive for input.
97                /// </summary>
98                /// <param name="stream">The <see cref="TarInputStream"/> to use for input.</param>
99                protected TarArchive(TarInputStream stream)
100                {
101                        if ( stream == null ) {
102                                throw new ArgumentNullException("stream");
103                        }
104                       
105                        tarIn = stream;
106                }
107               
108                /// <summary>
109                /// Initialise a TarArchive for output.
110                /// </summary>
111                /// <param name="stream">The <see cref="TarOutputStream"/> to use for output.</param>
112                protected TarArchive(TarOutputStream stream)
113                {
114                        if ( stream == null ) {
115                                throw new ArgumentNullException("stream");
116                        }
117                       
118                        tarOut = stream;
119                }
120                #endregion
121               
122                #region Static factory methods
123                /// <summary>
124                /// The InputStream based constructors create a TarArchive for the
125                /// purposes of extracting or listing a tar archive. Thus, use
126                /// these constructors when you wish to extract files from or list
127                /// the contents of an existing tar archive.
128                /// </summary>
129                /// <param name="inputStream">The stream to retrieve archive data from.</param>
130                /// <returns>Returns a new <see cref="TarArchive"/> suitable for reading from.</returns>
131                public static TarArchive CreateInputTarArchive(Stream inputStream)
132                {
133                        if ( inputStream == null ) {
134                                throw new ArgumentNullException("inputStream");
135                        }
136
137                        TarInputStream tarStream = inputStream as TarInputStream;
138
139                        if ( tarStream != null ) {
140                                return new TarArchive(tarStream);
141                        }
142                        else {
143                                return CreateInputTarArchive(inputStream, TarBuffer.DefaultBlockFactor);
144                        }
145                }
146               
147                /// <summary>
148                /// Create TarArchive for reading setting block factor
149                /// </summary>
150                /// <param name="inputStream">A stream containing the tar archive contents</param>
151                /// <param name="blockFactor">The blocking factor to apply</param>
152                /// <returns>Returns a <see cref="TarArchive"/> suitable for reading.</returns>
153                public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor)
154                {
155                        if ( inputStream == null ) {
156                                throw new ArgumentNullException("inputStream");
157                        }
158
159                        if ( inputStream is TarInputStream ) {
160                                throw new ArgumentException("TarInputStream not valid");
161                        }
162                       
163                        return new TarArchive(new TarInputStream(inputStream, blockFactor));
164                }
165               
166                /// <summary>
167                /// Create a TarArchive for writing to, using the default blocking factor
168                /// </summary>
169                /// <param name="outputStream">The <see cref="Stream"/> to write to</param>
170                /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
171                public static TarArchive CreateOutputTarArchive(Stream outputStream)
172                {
173                        if ( outputStream == null ) {
174                                throw new ArgumentNullException("outputStream");
175                        }
176                        TarOutputStream tarStream = outputStream as TarOutputStream;
177                        if ( tarStream != null ) {
178                                return new TarArchive(tarStream);
179                        }
180                        else {
181                                return CreateOutputTarArchive(outputStream, TarBuffer.DefaultBlockFactor);
182                        }
183                }
184
185                /// <summary>
186                /// Create a <see cref="TarArchive">tar archive</see> for writing.
187                /// </summary>
188                /// <param name="outputStream">The stream to write to</param>
189                /// <param name="blockFactor">The blocking factor to use for buffering.</param>
190                /// <returns>Returns a <see cref="TarArchive"/> suitable for writing.</returns>
191                public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor)
192                {
193                        if ( outputStream == null ) {
194                                throw new ArgumentNullException("outputStream");
195                        }
196
197                        if ( outputStream is TarOutputStream ) {
198                                throw new ArgumentException("TarOutputStream is not valid");
199                        }
200
201                        return new TarArchive(new TarOutputStream(outputStream, blockFactor));
202                }
203                #endregion
204               
205                /// <summary>
206                /// Set the flag that determines whether existing files are
207                /// kept, or overwritten during extraction.
208                /// </summary>
209                /// <param name="keepOldFiles">
210                /// If true, do not overwrite existing files.
211                /// </param>
212                public void SetKeepOldFiles(bool keepOldFiles)
213                {
214                        if ( isDisposed ) {
215                                throw new ObjectDisposedException("TarArchive");
216                        }
217                       
218                        this.keepOldFiles = keepOldFiles;
219                }
220               
221                /// <summary>
222                /// Get/set the ascii file translation flag. If ascii file translation
223                /// is true, then the file is checked to see if it a binary file or not.
224                /// If the flag is true and the test indicates it is ascii text
225                /// file, it will be translated. The translation converts the local
226                /// operating system's concept of line ends into the UNIX line end,
227                /// '\n', which is the defacto standard for a TAR archive. This makes
228                /// text files compatible with UNIX.
229                /// </summary>
230                public bool AsciiTranslate
231                {
232                        get {
233                                if ( isDisposed ) {
234                                        throw new ObjectDisposedException("TarArchive");
235                                }
236                       
237                                return asciiTranslate;
238                        }
239                       
240                        set {
241                                if ( isDisposed ) {
242                                        throw new ObjectDisposedException("TarArchive");
243                                }
244                       
245                                asciiTranslate = value;
246                        }
247               
248                }
249               
250                /// <summary>
251                /// Set the ascii file translation flag.
252                /// </summary>
253                /// <param name= "asciiTranslate">
254                /// If true, translate ascii text files.
255                /// </param>
256                [Obsolete("Use the AsciiTranslate property")]
257                public void SetAsciiTranslation(bool asciiTranslate)
258                {
259                        if ( isDisposed ) {
260                                throw new ObjectDisposedException("TarArchive");
261                        }
262                       
263                        this.asciiTranslate = asciiTranslate;
264                }
265
266                /// <summary>
267                /// PathPrefix is added to entry names as they are written if the value is not null.
268                /// A slash character is appended after PathPrefix
269                /// </summary>
270                public string PathPrefix
271                {
272                        get {
273                                if ( isDisposed ) {
274                                        throw new ObjectDisposedException("TarArchive");
275                                }
276                       
277                                return pathPrefix;
278                        }
279                       
280                        set {
281                                if ( isDisposed ) {
282                                        throw new ObjectDisposedException("TarArchive");
283                                }
284                       
285                                pathPrefix = value;
286                        }
287               
288                }
289               
290                /// <summary>
291                /// RootPath is removed from entry names if it is found at the
292                /// beginning of the name.
293                /// </summary>
294                public string RootPath
295                {
296                        get {
297                                if ( isDisposed ) {
298                                        throw new ObjectDisposedException("TarArchive");
299                                }
300                       
301                                return rootPath;
302                        }
303
304                        set {
305                                if ( isDisposed ) {
306                                        throw new ObjectDisposedException("TarArchive");
307                                }
308                       
309                                rootPath = value;
310                        }
311                }
312               
313                /// <summary>
314                /// Set user and group information that will be used to fill in the
315                /// tar archive's entry headers. This information based on that available
316                /// for the linux operating system, which is not always available on other
317                /// operating systems.  TarArchive allows the programmer to specify values
318                /// to be used in their place.
319                /// <see cref="ApplyUserInfoOverrides"/> is set to true by this call.
320                /// </summary>
321                /// <param name="userId">
322                /// The user id to use in the headers.
323                /// </param>
324                /// <param name="userName">
325                /// The user name to use in the headers.
326                /// </param>
327                /// <param name="groupId">
328                /// The group id to use in the headers.
329                /// </param>
330                /// <param name="groupName">
331                /// The group name to use in the headers.
332                /// </param>
333                public void SetUserInfo(int userId, string userName, int groupId, string groupName)
334                {
335                        if ( isDisposed ) {
336                                throw new ObjectDisposedException("TarArchive");
337                        }
338                       
339                        this.userId    = userId;
340                        this.userName  = userName;
341                        this.groupId   = groupId;
342                        this.groupName = groupName;
343                        applyUserInfoOverrides = true;
344                }
345               
346                /// <summary>
347                /// Get or set a value indicating if overrides defined by <see cref="SetUserInfo">SetUserInfo</see> should be applied.
348                /// </summary>
349                /// <remarks>If overrides are not applied then the values as set in each header will be used.</remarks>
350                public bool ApplyUserInfoOverrides
351                {
352                        get {
353                                if ( isDisposed ) {
354                                        throw new ObjectDisposedException("TarArchive");
355                                }
356                       
357                                return applyUserInfoOverrides;
358                        }
359
360                        set {
361                                if ( isDisposed ) {
362                                        throw new ObjectDisposedException("TarArchive");
363                                }
364                       
365                                applyUserInfoOverrides = value;
366                        }
367                }
368
369                /// <summary>
370                /// Get the archive user id.
371                /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
372                /// on how to allow setting values on a per entry basis.
373                /// </summary>
374                /// <returns>
375                /// The current user id.
376                /// </returns>
377                public int UserId {
378                        get {
379                                if ( isDisposed ) {
380                                        throw new ObjectDisposedException("TarArchive");
381                                }
382                       
383                                return userId;
384                        }
385                }
386               
387                /// <summary>
388                /// Get the archive user name.
389                /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
390                /// on how to allow setting values on a per entry basis.
391                /// </summary>
392                /// <returns>
393                /// The current user name.
394                /// </returns>
395                public string UserName {
396                        get {
397                                if ( isDisposed ) {
398                                        throw new ObjectDisposedException("TarArchive");
399                                }
400                       
401                                return userName;
402                        }
403                }
404               
405                /// <summary>
406                /// Get the archive group id.
407                /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
408                /// on how to allow setting values on a per entry basis.
409                /// </summary>
410                /// <returns>
411                /// The current group id.
412                /// </returns>
413                public int GroupId {
414                        get {
415                                if ( isDisposed ) {
416                                        throw new ObjectDisposedException("TarArchive");
417                                }
418                       
419                                return this.groupId;
420                        }
421                }
422               
423                /// <summary>
424                /// Get the archive group name.
425                /// See <see cref="ApplyUserInfoOverrides">ApplyUserInfoOverrides</see> for detail
426                /// on how to allow setting values on a per entry basis.
427                /// </summary>
428                /// <returns>
429                /// The current group name.
430                /// </returns>
431                public string GroupName {
432                        get {
433                                if ( isDisposed ) {
434                                        throw new ObjectDisposedException("TarArchive");
435                                }
436                       
437                                return this.groupName;
438                        }
439                }
440               
441                /// <summary>
442                /// Get the archive's record size. Tar archives are composed of
443                /// a series of RECORDS each containing a number of BLOCKS.
444                /// This allowed tar archives to match the IO characteristics of
445                /// the physical device being used. Archives are expected
446                /// to be properly "blocked".
447                /// </summary>
448                /// <returns>
449                /// The record size this archive is using.
450                /// </returns>
451                public int RecordSize {
452                        get {
453                                if ( isDisposed ) {
454                                        throw new ObjectDisposedException("TarArchive");
455                                }
456                               
457                                if (tarIn != null) {
458                                        return tarIn.RecordSize;
459                                } else if (tarOut != null) {
460                                        return tarOut.RecordSize;
461                                }
462                                return TarBuffer.DefaultRecordSize;
463                        }
464                }
465               
466                /// <summary>
467                /// Close the archive.
468                /// </summary>
469                [Obsolete("Use Close instead")]
470                public void CloseArchive()
471                {
472                        Close();
473                }
474               
475                /// <summary>
476                /// Perform the "list" command for the archive contents.
477                ///
478                /// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list
479                /// the contents. If the progress display event is not set, nothing will be listed!
480                /// </summary>
481                public void ListContents()
482                {
483                        if ( isDisposed ) {
484                                throw new ObjectDisposedException("TarArchive");
485                        }
486                       
487                        while (true) {
488                                TarEntry entry = this.tarIn.GetNextEntry();
489                               
490                                if (entry == null) {
491                                        break;
492                                }
493                                OnProgressMessageEvent(entry, null);
494                        }
495                }
496               
497                /// <summary>
498                /// Perform the "extract" command and extract the contents of the archive.
499                /// </summary>
500                /// <param name="destinationDirectory">
501                /// The destination directory into which to extract.
502                /// </param>
503                public void ExtractContents(string destinationDirectory)
504                {
505                        if ( isDisposed ) {
506                                throw new ObjectDisposedException("TarArchive");
507                        }
508                       
509                        while (true) {
510                                TarEntry entry = this.tarIn.GetNextEntry();
511                               
512                                if (entry == null) {
513                                        break;
514                                }
515                               
516                                this.ExtractEntry(destinationDirectory, entry);
517                        }
518                }
519               
520                /// <summary>
521                /// Extract an entry from the archive. This method assumes that the
522                /// tarIn stream has been properly set with a call to GetNextEntry().
523                /// </summary>
524                /// <param name="destDir">
525                /// The destination directory into which to extract.
526                /// </param>
527                /// <param name="entry">
528                /// The TarEntry returned by tarIn.GetNextEntry().
529                /// </param>
530                void ExtractEntry(string destDir, TarEntry entry)
531                {
532                        OnProgressMessageEvent(entry, null);
533                       
534                        string name = entry.Name;
535                       
536                        if (Path.IsPathRooted(name) == true) {
537                                // NOTE:
538                                // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
539                                name = name.Substring(Path.GetPathRoot(name).Length);
540                        }
541                       
542                        name = name.Replace('/', Path.DirectorySeparatorChar);
543                       
544                        string destFile = Path.Combine(destDir, name);
545                       
546                        if (entry.IsDirectory) {
547                                EnsureDirectoryExists(destFile);
548                        } else {
549                                string parentDirectory = Path.GetDirectoryName(destFile);
550                                EnsureDirectoryExists(parentDirectory);
551                               
552                                bool process = true;
553                                FileInfo fileInfo = new FileInfo(destFile);
554                                if (fileInfo.Exists) {
555                                        if (this.keepOldFiles) {
556                                                OnProgressMessageEvent(entry, "Destination file already exists");
557                                                process = false;
558                                        } else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) {
559                                                OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
560                                                process = false;
561                                        }
562                                }
563                               
564                                if (process) {
565                                        bool asciiTrans = false;
566                                       
567                                        Stream outputStream = File.Create(destFile);
568                                        if (this.asciiTranslate) {
569                                                asciiTrans = !IsBinary(destFile);
570                                        }
571                                       
572                                        StreamWriter outw = null;
573                                        if (asciiTrans) {
574                                                outw = new StreamWriter(outputStream);
575                                        }
576                                       
577                                        byte[] rdbuf = new byte[32 * 1024];
578                                       
579                                        while (true) {
580                                                int numRead = this.tarIn.Read(rdbuf, 0, rdbuf.Length);
581                                               
582                                                if (numRead <= 0) {
583                                                        break;
584                                                }
585                                               
586                                                if (asciiTrans) {
587                                                        for (int off = 0, b = 0; b < numRead; ++b) {
588                                                                if (rdbuf[b] == 10) {
589                                                                        string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
590                                                                        outw.WriteLine(s);
591                                                                        off = b + 1;
592                                                                }
593                                                        }
594                                                } else {
595                                                        outputStream.Write(rdbuf, 0, numRead);
596                                                }
597                                        }
598                                       
599                                        if (asciiTrans) {
600                                                outw.Close();
601                                        } else {
602                                                outputStream.Close();
603                                        }
604                                }
605                        }
606                }
607
608                /// <summary>
609                /// Write an entry to the archive. This method will call the putNextEntry
610                /// and then write the contents of the entry, and finally call closeEntry()
611                /// for entries that are files. For directories, it will call putNextEntry(),
612                /// and then, if the recurse flag is true, process each entry that is a
613                /// child of the directory.
614                /// </summary>
615                /// <param name="sourceEntry">
616                /// The TarEntry representing the entry to write to the archive.
617                /// </param>
618                /// <param name="recurse">
619                /// If true, process the children of directory entries.
620                /// </param>
621                public void WriteEntry(TarEntry sourceEntry, bool recurse)
622                {
623                        if ( sourceEntry == null ) {
624                                throw new ArgumentNullException("sourceEntry");
625                        }
626                       
627                        if ( isDisposed ) {
628                                throw new ObjectDisposedException("TarArchive");
629                        }
630                       
631                        try
632                        {
633                                if ( recurse ) {
634                                        TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
635                                                                                           sourceEntry.GroupId, sourceEntry.GroupName);
636                                }
637                                WriteEntryCore(sourceEntry, recurse);
638                        }
639                        finally
640                        {
641                                if ( recurse ) {
642                                        TarHeader.RestoreSetValues();
643                                }
644                        }
645                }
646               
647                /// <summary>
648                /// Write an entry to the archive. This method will call the putNextEntry
649                /// and then write the contents of the entry, and finally call closeEntry()
650                /// for entries that are files. For directories, it will call putNextEntry(),
651                /// and then, if the recurse flag is true, process each entry that is a
652                /// child of the directory.
653                /// </summary>
654                /// <param name="sourceEntry">
655                /// The TarEntry representing the entry to write to the archive.
656                /// </param>
657                /// <param name="recurse">
658                /// If true, process the children of directory entries.
659                /// </param>
660                void WriteEntryCore(TarEntry sourceEntry, bool recurse)
661                {
662                        bool asciiTrans = false;
663                       
664                        string tempFileName = null;
665                        string entryFilename   = sourceEntry.File;
666                       
667                        TarEntry entry = (TarEntry)sourceEntry.Clone();
668
669                        if ( applyUserInfoOverrides ) {
670                                entry.GroupId = groupId;
671                                entry.GroupName = groupName;
672                                entry.UserId = userId;
673                                entry.UserName = userName;
674                        }
675                       
676                        OnProgressMessageEvent(entry, null);
677                       
678                        if (this.asciiTranslate && !entry.IsDirectory) {
679                                asciiTrans = !IsBinary(entryFilename);
680
681                                if (asciiTrans) {
682                                        tempFileName = Path.GetTempFileName();
683                                       
684                                        using (StreamReader inStream  = File.OpenText(entryFilename)) {
685                                                using (Stream outStream = File.Create(tempFileName)) {
686                                               
687                                                        while (true) {
688                                                                string line = inStream.ReadLine();
689                                                                if (line == null) {
690                                                                        break;
691                                                                }
692                                                                byte[] data = Encoding.ASCII.GetBytes(line);
693                                                                outStream.Write(data, 0, data.Length);
694                                                                outStream.WriteByte((byte)'\n');
695                                                        }
696                                                       
697                                                        outStream.Flush();
698                                                }
699                                        }
700                                       
701                                        entry.Size = new FileInfo(tempFileName).Length;
702                                        entryFilename = tempFileName;
703                                }
704                        }
705                       
706                        string newName = null;
707               
708                        if (this.rootPath != null) {
709                                if (entry.Name.StartsWith(this.rootPath)) {
710                                        newName = entry.Name.Substring(this.rootPath.Length + 1 );
711                                }
712                        }
713                       
714                        if (this.pathPrefix != null) {
715                                newName = (newName == null) ? this.pathPrefix + "/" + entry.Name : this.pathPrefix + "/" + newName;
716                        }
717                       
718                        if (newName != null) {
719                                entry.Name = newName;
720                        }
721                       
722                        tarOut.PutNextEntry(entry);
723                       
724                        if (entry.IsDirectory) {
725                                if (recurse) {
726                                        TarEntry[] list = entry.GetDirectoryEntries();
727                                        for (int i = 0; i < list.Length; ++i) {
728                                                WriteEntryCore(list[i], recurse);
729                                        }
730                                }
731                        }
732                        else {
733                                using (Stream inputStream = File.OpenRead(entryFilename)) {
734                                        int numWritten = 0;
735                                        byte[] localBuffer = new byte[32 * 1024];
736                                        while (true) {
737                                                int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
738                                               
739                                                if (numRead <=0) {
740                                                        break;
741                                                }
742                                               
743                                                tarOut.Write(localBuffer, 0, numRead);
744                                                numWritten +=  numRead;
745                                        }
746                                }
747                               
748                                if ( (tempFileName != null) && (tempFileName.Length > 0) ) {
749                                        File.Delete(tempFileName);
750                                }
751                               
752                                tarOut.CloseEntry();
753                        }
754                }
755
756                /// <summary>
757                /// Releases the unmanaged resources used by the FileStream and optionally releases the managed resources.
758                /// </summary>
759                /// <param name="disposing">true to release both managed and unmanaged resources;
760                /// false to release only unmanaged resources.</param>
761                protected virtual void Dispose(bool disposing)
762                {
763                        if ( !isDisposed ) {
764                                isDisposed = true;
765                                if ( disposing ) {
766                                        if ( tarOut != null ) {
767                                                tarOut.Flush();
768                                                tarOut.Close();
769                                        }
770               
771                                        if ( tarIn != null ) {
772                                                tarIn.Close();
773                                        }
774                                }
775                        }
776                }
777               
778                /// <summary>
779                /// Closes the archive and releases any associated resources.
780                /// </summary>
781                public virtual void Close()
782                {
783                        Dispose(true);
784                        GC.SuppressFinalize(this);
785                }
786               
787                /// <summary>
788                /// Ensures that resources are freed and other cleanup operations are performed
789                /// when the garbage collector reclaims the <see cref="TarArchive"/>.
790                /// </summary>
791                ~TarArchive()
792                {
793                        Dispose(false);
794                }
795               
796                #region IDisposable Members
797
798                /// <summary>
799                /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
800                /// </summary>
801                void IDisposable.Dispose()
802                {
803                        Close();
804                }
805
806                #endregion
807               
808                static void EnsureDirectoryExists(string directoryName)
809                {
810                        if (!Directory.Exists(directoryName)) {
811                                try {
812                                        Directory.CreateDirectory(directoryName);
813                                }
814                                catch (Exception e) {
815                                        throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message, e);
816                                }
817                        }
818                }
819               
820                // TODO: TarArchive - Is there a better way to test for a text file?
821                // It no longer reads entire files into memory but is still a weak test!
822                // This assumes that byte values 0-7, 14-31 or 255 are binary
823                // and that all non text files contain one of these values
824                static bool IsBinary(string filename)
825                {
826                        using (FileStream fs = File.OpenRead(filename))
827                        {
828                                int sampleSize = System.Math.Min(4096, (int)fs.Length);
829                                byte[] content = new byte[sampleSize];
830                       
831                                int bytesRead = fs.Read(content, 0, sampleSize);
832                       
833                                for (int i = 0; i < bytesRead; ++i) {
834                                        byte b = content[i];
835                                        if ( (b < 8) || ((b > 13) && (b < 32)) || (b == 255) ) {
836                                                return true;
837                                        }
838                                }
839                        }
840                        return false;
841                }               
842               
843                #region Instance Fields
844                bool keepOldFiles;
845                bool asciiTranslate;
846               
847                int    userId;
848                string userName = string.Empty;
849                int    groupId;
850                string groupName = string.Empty;
851               
852                string rootPath;
853                string pathPrefix;
854               
855                bool applyUserInfoOverrides;
856               
857                TarInputStream  tarIn;
858                TarOutputStream tarOut;
859                bool isDisposed;
860                #endregion
861        }
862}
863
864
865/* The original Java file had this header:
866        ** Authored by Timothy Gerard Endres
867        ** <mailto:time@gjt.org>  <http://www.trustice.com>
868        **
869        ** This work has been placed into the public domain.
870        ** You may use this work in any way and for any purpose you wish.
871        **
872        ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
873        ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
874        ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
875        ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
876        ** REDISTRIBUTION OF THIS SOFTWARE.
877        **
878        */
879
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.