コード例 #1
0
ファイル: TarArchive.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Raises the ProgressMessage event
		/// </summary>
		/// <param name="entry">The <see cref="TarEntry">TarEntry</see> for this event</param>
		/// <param name="message">message for this event.  Null is no message</param>
		protected virtual void OnProgressMessageEvent(TarEntry entry, string message)
		{
		    ProgressMessageHandler handler = ProgressMessageEvent;
			if (handler != null) {
				handler(this, entry, message);
			}
		}
コード例 #2
0
		/// <summary>
		/// Get the next entry in this tar archive. This will skip
		/// over any remaining data in the current entry, if there
		/// is one, and place the input stream at the header of the
		/// next entry, and read the header and instantiate a new
		/// TarEntry from the header bytes and return that entry.
		/// If there are no more entries in the archive, null will
		/// be returned to indicate that the end of the archive has
		/// been reached.
		/// </summary>
		/// <returns>
		/// The next TarEntry in the archive, or null.
		/// </returns>
		public TarEntry GetNextEntry()
		{
			if (hasHitEOF) {
				return null;
			}
			
			if (currentEntry != null) {
				SkipToNextEntry();
			}
			
			byte[] headerBuf = tarBuffer.ReadBlock();
			
			if (headerBuf == null) {
				hasHitEOF = true;
			} else if (TarBuffer.IsEndOfArchiveBlock(headerBuf)) {
				hasHitEOF = true;
			}
			
			if (hasHitEOF) {
				currentEntry = null;
			} else {
				try {
					TarHeader header = new TarHeader();
					header.ParseBuffer(headerBuf);
					if ( !header.IsChecksumValid )
					{
						throw new TarException("Header checksum is invalid");
					}
					this.entryOffset = 0;
					this.entrySize = header.Size;
					
					StringBuilder longName = null;
					
					if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) {
						
						byte[] nameBuffer = new byte[TarBuffer.BlockSize];
						long numToRead = this.entrySize;
						
						longName = new StringBuilder();
						
						while (numToRead > 0) {
							int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead));
							
							if (numRead == -1) {
								throw new InvalidHeaderException("Failed to read long name entry");
							}
							
							longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
							numToRead -= numRead;
						}
						
						SkipToNextEntry();
						headerBuf = this.tarBuffer.ReadBlock();
					} else if (header.TypeFlag == TarHeader.LF_GHDR) {  // POSIX global extended header 
						// Ignore things we dont understand completely for now
						SkipToNextEntry();
						headerBuf = this.tarBuffer.ReadBlock();
					} else if (header.TypeFlag == TarHeader.LF_XHDR) {  // POSIX extended header
						// Ignore things we dont understand completely for now
						SkipToNextEntry();
						headerBuf = this.tarBuffer.ReadBlock();
					} else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) {
						// TODO: could show volume name when verbose
						SkipToNextEntry();
						headerBuf = this.tarBuffer.ReadBlock();
					} else if (header.TypeFlag != TarHeader.LF_NORMAL && 
							   header.TypeFlag != TarHeader.LF_OLDNORM &&
							   header.TypeFlag != TarHeader.LF_DIR) {
						// Ignore things we dont understand completely for now
						SkipToNextEntry();
						headerBuf = tarBuffer.ReadBlock();
					}
					
					if (entryFactory == null) {
						currentEntry = new TarEntry(headerBuf);
						if (longName != null) {
							currentEntry.Name = longName.ToString();
						}
					} else {
						currentEntry = entryFactory.CreateEntry(headerBuf);
					}
					
					// Magic was checked here for 'ustar' but there are multiple valid possibilities
					// so this is not done anymore.
					
					entryOffset = 0;
					
					// TODO: Review How do we resolve this discrepancy?!
					entrySize = this.currentEntry.Size;
				} catch (InvalidHeaderException ex) {
					entrySize = 0;
					entryOffset = 0;
					currentEntry = null;
					string errorText = string.Format("Bad header in record {0} block {1} {2}",
						tarBuffer.CurrentRecord, tarBuffer.CurrentBlock, ex.Message);
					throw new InvalidHeaderException(errorText);
				}
			}
			return currentEntry;
		}
コード例 #3
0
		/// <summary>
		/// Put an entry on the output stream. This writes the entry's
		/// header and positions the output stream for writing
		/// the contents of the entry. Once this method is called, the
		/// stream is ready for calls to write() to write the entry's
		/// contents. Once the contents are written, closeEntry()
		/// <B>MUST</B> be called to ensure that all buffered data
		/// is completely written to the output stream.
		/// </summary>
		/// <param name="entry">
		/// The TarEntry to be written to the archive.
		/// </param>
		public void PutNextEntry(TarEntry entry)
		{
			if ( entry == null ) {
				throw new ArgumentNullException("entry");
			}

			if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN) {
				TarHeader longHeader = new TarHeader();
				longHeader.TypeFlag = TarHeader.LF_GNU_LONGNAME;
				longHeader.Name = longHeader.Name + "././@LongLink";
				longHeader.UserId = 0;
				longHeader.GroupId = 0;
				longHeader.GroupName = "";
				longHeader.UserName = "";
				longHeader.LinkName = "";
                longHeader.Size = entry.TarHeader.Name.Length;

				longHeader.WriteHeader(blockBuffer);
				buffer.WriteBlock(blockBuffer);  // Add special long filename header block

				int nameCharIndex = 0;

				while (nameCharIndex < entry.TarHeader.Name.Length) {
					Array.Clear(blockBuffer, 0, blockBuffer.Length);
					TarHeader.GetAsciiBytes(entry.TarHeader.Name, nameCharIndex, this.blockBuffer, 0, TarBuffer.BlockSize);
					nameCharIndex += TarBuffer.BlockSize;
					buffer.WriteBlock(blockBuffer);
				}
			}
			
			entry.WriteEntryHeader(blockBuffer);
			buffer.WriteBlock(blockBuffer);
			
			currBytes = 0;
			
			currSize = entry.IsDirectory ? 0 : entry.Size;
		}
コード例 #4
0
ファイル: TarEntry.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Get entries for all files present in this entries directory.
		/// If this entry doesnt represent a directory zero entries are returned.
		/// </summary>
		/// <returns>
		/// An array of TarEntry's for this entry's children.
		/// </returns>
		public TarEntry[] GetDirectoryEntries()
		{
			if ( (file == null) || !Directory.Exists(file)) {
				return new TarEntry[0];
			}
			
			string[]   list   = Directory.GetFileSystemEntries(file);
			TarEntry[] result = new TarEntry[list.Length];

			for (int i = 0; i < list.Length; ++i) {
				result[i] = TarEntry.CreateEntryFromFile(list[i]);
			}
			
			return result;
		}
コード例 #5
0
ファイル: TarEntry.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Determine if the given entry is a descendant of this entry.
		/// Descendancy is determined by the name of the descendant
		/// starting with this entry's name.
		/// </summary>
		/// <param name = "toTest">
		/// Entry to be checked as a descendent of this.
		/// </param>
		/// <returns>
		/// True if entry is a descendant of this.
		/// </returns>
		public bool IsDescendent(TarEntry toTest)
		{
			if ( toTest == null ) {
				throw new ArgumentNullException("toTest");
			}

			return toTest.Name.StartsWith(Name);
		}
コード例 #6
0
ファイル: TarEntry.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Construct an entry for a file. File is set to file, and the
		/// header is constructed from information from the file.
		/// </summary>
		/// <param name = "fileName">The file name that the entry represents.</param>
		/// <returns>Returns the newly created <see cref="TarEntry"/></returns>
		public static TarEntry CreateEntryFromFile(string fileName)
		{
			TarEntry entry = new TarEntry();
			entry.GetFileTarHeader(entry.header, fileName);
			return entry;
		}
コード例 #7
0
ファイル: TarEntry.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Construct an entry with only a <paramref name="name">name</paramref>.
		/// This allows the programmer to construct the entry's header "by hand". 
		/// </summary>
		/// <param name="name">The name to use for the entry</param>
		/// <returns>Returns the newly created <see cref="TarEntry"/></returns>
		public static TarEntry CreateTarEntry(string name)
		{
			TarEntry entry = new TarEntry();
			TarEntry.NameTarHeader(entry.header, name);
			return entry;
		}
コード例 #8
0
ファイル: TarEntry.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Clone this tar entry.
		/// </summary>
		/// <returns>Returns a clone of this entry.</returns>
		public object Clone()
		{
			TarEntry entry = new TarEntry();
			entry.file = file;
			entry.header = (TarHeader)header.Clone();
			entry.Name = Name;
			return entry;
		}
コード例 #9
0
ファイル: TarArchive.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Write an entry to the archive. This method will call the putNextEntry
		/// and then write the contents of the entry, and finally call closeEntry()
		/// for entries that are files. For directories, it will call putNextEntry(),
		/// and then, if the recurse flag is true, process each entry that is a
		/// child of the directory.
		/// </summary>
		/// <param name="sourceEntry">
		/// The TarEntry representing the entry to write to the archive.
		/// </param>
		/// <param name="recurse">
		/// If true, process the children of directory entries.
		/// </param>
		void WriteEntryCore(TarEntry sourceEntry, bool recurse)
		{
			string tempFileName = null;
			string entryFilename   = sourceEntry.File;
			
			TarEntry entry = (TarEntry)sourceEntry.Clone();

			if ( applyUserInfoOverrides ) {
				entry.GroupId = groupId;
				entry.GroupName = groupName;
				entry.UserId = userId;
				entry.UserName = userName;
			}
			
			OnProgressMessageEvent(entry, null);
			
			if (asciiTranslate && !entry.IsDirectory) {

				if (!IsBinary(entryFilename)) {
					tempFileName = Path.GetTempFileName();
					
					using (StreamReader inStream  = File.OpenText(entryFilename)) {
						using (Stream outStream = File.Create(tempFileName)) {
						
							while (true) {
								string line = inStream.ReadLine();
								if (line == null) {
									break;
								}
								byte[] data = Encoding.ASCII.GetBytes(line);
								outStream.Write(data, 0, data.Length);
								outStream.WriteByte((byte)'\n');
							}
							
							outStream.Flush();
						}
					}
					
					entry.Size = new FileInfo(tempFileName).Length;
					entryFilename = tempFileName;
				}
			}
			
			string newName = null;
		
			if (rootPath != null) {
				if (entry.Name.StartsWith(rootPath)) {
					newName = entry.Name.Substring(rootPath.Length + 1 );
				}
			}
			
			if (pathPrefix != null) {
				newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName;
			}
			
			if (newName != null) {
				entry.Name = newName;
			}
			
			tarOut.PutNextEntry(entry);
			
			if (entry.IsDirectory) {
				if (recurse) {
					TarEntry[] list = entry.GetDirectoryEntries();
					for (int i = 0; i < list.Length; ++i) {
						WriteEntryCore(list[i], recurse);
					}
				}
			}
			else {
				using (Stream inputStream = File.OpenRead(entryFilename)) {
					byte[] localBuffer = new byte[32 * 1024];
					while (true) {
						int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
						
						if (numRead <=0) {
							break;
						}
						
						tarOut.Write(localBuffer, 0, numRead);
					}
				}
				
				if ( (tempFileName != null) && (tempFileName.Length > 0) ) {
					File.Delete(tempFileName);
				}
				
				tarOut.CloseEntry();
			}
		}
コード例 #10
0
ファイル: TarArchive.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Write an entry to the archive. This method will call the putNextEntry
		/// and then write the contents of the entry, and finally call closeEntry()
		/// for entries that are files. For directories, it will call putNextEntry(),
		/// and then, if the recurse flag is true, process each entry that is a
		/// child of the directory.
		/// </summary>
		/// <param name="sourceEntry">
		/// The TarEntry representing the entry to write to the archive.
		/// </param>
		/// <param name="recurse">
		/// If true, process the children of directory entries.
		/// </param>
		public void WriteEntry(TarEntry sourceEntry, bool recurse)
		{
			if ( sourceEntry == null ) {
				throw new ArgumentNullException("sourceEntry");
			}
			
			if ( isDisposed ) {
				throw new ObjectDisposedException("TarArchive");
			}
			
			try
			{
				if ( recurse ) {
					TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
											   sourceEntry.GroupId, sourceEntry.GroupName);
				}
				WriteEntryCore(sourceEntry, recurse);
			}
			finally
			{
				if ( recurse ) {
					TarHeader.RestoreSetValues();
				}
			}
		}
コード例 #11
0
ファイル: TarArchive.cs プロジェクト: missxiaohuang/Weekly
		/// <summary>
		/// Extract an entry from the archive. This method assumes that the
		/// tarIn stream has been properly set with a call to GetNextEntry().
		/// </summary>
		/// <param name="destDir">
		/// The destination directory into which to extract.
		/// </param>
		/// <param name="entry">
		/// The TarEntry returned by tarIn.GetNextEntry().
		/// </param>
		void ExtractEntry(string destDir, TarEntry entry)
		{
			OnProgressMessageEvent(entry, null);
			
			string name = entry.Name;
			
			if (Path.IsPathRooted(name)) {
				// NOTE:
				// for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
				name = name.Substring(Path.GetPathRoot(name).Length);
			}
			
			name = name.Replace('/', Path.DirectorySeparatorChar);
			
			string destFile = Path.Combine(destDir, name);
			
			if (entry.IsDirectory) {
				EnsureDirectoryExists(destFile);
			} else {
				string parentDirectory = Path.GetDirectoryName(destFile);
				EnsureDirectoryExists(parentDirectory);
				
				bool process = true;
				FileInfo fileInfo = new FileInfo(destFile);
				if (fileInfo.Exists) {
					if (keepOldFiles) {
						OnProgressMessageEvent(entry, "Destination file already exists");
						process = false;
					} else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) {
						OnProgressMessageEvent(entry, "Destination file already exists, and is read-only");
						process = false;
					}
				}
				
				if (process) {
					bool asciiTrans = false;
					
					Stream outputStream = File.Create(destFile);
					if (this.asciiTranslate) {
						asciiTrans = !IsBinary(destFile);
					}
					
					StreamWriter outw = null;
					if (asciiTrans) {
						outw = new StreamWriter(outputStream);
					}
					
					byte[] rdbuf = new byte[32 * 1024];
					
					while (true) {
						int numRead = tarIn.Read(rdbuf, 0, rdbuf.Length);
						
						if (numRead <= 0) {
							break;
						}
						
						if (asciiTrans) {
							for (int off = 0, b = 0; b < numRead; ++b) {
								if (rdbuf[b] == 10) {
									string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
									outw.WriteLine(s);
									off = b + 1;
								}
							}
						} else {
							outputStream.Write(rdbuf, 0, numRead);
						}
					}
					
					if (asciiTrans) {
						outw.Close();
					} else {
						outputStream.Close();
					}
				}
			}
		}