github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/windowsuserdatafiles/untar.ps1 (about)

     1  
     2  Function GUnZip-File{
     3      Param(
     4          $infile,
     5          $outdir
     6          )
     7  
     8      $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
     9      $tempFile = "$env:TEMP\jujud.tar"
    10      $tempOut = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
    11      $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)
    12  
    13      $buffer = New-Object byte[](1024)
    14      while($true) {
    15          $read = $gzipstream.Read($buffer, 0, 1024)
    16          if ($read -le 0){break}
    17          $tempOut.Write($buffer, 0, $read)
    18      }
    19      $gzipStream.Close()
    20      $tempOut.Close()
    21      $input.Close()
    22  
    23      $in = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
    24      Untar-File $in $outdir
    25      $in.Close()
    26      rm $tempFile
    27  }
    28  
    29  $HEADERSIZE = 512
    30  
    31  Function Untar-File {
    32      Param(
    33          $inStream,
    34          $outdir
    35          )
    36      $DirectoryEntryType = 0x35
    37      $headerBytes = New-Object byte[]($HEADERSIZE)
    38  
    39      # $headerBytes is written inside, function returns whether we've reached the end
    40      while(GetHeaderBytes $inStream $headerBytes) {
    41          $fileName, $entryType, $sizeInBytes = GetFileInfoFromHeader $headerBytes
    42  
    43          $totalPath = Join-Path $outDir $fileName
    44          if ($entryType -eq $DirectoryEntryType) {
    45              [System.IO.Directory]::CreateDirectory($totalPath)
    46              continue;
    47          }
    48  
    49          $fName = [System.IO.Path]::GetFileName($totalPath)
    50          $dirName = [System.IO.Path]::GetDirectoryName($totalPath)
    51          [System.IO.Directory]::CreateDirectory($dirName)
    52          $file = [System.IO.File]::Create($totalPath)
    53          WriteTarEntryToFile $inStream $file $sizeInBytes
    54          $file.Close()
    55      }
    56  }
    57  
    58  Function WriteTarEntryToFile {
    59      Param(
    60          $inStream,
    61          $outFile,
    62          $sizeInBytes
    63          )
    64      $moveToAlign512 = 0
    65      $toRead = 0
    66      $buf = New-Object byte[](512)
    67  
    68      $remainingBytesInFile = $sizeInBytes
    69      while ($remainingBytesInFile -ne 0) {
    70          if ($remainingBytesInFile - 512 -lt 0) {
    71              $moveToAlign512 = 512 - $remainingBytesInFile
    72              $toRead = $remainingBytesInFile
    73          } else {
    74              $toRead = 512
    75          }
    76  
    77          $bytesRead = 0
    78          $bytesRemainingToRead = $toRead
    79          while ($bytesRead -lt $toRead -and $bytesRemainingToRead -gt 0) {
    80              $bytesRead = $inStream.Read($buf, $toRead - $bytesRemainingToRead, $bytesRemainingToRead)
    81              $bytesRemainingToRead = $bytesRemainingToRead - $bytesRead
    82              $remainingBytesInFile = $remainingBytesInFile - $bytesRead
    83              $outFile.Write($buf, 0, $bytesRead)
    84          }
    85  
    86          if ($moveToAlign512 -ne 0) {
    87              $inStream.Seek($moveToAlign512, [System.IO.SeekOrigin]::Current)
    88          }
    89      }
    90  }
    91  
    92  Function GetHeaderBytes {
    93      Param($inStream, $headerBytes)
    94  
    95      $headerRead = 0
    96      $bytesRemaining = $HEADERSIZE
    97      while ($bytesRemaining -gt 0) {
    98          $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining)
    99          $bytesRemaining -= $headerRead
   100          if ($headerRead -le 0 -and $bytesRemaining -gt 0) {
   101              throw "Error reading tar header. Header size invalid"
   102          }
   103      }
   104  
   105      # Proper end of archive is 2 empty headers
   106      if (IsEmptyByteArray $headerBytes) {
   107          $bytesRemaining = $HEADERSIZE
   108          while ($bytesRemaining -gt 0) {
   109              $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining)
   110              $bytesRemaining -= $headerRead
   111              if ($headerRead -le 0 -and $bytesRemaining -gt 0) {
   112                  throw "Broken end archive"
   113              }
   114          }
   115          if ($bytesRemaining -eq 0 -and (IsEmptyByteArray($headerBytes))) {
   116              return $false
   117          }
   118          throw "Error occurred: expected end of archive"
   119      }
   120  
   121      return $true
   122  }
   123  
   124  Function GetFileInfoFromHeader {
   125      Param($headerBytes)
   126  
   127      $FileName = [System.Text.Encoding]::UTF8.GetString($headerBytes, 0, 100);
   128      $EntryType = $headerBytes[156];
   129      $SizeInBytes = [Convert]::ToInt64([System.Text.Encoding]::ASCII.GetString($headerBytes, 124, 11).Trim(), 8);
   130      Return $FileName.replace("`0", [String].Empty), $EntryType, $SizeInBytes
   131  }
   132  
   133  Function IsEmptyByteArray {
   134      Param ($bytes)
   135      foreach($b in $bytes) {
   136          if ($b -ne 0) {
   137              return $false
   138          }
   139      }
   140      return $true
   141  }