# HG changeset patch # User Brett Smith # Date 1212715484 14400 # Node ID 17d845dacff5e61f76a5c574823f7034109784fa # Parent 23eb5e0a66659da4033b6bbbc8a290c6b1b570f2 Deal with partially extracted tarballs. If you can only extract part of a tarball -- for example, because it includes nodes and you're not root -- tar will extract what it can but give an error code. So now dtrx will only fail if some subprogram threw an error code *and* nothing actually got extracted. Otherwise, we'll show whatever errors came up, but we'll still assume the extraction was as successful as it's going to be. diff -r 23eb5e0a6665 -r 17d845dacff5 scripts/dtrx --- a/scripts/dtrx Thu Jun 05 10:00:38 2008 -0400 +++ b/scripts/dtrx Thu Jun 05 21:24:44 2008 -0400 @@ -138,6 +138,8 @@ self.content_type = None self.content_name = None self.pipes = [] + self.stderr = tempfile.TemporaryFile() + self.exit_codes = [] try: self.archive = open(filename, 'r') except (IOError, OSError), error: @@ -150,6 +152,12 @@ def pipe(self, command, description="extraction"): self.pipes.append((command, description)) + def first_bad_exit_code(self): + for index, code in enumerate(self.exit_codes): + if code != 0: + return index + return None + def run_pipes(self, final_stdout=None): if not self.pipes: return @@ -171,23 +179,17 @@ try: processes.append(subprocess.Popen(command, stdin=stdin, stdout=stdout, - stderr=subprocess.PIPE)) + stderr=self.stderr)) except OSError, error: if error.errno == errno.ENOENT: raise ExtractorUnusable("could not run %s" % (command[0],)) raise - exit_codes = [pipe.wait() for pipe in processes] + self.exit_codes = [pipe.wait() for pipe in processes] self.archive.close() for index in range(last_pipe): processes[index].stdout.close() - processes[index].stderr.close() - for index, status in enumerate(exit_codes): - if status != 0: - raise ExtractorError("%s error: '%s' returned status code %s" % - (self.pipes[index][1], - ' '.join(self.pipes[index][0]), status)) self.archive = final_stdout - + def prepare(self): pass @@ -232,6 +234,19 @@ pieces.pop() return '.'.join(pieces) + def check_success(self, got_output): + self.stderr.seek(0, 0) + if self.stderr.read(1): + self.stderr.seek(0, 0) + logger.warning(self.stderr.read(-1)) + self.stderr.close() + error_index = self.first_bad_exit_code() + if (not got_output) and (error_index is not None): + command = ' '.join(self.pipes[error_index][0]) + raise ExtractorError("%s error: '%s' returned status code %s" % + (self.pipes[error_index][1], command, + self.exit_codes[error_index])) + def extract(self): try: self.target = tempfile.mkdtemp(prefix='.dtrx-', dir='.') @@ -243,6 +258,7 @@ self.archive.seek(0, 0) self.extract_archive() self.check_contents() + self.check_success(self.content_type != EMPTY) except EXTRACTION_ERRORS: self.archive.close() os.chdir(old_path) @@ -285,15 +301,14 @@ output_fd, self.target = tempfile.mkstemp(prefix='.dtrx-', dir='.') except (OSError, IOError), error: raise ExtractorError("cannot extract here: %s" % (error.strerror,)) + self.run_pipes(output_fd) + os.close(output_fd) try: - self.run_pipes(output_fd) + self.check_success(os.stat(self.target)[stat.ST_SIZE] > 0) except EXTRACTION_ERRORS: - os.close(output_fd) os.unlink(self.target) raise - os.close(output_fd) - - + class TarExtractor(BaseExtractor): file_type = 'tar file' diff -r 23eb5e0a6665 -r 17d845dacff5 tests/test-tar-with-node.tar.gz Binary file tests/test-tar-with-node.tar.gz has changed diff -r 23eb5e0a6665 -r 17d845dacff5 tests/tests.yml --- a/tests/tests.yml Thu Jun 05 10:00:38 2008 -0400 +++ b/tests/tests.yml Thu Jun 05 21:24:44 2008 -0400 @@ -573,3 +573,12 @@ l n grep: "^test-deep-recursion/subsubdir/test-text\.gz$" + +- name: partly failed extraction + options: -n + filenames: test-tar-with-node.tar.gz + baseline: | + mkdir test-tar-with-node + cd test-tar-with-node + tar -zxf ../$1 + grep: Cannot mknod