... echo 'Reading descriptor file' . PHP_EOL; $descriptor = file_get_contents('descriptor.xml'); if ($descriptor === false) { echo 'ERROR: Could not read descriptor.xml.' . PHP_EOL; exit(7); } else { // delete descriptor now that we've read it @unlink('descriptor.xml'); } // look for payload in tarball $hasPayload = false; $dxml = new SimpleXMLElement($descriptor); $payload = (string) $dxml->payload; $componentName = (string) $dxml->installKey->vmis->componentName; for ($i=0; $i ... $stage = 0; $fileHeader = ''; $fileXML = ''; $xmlOffset = 0; $dataBaseOffset = 0; while (!feof($fd)) { $c = fread($fd, 1); if ($c === false) break; if ($stage == 0) { // looking for , appending header. '' = 11 long // increment offset counters $xmlOffset++; $dataBaseOffset++; // append new character $fileHeader .= $c; // check for match if (($xmlOffset > 11) && (substr($fileHeader, -11, 11) == '')) { // actual file header is 0 to position - 11 $xmlOffset -= 11; // manipulate data $fileXML = substr($fileHeader, $xmlOffset, 11); // move tag into xml $fileHeader = substr($fileHeader, 0, $xmlOffset); // strip tag from binary header $stage = 1; } } else if ($stage == 1) { // looking for , appending XML, '' = 12 long // increment offset counter $dataBaseOffset++; // append new character $fileXML .= $c; // check for match if ((strlen($fileXML) > 12) && (substr($fileXML, -12, 12) == '')) { // data base offset is now the current position $stage = true; break; } } } if ($stage !== true) { echo 'ERROR: Could not find ... XML markers' . PHP_EOL; fclose($fd); exit(12); } // check XML for component name $hxml = new SimpleXMLElement($fileXML); $testComponentName = (string) $hxml->name; if ($testComponentName != $componentName) { echo 'ERROR: Payload file does not contain expected vmware component' . PHP_EOL; echo 'EXPECTED: ' . $componentName . PHP_EOL; echo 'ACTUAL: ' . $testComponentName . PHP_EOL; fclose($fd); exit(13); } else { echo 'Payload file contains expected vmware component' . PHP_EOL; } // enumerate files $files = array(); foreach($hxml->fileset->file as $file) { $attrs = $file->attributes(); if (!isset($attrs['path']) || !isset($attrs['compressedSize']) || !isset($attrs['uncompressedSize']) || !isset($attrs['offset'])) continue; $files[] = array( 'path' => (string) $attrs['path'], 'compressedSize' => intval((string) $attrs['compressedSize']), 'uncompressedSize' => intval((string) $attrs['uncompressedSize']), 'offset' => intval((string) $attrs['offset']), 'actualOffset' => intval((string) $attrs['offset']) + $dataBaseOffset ); } // dump debug info echo PHP_EOL; echo 'Structure:' . PHP_EOL; echo '==============================' . PHP_EOL; echo 'XML Offset: ' . $xmlOffset . PHP_EOL; echo 'XML Length: ' . ($dataBaseOffset - $xmlOffset) . PHP_EOL; echo 'Data Offset Base: ' . $dataBaseOffset . PHP_EOL; echo '==============================' . PHP_EOL; echo PHP_EOL; echo 'Contents:' . PHP_EOL; echo '================================================================================' . PHP_EOL; echo 'File Compressed Actual' . PHP_EOL; foreach ($files as $file) { printf("%-50s%-13d%-13d\n", $file['path'], $file['compressedSize'], $file['uncompressedSize']); } echo '================================================================================' . PHP_EOL; echo PHP_EOL; // extract foreach ($files as $file) { echo 'Extracting ' . $file['path'] . PHP_EOL; $result = fseek($fd, $file['actualOffset'], SEEK_SET); if ($result != 0) { echo 'ERROR: could not seek to ' . $file['actualOffset'] . PHP_EOL; $success = false; continue; } // check path for leading /'s if (substr($file['path'], 0, 1) == '/') $file['path'] = substr($file['path'], 1); $file['path'] .= '.gz'; // add .gz extension $filename = basename($file['path']); $destdir = dirname($file['path']); $dirparts = explode('/', $destdir); $tmpdir = ''; foreach ($dirparts as $dir) { $tmpdir = ($tmpdir == '') ? $dir : ($tmpdir . '/' . $dir); $result = (!is_dir($tmpdir)) ? mkdir($tmpdir) : true; if (!$result) { echo 'ERROR: unable to make directory ' . $dir . PHP_EOL; $destdir = false; $dirparts = false; $success = false; break; } } // skip if aborted if ($dirparts === false) continue; // open for write $ofd = fopen($file['path'], 'wb'); if (!is_resource($ofd)) { echo 'ERROR: unable to open "' . $file['path'] . '" for writing' . PHP_EOL; $success = false; continue; } $bytesToRead = $file['compressedSize']; while (!feof($fd) && ($bytesToRead > 0)) { $data = fread($fd, (($bytesToRead < $blockSize) ? $bytesToRead : $blockSize)); if ($data === false) { echo 'ERROR: unable to read from input file' . PHP_EOL; $success = false; break; } $bytesToRead -= strlen($data); $written = fwrite($ofd, $data); if ($written === false) { echo 'ERROR: unable to write to output file' . PHP_EOL; $success = false; break; } } fclose($ofd); if (($bytesToRead == 0) && file_exists($file['path']) && (filesize($file['path']) == $file['compressedSize'])) { echo 'File extracted successfully' . PHP_EOL; echo 'Uncompressing' . PHP_EOL; exec('gunzip ' . $file['path']); $file['path'] = substr($file['path'], 0, strlen($file['path']) - 3); // strip .gz if (!file_exists($file['path'])) { echo 'ERROR: extraction failed' . PHP_EOL; $success = false; } else if (filesize($file['path']) != $file['uncompressedSize']) { echo 'ERROR: extraction produced file of unexpected size' . PHP_EOL; $success = false; } else { echo 'Uncompressed successfully' . PHP_EOL; } } else if (!file_exists($file['path'])) { echo 'ERROR: could not create output file' . PHP_EOL; $success = false; } else if (filesize($file['path']) != $file['compressedSize']) { echo 'ERROR: written file does not appear to have the correct size' . PHP_EOL; $success = false; } echo PHP_EOL; } fclose($fd); @unlink($payload); exit($success ? 0 : 14);