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 }