169 self.archive.flush() |
169 self.archive.flush() |
170 |
170 |
171 def prepare(self): |
171 def prepare(self): |
172 pass |
172 pass |
173 |
173 |
174 def check_contents(self): |
174 def check_included_archive(self, filename): |
175 archive_type = None |
175 if extractor_map.has_key(mimetypes.guess_type(filename)[0]): |
176 filenames = self.get_filenames() |
176 self.included_archives.append(filename) |
177 try: |
177 |
178 filename = filenames.next() |
178 def check_first_filename(self, filenames): |
179 if extractor_map.has_key(mimetypes.guess_type(filename)[0]): |
179 try: |
180 self.included_archives.append(filename) |
180 first_filename = filenames.next() |
181 first_part = filename.split('/', 1)[0] + '/' |
|
182 except StopIteration: |
181 except StopIteration: |
183 filenames.stop() |
182 filenames.stop() |
184 return EMPTY |
183 return (None, None) |
|
184 self.check_included_archive(first_filename) |
|
185 parts = first_filename.split('/') |
|
186 first_part = [parts[0]] |
|
187 if parts[0] == '.': |
|
188 first_part.append(parts[1]) |
|
189 return (first_filename, '/'.join(first_part + [''])) |
|
190 |
|
191 def check_second_filename(self, filenames, first_part, first_filename): |
|
192 try: |
|
193 filename = filenames.next() |
|
194 except StopIteration: |
|
195 return ONE_ENTRY, first_filename |
|
196 self.check_included_archive(filename) |
|
197 if not filename.startswith(first_part): |
|
198 return BOMB, None |
|
199 return None, first_part |
|
200 |
|
201 def check_contents(self): |
|
202 filenames = self.get_filenames() |
|
203 first_filename, first_part = self.check_first_filename(filenames) |
|
204 if first_filename is None: |
|
205 return (EMPTY, None) |
|
206 archive_type, type_info = self.check_second_filename(filenames, |
|
207 first_part, |
|
208 first_filename) |
185 for filename in filenames: |
209 for filename in filenames: |
186 if extractor_map.has_key(mimetypes.guess_type(filename)[0]): |
210 self.check_included_archive(filename) |
187 self.included_archives.append(filename) |
211 if (archive_type != BOMB) and (not filename.startswith(first_part)): |
188 if (archive_type is None) and (not filename.startswith(first_part)): |
|
189 archive_type = BOMB |
212 archive_type = BOMB |
|
213 type_info = None |
190 filenames.stop() |
214 filenames.stop() |
191 if archive_type: |
215 if archive_type is None: |
192 return archive_type |
216 if self.basename() == first_part[:-1]: |
193 if self.basename() == first_part[:-1]: |
217 archive_type = MATCHING_DIRECTORY |
194 return MATCHING_DIRECTORY |
218 else: |
195 return first_part |
219 archive_type = ONE_ENTRY |
|
220 return archive_type, type_info |
196 |
221 |
197 def basename(self): |
222 def basename(self): |
198 pieces = os.path.basename(self.filename).split('.') |
223 pieces = os.path.basename(self.filename).split('.') |
199 extension = '.' + pieces[-1] |
224 extension = '.' + pieces[-1] |
200 if mimetypes.encodings_map.has_key(extension): |
225 if mimetypes.encodings_map.has_key(extension): |
268 pieces.pop() |
293 pieces.pop() |
269 return '.'.join(pieces) |
294 return '.'.join(pieces) |
270 |
295 |
271 def check_contents(self): |
296 def check_contents(self): |
272 CpioExtractor.check_contents(self) |
297 CpioExtractor.check_contents(self) |
273 return BOMB |
298 return (BOMB, None) |
274 |
299 |
275 |
300 |
276 class DebExtractor(TarExtractor): |
301 class DebExtractor(TarExtractor): |
277 def prepare(self): |
302 def prepare(self): |
278 self.pipe(['ar', 'p', self.filename, 'data.tar.gz'], |
303 self.pipe(['ar', 'p', self.filename, 'data.tar.gz'], |
306 |
331 |
307 def get_filenames(self): |
332 def get_filenames(self): |
308 yield self.basename() |
333 yield self.basename() |
309 |
334 |
310 def check_contents(self): |
335 def check_contents(self): |
311 return COMPRESSED |
336 return (ONE_ENTRY_KNOWN, self.basename()) |
312 |
337 |
313 def extract(self, path): |
338 def extract(self, path): |
314 output = open(path, 'w') |
339 output = open(path, 'w') |
|
340 self.archive.seek(0, 0) |
315 self.run(['cat'], "output write", stdin=self.archive, stdout=output) |
341 self.run(['cat'], "output write", stdin=self.archive, stdout=output) |
316 output.close() |
342 output.close() |
317 |
343 |
318 |
344 |
319 class BaseHandler(object): |
345 class BaseHandler(object): |
320 def __init__(self, extractor, contents, options): |
346 def __init__(self, extractor, contents, content_name, options): |
321 self.logger = logging.getLogger('dtrx-log') |
347 self.logger = logging.getLogger('dtrx-log') |
322 self.extractor = extractor |
348 self.extractor = extractor |
323 self.contents = contents |
349 self.contents = contents |
|
350 self.content_name = content_name |
324 self.options = options |
351 self.options = options |
325 self.target = None |
352 self.target = None |
326 |
353 |
327 def extract(self): |
354 def extract(self): |
328 try: |
355 try: |
351 # Match . . tempdir + checked |
378 # Match . . tempdir + checked |
352 # Bomb . basename DirectoryChecked |
379 # Bomb . basename DirectoryChecked |
353 |
380 |
354 class FlatHandler(BaseHandler): |
381 class FlatHandler(BaseHandler): |
355 def can_handle(contents, options): |
382 def can_handle(contents, options): |
356 return ((options.flat and (contents != COMPRESSED)) or |
383 return ((options.flat and (contents != ONE_ENTRY_KNOWN)) or |
357 (options.overwrite and (contents == MATCHING_DIRECTORY))) |
384 (options.overwrite and (contents == MATCHING_DIRECTORY))) |
358 can_handle = staticmethod(can_handle) |
385 can_handle = staticmethod(can_handle) |
359 |
386 |
360 def __init__(self, extractor, contents, options): |
387 def __init__(self, extractor, contents, content_name, options): |
361 BaseHandler.__init__(self, extractor, contents, options) |
388 BaseHandler.__init__(self, extractor, contents, content_name, options) |
362 self.target = '.' |
389 self.target = '.' |
363 |
390 |
364 def cleanup(self): |
391 def cleanup(self): |
365 for filename in self.extractor.get_filenames(): |
392 for filename in self.extractor.get_filenames(): |
366 stat_info = os.stat(filename) |
393 stat_info = os.stat(filename) |
370 os.chmod(filename, stat_info.st_mode | perms) |
397 os.chmod(filename, stat_info.st_mode | perms) |
371 |
398 |
372 |
399 |
373 class OverwriteHandler(BaseHandler): |
400 class OverwriteHandler(BaseHandler): |
374 def can_handle(contents, options): |
401 def can_handle(contents, options): |
375 return ((options.flat and (contents == COMPRESSED)) or |
402 return ((options.flat and (contents == ONE_ENTRY_KNOWN)) or |
376 (options.overwrite and (contents != MATCHING_DIRECTORY))) |
403 (options.overwrite and (contents != MATCHING_DIRECTORY))) |
377 can_handle = staticmethod(can_handle) |
404 can_handle = staticmethod(can_handle) |
378 |
405 |
379 def __init__(self, extractor, contents, options): |
406 def __init__(self, extractor, contents, content_name, options): |
380 BaseHandler.__init__(self, extractor, contents, options) |
407 BaseHandler.__init__(self, extractor, contents, content_name, options) |
381 self.target = self.extractor.basename() |
408 self.target = self.extractor.basename() |
382 |
409 |
383 |
410 |
384 class MatchHandler(BaseHandler): |
411 class MatchHandler(BaseHandler): |
385 def can_handle(contents, options): |
412 def can_handle(contents, options): |
386 return ((contents == MATCHING_DIRECTORY) or |
413 return ((contents == MATCHING_DIRECTORY) or |
387 (hasattr(contents, 'encode') and |
414 ((contents == ONE_ENTRY) and |
388 (options.onedir_policy in (EXTRACT_RENAME, EXTRACT_HERE)))) |
415 (options.onedir_policy in (EXTRACT_RENAME, EXTRACT_HERE)))) |
389 can_handle = staticmethod(can_handle) |
416 can_handle = staticmethod(can_handle) |
390 |
417 |
391 def extract(self): |
418 def extract(self): |
392 if self.contents == MATCHING_DIRECTORY: |
419 if self.contents == MATCHING_DIRECTORY: |
393 basename = destination = self.extractor.basename() |
420 basename = destination = self.extractor.basename() |
394 elif self.options.onedir_policy == EXTRACT_HERE: |
421 elif self.options.onedir_policy == EXTRACT_HERE: |
395 basename = destination = self.contents.rstrip('/') |
422 basename = destination = self.content_name.rstrip('/') |
396 else: |
423 else: |
397 basename = self.contents.rstrip('/') |
424 basename = self.content_name.rstrip('/') |
398 destination = self.extractor.basename() |
425 destination = self.extractor.basename() |
399 self.target = tempdir = tempfile.mkdtemp(dir='.') |
426 self.target = tempdir = tempfile.mkdtemp(dir='.') |
400 result = BaseHandler.extract(self) |
427 result = BaseHandler.extract(self) |
401 if result is None: |
428 if result is None: |
402 checker = self.extractor.name_checker(destination) |
429 checker = self.extractor.name_checker(destination) |
409 class EmptyHandler(object): |
436 class EmptyHandler(object): |
410 def can_handle(contents, options): |
437 def can_handle(contents, options): |
411 return contents == EMPTY |
438 return contents == EMPTY |
412 can_handle = staticmethod(can_handle) |
439 can_handle = staticmethod(can_handle) |
413 |
440 |
414 def __init__(self, extractor, contents, options): pass |
441 def __init__(self, extractor, contents, content_name, options): pass |
415 def extract(self): pass |
442 def extract(self): pass |
416 def cleanup(self): pass |
443 def cleanup(self): pass |
417 |
444 |
418 |
445 |
419 class BombHandler(BaseHandler): |
446 class BombHandler(BaseHandler): |
420 def can_handle(contents, options): |
447 def can_handle(contents, options): |
421 return True |
448 return True |
422 can_handle = staticmethod(can_handle) |
449 can_handle = staticmethod(can_handle) |
423 |
450 |
424 def __init__(self, extractor, contents, options): |
451 def __init__(self, extractor, contents, content_name, options): |
425 BaseHandler.__init__(self, extractor, contents, options) |
452 BaseHandler.__init__(self, extractor, contents, content_name, options) |
426 checker = self.extractor.name_checker(self.extractor.basename()) |
453 checker = self.extractor.name_checker(self.extractor.basename()) |
427 self.target = checker.check() |
454 self.target = checker.check() |
428 |
455 |
429 |
456 |
430 extractor_map = {'application/x-tar': TarExtractor, |
457 extractor_map = {'application/x-tar': TarExtractor, |
517 except ExtractorError, error: |
547 except ExtractorError, error: |
518 return str(error) |
548 return str(error) |
519 |
549 |
520 def get_handler(self): |
550 def get_handler(self): |
521 try: |
551 try: |
522 content = self.current_extractor.check_contents() |
552 content, content_name = self.current_extractor.check_contents() |
523 if hasattr(content, 'encode'): # Archive contains one directory. |
553 if content == ONE_ENTRY: |
524 question = textwrap.wrap("%s contains one directory: %s. %s" % |
554 question = textwrap.wrap("%s contains one entry: %s." % |
525 (self.current_filename, content, |
555 (self.current_filename, content_name)) |
526 "You can:")) |
|
527 question.extend(["You can:", |
556 question.extend(["You can:", |
528 " * extract it Inside another directory", |
557 " * extract it Inside another directory", |
529 " * extract it and Rename the directory", |
558 " * extract it and Rename the directory", |
530 " * extract it Here", |
559 " * extract it Here", |
531 "What do you want to do? (I/r/h) "]) |
560 "What do you want to do? (I/r/h) "]) |
532 self.options.onedir_policy = \ |
561 self.options.onedir_policy = \ |
533 self.ask_question(question, self.policy_answers) |
562 self.ask_question(question, self.policy_answers) |
534 for handler in handlers: |
563 for handler in handlers: |
535 if handler.can_handle(content, self.options): |
564 if handler.can_handle(content, self.options): |
536 self.current_handler = handler(self.current_extractor, |
565 self.current_handler = handler(self.current_extractor, |
537 content, self.options) |
566 content, content_name, |
|
567 self.options) |
538 break |
568 break |
539 except ExtractorError, error: |
569 except ExtractorError, error: |
540 return str(error) |
570 return str(error) |
541 |
571 |
542 def recurse(self): |
572 def recurse(self): |