📄 tararchive.cs
字号:
}
return TarBuffer.DefaultRecordSize;
}
}
/// <summary>
/// Close the archive. This simply calls the underlying
/// tar stream's close() method.
/// </summary>
public void CloseArchive()
{
if (this.tarIn != null) {
this.tarIn.Close();
} else if (this.tarOut != null) {
this.tarOut.Flush();
this.tarOut.Close();
}
}
/// <summary>
/// Perform the "list" command for the archive contents.
///
/// NOTE That this method uses the <see cref="ProgressMessageEvent"> progress event</see> to actually list
/// the contents. If the progress display event is not set, nothing will be listed!
/// </summary>
public void ListContents()
{
while (true) {
TarEntry entry = this.tarIn.GetNextEntry();
if (entry == null) {
break;
}
OnProgressMessageEvent(entry, null);
}
}
/// <summary>
/// Perform the "extract" command and extract the contents of the archive.
/// </summary>
/// <param name="destDir">
/// The destination directory into which to extract.
/// </param>
public void ExtractContents(string destDir)
{
while (true) {
TarEntry entry = this.tarIn.GetNextEntry();
if (entry == null) {
break;
}
this.ExtractEntry(destDir, entry);
}
}
void EnsureDirectoryExists(string directoryName)
{
if (!Directory.Exists(directoryName)) {
try {
Directory.CreateDirectory(directoryName);
}
catch (Exception e) {
throw new TarException("Exception creating directory '" + directoryName + "', " + e.Message);
}
}
}
// TODO: Is there a better way to test for a text file?
// It no longer reads entire files into memory but is still a weak test!
// assumes that ascii 0-7, 14-31 or 255 are binary
// and that all non text files contain one of these values
bool IsBinary(string filename)
{
using (FileStream fs = File.OpenRead(filename))
{
int sampleSize = System.Math.Min(4096, (int)fs.Length);
byte[] content = new byte[sampleSize];
int bytesRead = fs.Read(content, 0, sampleSize);
for (int i = 0; i < bytesRead; ++i) {
byte b = content[i];
if (b < 8 || (b > 13 && b < 32) || b == 255) {
return true;
}
}
}
return false;
}
/// <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) == true) {
// 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 (this.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 = this.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();
}
}
}
}
/// <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)
{
try
{
if ( recurse ) {
TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName,
sourceEntry.GroupId, sourceEntry.GroupName);
}
InternalWriteEntry(sourceEntry, recurse);
}
finally
{
if ( recurse ) {
TarHeader.RestoreSetValues();
}
}
}
/// <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 InternalWriteEntry(TarEntry sourceEntry, bool recurse)
{
bool asciiTrans = false;
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 (this.asciiTranslate && !entry.IsDirectory) {
asciiTrans = !IsBinary(entryFilename);
if (asciiTrans) {
tempFileName = Path.GetTempFileName();
StreamReader inStream = File.OpenText(entryFilename);
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');
}
inStream.Close();
outStream.Flush();
outStream.Close();
entry.Size = new FileInfo(tempFileName).Length;
entryFilename = tempFileName;
}
}
string newName = null;
if (this.rootPath != null) {
if (entry.Name.StartsWith(this.rootPath)) {
newName = entry.Name.Substring(this.rootPath.Length + 1 );
}
}
if (this.pathPrefix != null) {
newName = (newName == null) ? this.pathPrefix + "/" + entry.Name : this.pathPrefix + "/" + newName;
}
if (newName != null) {
entry.Name = newName;
}
this.tarOut.PutNextEntry(entry);
if (entry.IsDirectory) {
if (recurse) {
TarEntry[] list = entry.GetDirectoryEntries();
for (int i = 0; i < list.Length; ++i) {
InternalWriteEntry(list[i], recurse);
}
}
} else {
Stream inputStream = File.OpenRead(entryFilename);
int numWritten = 0;
byte[] eBuf = new byte[32 * 1024];
while (true) {
int numRead = inputStream.Read(eBuf, 0, eBuf.Length);
if (numRead <=0) {
break;
}
this.tarOut.Write(eBuf, 0, numRead);
numWritten += numRead;
}
inputStream.Close();
if (tempFileName != null && tempFileName.Length > 0) {
File.Delete(tempFileName);
}
this.tarOut.CloseEntry();
}
}
}
}
/* The original Java file had this header:
** Authored by Timothy Gerard Endres
** <mailto:time@gjt.org> <http://www.trustice.com>
**
** This work has been placed into the public domain.
** You may use this work in any way and for any purpose you wish.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE.
**
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -