예제 #1
0
 // Extract a file from our archive
 public void ExtractFile(TARMetaData entry, string output)
 {
     // Check we're extracting a normal file
     if (entry.GetTypeFlags() == TARMetaData.TypeFlags.NormalFile)
     {
         //Create any directories as required
         string directory = Path.GetDirectoryName(output);
         if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
         {
             Directory.CreateDirectory(directory);
         }
         {
             // Open relevant streams and extract
             using (var stream = File.OpenRead(Filename))
                 if (isCompressed)
                 {
                     using (var gzip = new GZipStream(stream, CompressionMode.Decompress))
                         ExtractFile(entry, gzip, output);
                 }
                 else
                 {
                     ExtractFile(entry, stream, output);
                 }
         }
     }
 }
예제 #2
0
    // Add a file to our archive using streams
    // For simplicity, we always add to the start of the archive
    private void AddFile(string filePath, Stream streamIn, Stream streamOut)
    {
        // For the user name and user group, we use Environment.UserName
        // I haven't found a simple, platform independent way of getting the
        // User Group correctly
        string userName  = Environment.UserName;
        string userGroup = Environment.UserName;

        // Read all the file data to add
        byte[] fileData = File.ReadAllBytes(filePath);

        // Use the File's Last Write time as the file's time in the archive
        long currentTime = new DateTimeOffset(File.GetLastWriteTime(filePath)).ToUnixTimeSeconds();

        // Create the metadata structure
        TARMetaData fileMD = TARMetaData.CreateDefaultFileMetaData(Path.GetFileName(filePath), fileData.Length, currentTime, userName, userGroup);

        // Copy the metadata to a byte array and write it
        byte[] bAssetMD = fileMD.ToByteArray(true);
        streamOut.Write(bAssetMD, 0, bAssetMD.Length);

        // Then write out the file following this
        streamOut.Write(fileData, 0, fileData.Length);

        // Pad after the file data until we reach a 512 byte boundary if needed
        if (fileData.Length % 512 > 0)
        {
            int    paddingBytes  = 512 - (fileData.Length % 512);
            byte[] bPaddingBytes = new byte[paddingBytes];
            streamOut.Write(bPaddingBytes, 0, paddingBytes);
        }

        // Then loop through each of the original entries
        foreach (TARMetaData entry in Entries)
        {
            //Read the original meta data from the input and write to output
            var metadata = new byte[512];
            streamIn.Read(metadata, 0, metadata.Length);
            streamOut.Write(metadata, 0, metadata.Length);

            //Read the original file data from the input and write to output
            var file = new byte[entry.fileSize];
            streamIn.Read(file, 0, file.Length);
            streamOut.Write(file, 0, file.Length);

            // Pad after the file data until we reach a 512 byte boundary if needed
            if (file.Length % 512 > 0)
            {
                int    paddingBytes  = 512 - (file.Length % 512);
                byte[] bPaddingBytes = new byte[paddingBytes];
                streamIn.Read(bPaddingBytes, 0, paddingBytes);
                streamOut.Write(bPaddingBytes, 0, paddingBytes);
            }
        }
    }
예제 #3
0
    // Remove a file from our archive using the entry name
    // We cannot do in place overwrites, as we read in the original file
    // And then write it out
    public void RemoveFile(string entryName, string output, bool outputCompressed)
    {
        // Look up the entry based on filename
        TARMetaData entry = Entries.Find(e => e.fileName == entryName);

        //If we found one, extract it
        if (entry != null)
        {
            RemoveFile(entry, output, outputCompressed);
        }
    }
예제 #4
0
    // Extract a file from our archive using the entry name
    public void ExtractFile(string entryName, string output)
    {
        // Look up the entry based on filename
        TARMetaData entry = Entries.Find(e => e.fileName == entryName);

        //If we found one, extract it
        if (entry != null)
        {
            ExtractFile(entry, output);
        }
    }
예제 #5
0
 // Extract a file from a stream
 private void ExtractFile(TARMetaData entry, Stream stream, string output)
 {
     // Open the output
     using (var str = File.Open(output, FileMode.OpenOrCreate, FileAccess.Write))
     {
         // Create a buffer to hold the file
         var buf = new byte[entry.fileSize];
         // Seek to the relevant place in the stream
         StreamSeek(stream, entry.FileBufferPositionStart);
         // Read from the stream, write to the file
         stream.Read(buf, 0, buf.Length);
         str.Write(buf, 0, buf.Length);
     }
 }
예제 #6
0
    // Remove a file from our archive
    // We cannot do in place overwrites, as we read in the original file
    // And then write it out
    public void RemoveFile(TARMetaData entryToRemove, string output, bool outputCompressed)
    {
        //Create any directories as required
        string directory = Path.GetDirectoryName(output);

        if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }
        {
            // Open relevant streams and add file as necessary
            // Code is a bit messy, but essentially we have four conditions
            // where the input stream can be compressed or not, and the output
            // stream can be compressed or not
            using (var streamIn = File.OpenRead(Filename))
            {
                using (var streamOut = File.Open(output, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    if (isCompressed)
                    {
                        using (var gzipIn = new GZipStream(streamIn, CompressionMode.Decompress))
                        {
                            if (outputCompressed)
                            {
                                using (var gzipOut = new GZipStream(streamOut, CompressionMode.Compress))
                                    RemoveFile(entryToRemove, gzipIn, gzipOut);
                            }
                            else
                            {
                                RemoveFile(entryToRemove, gzipIn, streamOut);
                            }
                        }
                    }
                    else
                    {
                        if (outputCompressed)
                        {
                            using (var gzipOut = new GZipStream(streamOut, CompressionMode.Compress))
                                RemoveFile(entryToRemove, streamIn, gzipOut);
                        }
                        else
                        {
                            RemoveFile(entryToRemove, streamIn, streamOut);
                        }
                    }
                }
            }
        }
    }
예제 #7
0
    // Load a TAR archive from a Stream
    private void LoadFromStream(Stream stream)
    {
        // TAR Entry MetaData is stored in 512 byte buffers
        var  metaDataBuffer = new byte[512];
        int  readCount      = 0;
        long bufferPosition = 0;

        do
        {
            // Read 512 bytes
            readCount = stream.Read(metaDataBuffer, 0, 512);

            // If we were successful
            if (readCount >= 512)
            {
                // Unpack the MetaData and update the buffer positions
                TARMetaData fileMetaData = new TARMetaData(metaDataBuffer);
                fileMetaData.MetaDataBufferPositionStart = bufferPosition;
                bufferPosition += readCount;
                fileMetaData.FileBufferPositionStart = bufferPosition;

                // If the entry has file data following it
                if (fileMetaData.GetTypeFlags() == TARMetaData.TypeFlags.NormalFile ||
                    fileMetaData.GetTypeFlags() == TARMetaData.TypeFlags.ExtendedHeaderWithMetaDataForNextFileInArchive)
                {
                    // Seek past the data
                    StreamSeek(stream, fileMetaData.fileSize);
                    bufferPosition += fileMetaData.fileSize;

                    // Make sure we seek past by a multiple of 512
                    if (fileMetaData.fileSize % 512 > 0)
                    {
                        long offset = 512 - (fileMetaData.fileSize % 512);
                        StreamSeek(stream, offset);
                        bufferPosition += offset;
                    }
                }

                // Store the meta data
                Entries.Add(fileMetaData);
            }

            //Loop until we've run out of entries
        } while (readCount >= 512);
    }
예제 #8
0
    // Remove a file from our archive
    private void RemoveFile(TARMetaData entryToRemove, Stream inputStream, Stream outputStream)
    {
        // Loop through every entry
        foreach (TARMetaData entry in Entries)
        {
            // Check to see if this is the entry we are removing
            // If not, set write to true, else set to fale
            bool write = (entry.fileName != entryToRemove.fileName);

            // Read the metadata from the input file
            var metadata = new byte[512];
            inputStream.Read(metadata, 0, metadata.Length);

            //If this file is not being deleted, write out the metadata
            if (write)
            {
                outputStream.Write(metadata, 0, metadata.Length);
            }

            // Read the file data from the input file
            var file = new byte[entry.fileSize];
            inputStream.Read(file, 0, file.Length);

            //If this file is not being deleted, write out the file
            if (write)
            {
                outputStream.Write(file, 0, file.Length);
            }

            // Pad after the file data until we reach a 512 byte boundary if needed
            if (file.Length % 512 > 0)
            {
                int    paddingBytes  = 512 - (file.Length % 512);
                byte[] bPaddingBytes = new byte[paddingBytes];
                inputStream.Read(bPaddingBytes, 0, paddingBytes);
                // We only need to pad the output if the file is not being deleted
                if (write)
                {
                    outputStream.Write(bPaddingBytes, 0, paddingBytes);
                }
            }
        }
    }