Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(33089)

Delta Between Two Patch Sets: Lib/tarfile.py

Issue 19974: tarfile doesn't overwrite symlink by directory
Left Patch Set: Created 5 years, 9 months ago
Right Patch Set: Created 5 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Lib/test/test_tarfile.py » ('j') | Lib/test/test_tarfile.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 #------------------------------------------------------------------- 2 #-------------------------------------------------------------------
3 # tarfile.py 3 # tarfile.py
4 #------------------------------------------------------------------- 4 #-------------------------------------------------------------------
5 # Copyright (C) 2002 Lars Gustaebel <lars@gustaebel.de> 5 # Copyright (C) 2002 Lars Gustaebel <lars@gustaebel.de>
6 # All rights reserved. 6 # All rights reserved.
7 # 7 #
8 # Permission is hereby granted, free of charge, to any person 8 # Permission is hereby granted, free of charge, to any person
9 # obtaining a copy of this software and associated documentation 9 # obtaining a copy of this software and associated documentation
10 # files (the "Software"), to deal in the Software without 10 # files (the "Software"), to deal in the Software without
(...skipping 29 matching lines...) Expand all
40 #--------- 40 #---------
41 import sys 41 import sys
42 import os 42 import os
43 import io 43 import io
44 import shutil 44 import shutil
45 import stat 45 import stat
46 import time 46 import time
47 import struct 47 import struct
48 import copy 48 import copy
49 import re 49 import re
50 import errno
Martin Panter 2018/12/16 02:37:21 What is this needed for?
50 51
51 try: 52 try:
52 import grp, pwd 53 import grp, pwd
53 except ImportError: 54 except ImportError:
54 grp = pwd = None 55 grp = pwd = None
55 56
56 # os.symlink on Windows prior to 6.0 raises NotImplementedError 57 # os.symlink on Windows prior to 6.0 raises NotImplementedError
57 symlink_exception = (AttributeError, NotImplementedError) 58 symlink_exception = (AttributeError, NotImplementedError)
58 try: 59 try:
59 # OSError (winerror=1314) will be raised if the caller does not hold the 60 # OSError (winerror=1314) will be raised if the caller does not hold the
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 """ 190 """
190 # POSIX 1003.1-1988 requires numbers to be encoded as a string of 191 # POSIX 1003.1-1988 requires numbers to be encoded as a string of
191 # octal digits followed by a null-byte, this allows values up to 192 # octal digits followed by a null-byte, this allows values up to
192 # (8**(digits-1))-1. GNU tar allows storing numbers greater than 193 # (8**(digits-1))-1. GNU tar allows storing numbers greater than
193 # that if necessary. A leading 0o200 or 0o377 byte indicate this 194 # that if necessary. A leading 0o200 or 0o377 byte indicate this
194 # particular encoding, the following digits-1 bytes are a big-endian 195 # particular encoding, the following digits-1 bytes are a big-endian
195 # base-256 representation. This allows values up to (256**(digits-1))-1. 196 # base-256 representation. This allows values up to (256**(digits-1))-1.
196 # A 0o200 byte indicates a positive number, a 0o377 byte a negative 197 # A 0o200 byte indicates a positive number, a 0o377 byte a negative
197 # number. 198 # number.
198 if 0 <= n < 8 ** (digits - 1): 199 if 0 <= n < 8 ** (digits - 1):
199 s = bytes("%0*o" % (digits - 1, n), "ascii") + NUL 200 s = bytes("%0*o" % (digits - 1, int(n)), "ascii") + NUL
200 elif format == GNU_FORMAT and -256 ** (digits - 1) <= n < 256 ** (digits - 1 ): 201 elif format == GNU_FORMAT and -256 ** (digits - 1) <= n < 256 ** (digits - 1 ):
201 if n >= 0: 202 if n >= 0:
202 s = bytearray([0o200]) 203 s = bytearray([0o200])
203 else: 204 else:
204 s = bytearray([0o377]) 205 s = bytearray([0o377])
205 n = 256 ** digits + n 206 n = 256 ** digits + n
206 207
207 for i in range(digits - 1): 208 for i in range(digits - 1):
208 s.insert(1, n & 0o377) 209 s.insert(1, n & 0o377)
209 n >>= 8 210 n >>= 8
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 raise OSError("end of file reached") 250 raise OSError("end of file reached")
250 dst.write(buf) 251 dst.write(buf)
251 return 252 return
252 253
253 def filemode(mode): 254 def filemode(mode):
254 """Deprecated in this location; use stat.filemode.""" 255 """Deprecated in this location; use stat.filemode."""
255 import warnings 256 import warnings
256 warnings.warn("deprecated in favor of stat.filemode", 257 warnings.warn("deprecated in favor of stat.filemode",
257 DeprecationWarning, 2) 258 DeprecationWarning, 2)
258 return stat.filemode(mode) 259 return stat.filemode(mode)
260
261 def _safe_print(s):
262 encoding = getattr(sys.stdout, 'encoding', None)
263 if encoding is not None:
264 s = s.encode(encoding, 'backslashreplace').decode(encoding)
265 print(s, end=' ')
259 266
260 267
261 class TarError(Exception): 268 class TarError(Exception):
262 """Base exception.""" 269 """Base exception."""
263 pass 270 pass
264 class ExtractError(TarError): 271 class ExtractError(TarError):
265 """General exception for extract errors.""" 272 """General exception for extract errors."""
266 pass 273 pass
267 class ReadError(TarError): 274 class ReadError(TarError):
268 """Exception for unreadable tar archives.""" 275 """Exception for unreadable tar archives."""
(...skipping 1129 matching lines...) Expand 10 before | Expand all | Expand 10 after
1398 tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, 1405 tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,
1399 errors="surrogateescape", pax_headers=None, debug=None, errorlevel=N one): 1406 errors="surrogateescape", pax_headers=None, debug=None, errorlevel=N one):
1400 """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to 1407 """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
1401 read from an existing archive, 'a' to append data to an existing 1408 read from an existing archive, 'a' to append data to an existing
1402 file or 'w' to create a new file overwriting an existing one. `mode' 1409 file or 'w' to create a new file overwriting an existing one. `mode'
1403 defaults to 'r'. 1410 defaults to 'r'.
1404 If `fileobj' is given, it is used for reading or writing data. If it 1411 If `fileobj' is given, it is used for reading or writing data. If it
1405 can be determined, `mode' is overridden by `fileobj's mode. 1412 can be determined, `mode' is overridden by `fileobj's mode.
1406 `fileobj' is not closed, when TarFile is closed. 1413 `fileobj' is not closed, when TarFile is closed.
1407 """ 1414 """
1408 if len(mode) > 1 or mode not in "raw": 1415 modes = {"r": "rb", "a": "r+b", "w": "wb"}
1416 if mode not in modes:
1409 raise ValueError("mode must be 'r', 'a' or 'w'") 1417 raise ValueError("mode must be 'r', 'a' or 'w'")
1410 self.mode = mode 1418 self.mode = mode
1411 self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] 1419 self._mode = modes[mode]
1412 1420
1413 if not fileobj: 1421 if not fileobj:
1414 if self.mode == "a" and not os.path.exists(name): 1422 if self.mode == "a" and not os.path.exists(name):
1415 # Create nonexistent files in append mode. 1423 # Create nonexistent files in append mode.
1416 self.mode = "w" 1424 self.mode = "w"
1417 self._mode = "wb" 1425 self._mode = "wb"
1418 fileobj = bltn_open(name, self._mode) 1426 fileobj = bltn_open(name, self._mode)
1419 self._extfileobj = False 1427 self._extfileobj = False
1420 else: 1428 else:
1421 if name is None and hasattr(fileobj, "name"): 1429 if name is None and hasattr(fileobj, "name"):
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 func = getattr(cls, cls.OPEN_METH[comptype]) 1565 func = getattr(cls, cls.OPEN_METH[comptype])
1558 else: 1566 else:
1559 raise CompressionError("unknown compression type %r" % comptype) 1567 raise CompressionError("unknown compression type %r" % comptype)
1560 return func(name, filemode, fileobj, **kwargs) 1568 return func(name, filemode, fileobj, **kwargs)
1561 1569
1562 elif "|" in mode: 1570 elif "|" in mode:
1563 filemode, comptype = mode.split("|", 1) 1571 filemode, comptype = mode.split("|", 1)
1564 filemode = filemode or "r" 1572 filemode = filemode or "r"
1565 comptype = comptype or "tar" 1573 comptype = comptype or "tar"
1566 1574
1567 if filemode not in "rw": 1575 if filemode not in ("r", "w"):
1568 raise ValueError("mode must be 'r' or 'w'") 1576 raise ValueError("mode must be 'r' or 'w'")
1569 1577
1570 stream = _Stream(name, filemode, comptype, fileobj, bufsize) 1578 stream = _Stream(name, filemode, comptype, fileobj, bufsize)
1571 try: 1579 try:
1572 t = cls(name, filemode, stream, **kwargs) 1580 t = cls(name, filemode, stream, **kwargs)
1573 except: 1581 except:
1574 stream.close() 1582 stream.close()
1575 raise 1583 raise
1576 t._extfileobj = False 1584 t._extfileobj = False
1577 return t 1585 return t
1578 1586
1579 elif mode in "aw": 1587 elif mode in ("a", "w"):
1580 return cls.taropen(name, mode, fileobj, **kwargs) 1588 return cls.taropen(name, mode, fileobj, **kwargs)
1581 1589
1582 raise ValueError("undiscernible mode") 1590 raise ValueError("undiscernible mode")
1583 1591
1584 @classmethod 1592 @classmethod
1585 def taropen(cls, name, mode="r", fileobj=None, **kwargs): 1593 def taropen(cls, name, mode="r", fileobj=None, **kwargs):
1586 """Open uncompressed tar archive name for reading or writing. 1594 """Open uncompressed tar archive name for reading or writing.
1587 """ 1595 """
1588 if len(mode) > 1 or mode not in "raw": 1596 if mode not in ("r", "a", "w"):
1589 raise ValueError("mode must be 'r', 'a' or 'w'") 1597 raise ValueError("mode must be 'r', 'a' or 'w'")
1590 return cls(name, mode, fileobj, **kwargs) 1598 return cls(name, mode, fileobj, **kwargs)
1591 1599
1592 @classmethod 1600 @classmethod
1593 def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): 1601 def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):
1594 """Open gzip compressed tar archive name for reading or writing. 1602 """Open gzip compressed tar archive name for reading or writing.
1595 Appending is not allowed. 1603 Appending is not allowed.
1596 """ 1604 """
1597 if len(mode) > 1 or mode not in "rw": 1605 if mode not in ("r", "w"):
1598 raise ValueError("mode must be 'r' or 'w'") 1606 raise ValueError("mode must be 'r' or 'w'")
1599 1607
1600 try: 1608 try:
1601 import gzip 1609 import gzip
1602 gzip.GzipFile 1610 gzip.GzipFile
1603 except (ImportError, AttributeError): 1611 except (ImportError, AttributeError):
1604 raise CompressionError("gzip module is not available") 1612 raise CompressionError("gzip module is not available")
1605 1613
1606 extfileobj = fileobj is not None
1607 try: 1614 try:
1608 fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) 1615 fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj)
1616 except OSError:
1617 if fileobj is not None and mode == 'r':
1618 raise ReadError("not a gzip file")
1619 raise
1620
1621 try:
1609 t = cls.taropen(name, mode, fileobj, **kwargs) 1622 t = cls.taropen(name, mode, fileobj, **kwargs)
1610 except OSError: 1623 except OSError:
1611 if not extfileobj and fileobj is not None: 1624 fileobj.close()
1612 fileobj.close() 1625 if mode == 'r':
1613 if fileobj is None: 1626 raise ReadError("not a gzip file")
1614 raise 1627 raise
1615 raise ReadError("not a gzip file")
1616 except: 1628 except:
1617 if not extfileobj and fileobj is not None: 1629 fileobj.close()
1618 fileobj.close()
1619 raise 1630 raise
1620 t._extfileobj = extfileobj 1631 t._extfileobj = False
1621 return t 1632 return t
1622 1633
1623 @classmethod 1634 @classmethod
1624 def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): 1635 def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):
1625 """Open bzip2 compressed tar archive name for reading or writing. 1636 """Open bzip2 compressed tar archive name for reading or writing.
1626 Appending is not allowed. 1637 Appending is not allowed.
1627 """ 1638 """
1628 if len(mode) > 1 or mode not in "rw": 1639 if mode not in ("r", "w"):
1629 raise ValueError("mode must be 'r' or 'w'.") 1640 raise ValueError("mode must be 'r' or 'w'.")
1630 1641
1631 try: 1642 try:
1632 import bz2 1643 import bz2
1633 except ImportError: 1644 except ImportError:
1634 raise CompressionError("bz2 module is not available") 1645 raise CompressionError("bz2 module is not available")
1635 1646
1636 fileobj = bz2.BZ2File(fileobj or name, mode, 1647 fileobj = bz2.BZ2File(fileobj or name, mode,
1637 compresslevel=compresslevel) 1648 compresslevel=compresslevel)
1638 1649
1639 try: 1650 try:
1640 t = cls.taropen(name, mode, fileobj, **kwargs) 1651 t = cls.taropen(name, mode, fileobj, **kwargs)
1641 except (OSError, EOFError): 1652 except (OSError, EOFError):
1642 fileobj.close() 1653 fileobj.close()
1643 raise ReadError("not a bzip2 file") 1654 if mode == 'r':
1655 raise ReadError("not a bzip2 file")
1656 raise
1657 except:
1658 fileobj.close()
1659 raise
1644 t._extfileobj = False 1660 t._extfileobj = False
1645 return t 1661 return t
1646 1662
1647 @classmethod 1663 @classmethod
1648 def xzopen(cls, name, mode="r", fileobj=None, preset=None, **kwargs): 1664 def xzopen(cls, name, mode="r", fileobj=None, preset=None, **kwargs):
1649 """Open lzma compressed tar archive name for reading or writing. 1665 """Open lzma compressed tar archive name for reading or writing.
1650 Appending is not allowed. 1666 Appending is not allowed.
1651 """ 1667 """
1652 if mode not in ("r", "w"): 1668 if mode not in ("r", "w"):
1653 raise ValueError("mode must be 'r' or 'w'") 1669 raise ValueError("mode must be 'r' or 'w'")
1654 1670
1655 try: 1671 try:
1656 import lzma 1672 import lzma
1657 except ImportError: 1673 except ImportError:
1658 raise CompressionError("lzma module is not available") 1674 raise CompressionError("lzma module is not available")
1659 1675
1660 fileobj = lzma.LZMAFile(fileobj or name, mode, preset=preset) 1676 fileobj = lzma.LZMAFile(fileobj or name, mode, preset=preset)
1661 1677
1662 try: 1678 try:
1663 t = cls.taropen(name, mode, fileobj, **kwargs) 1679 t = cls.taropen(name, mode, fileobj, **kwargs)
1664 except (lzma.LZMAError, EOFError): 1680 except (lzma.LZMAError, EOFError):
1665 fileobj.close() 1681 fileobj.close()
1666 raise ReadError("not an lzma file") 1682 if mode == 'r':
1683 raise ReadError("not an lzma file")
1684 raise
1685 except:
1686 fileobj.close()
1687 raise
1667 t._extfileobj = False 1688 t._extfileobj = False
1668 return t 1689 return t
1669 1690
1670 # All *open() methods are registered here. 1691 # All *open() methods are registered here.
1671 OPEN_METH = { 1692 OPEN_METH = {
1672 "tar": "taropen", # uncompressed tar 1693 "tar": "taropen", # uncompressed tar
1673 "gz": "gzopen", # gzip compressed tar 1694 "gz": "gzopen", # gzip compressed tar
1674 "bz2": "bz2open", # bzip2 compressed tar 1695 "bz2": "bz2open", # bzip2 compressed tar
1675 "xz": "xzopen" # lzma compressed tar 1696 "xz": "xzopen" # lzma compressed tar
1676 } 1697 }
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
1825 1846
1826 def list(self, verbose=True): 1847 def list(self, verbose=True):
1827 """Print a table of contents to sys.stdout. If `verbose' is False, only 1848 """Print a table of contents to sys.stdout. If `verbose' is False, only
1828 the names of the members are printed. If it is True, an `ls -l'-like 1849 the names of the members are printed. If it is True, an `ls -l'-like
1829 output is produced. 1850 output is produced.
1830 """ 1851 """
1831 self._check() 1852 self._check()
1832 1853
1833 for tarinfo in self: 1854 for tarinfo in self:
1834 if verbose: 1855 if verbose:
1835 print(stat.filemode(tarinfo.mode), end=' ') 1856 _safe_print(stat.filemode(tarinfo.mode))
1836 print("%s/%s" % (tarinfo.uname or tarinfo.uid, 1857 _safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid,
1837 tarinfo.gname or tarinfo.gid), end=' ') 1858 tarinfo.gname or tarinfo.gid))
1838 if tarinfo.ischr() or tarinfo.isblk(): 1859 if tarinfo.ischr() or tarinfo.isblk():
1839 print("%10s" % ("%d,%d" \ 1860 _safe_print("%10s" %
1840 % (tarinfo.devmajor, tarinfo.devminor)), end =' ') 1861 ("%d,%d" % (tarinfo.devmajor, tarinfo.devminor)))
1841 else: 1862 else:
1842 print("%10d" % tarinfo.size, end=' ') 1863 _safe_print("%10d" % tarinfo.size)
1843 print("%d-%02d-%02d %02d:%02d:%02d" \ 1864 _safe_print("%d-%02d-%02d %02d:%02d:%02d" \
1844 % time.localtime(tarinfo.mtime)[:6], end=' ') 1865 % time.localtime(tarinfo.mtime)[:6])
1845 1866
1846 print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') 1867 _safe_print(tarinfo.name + ("/" if tarinfo.isdir() else ""))
1847 1868
1848 if verbose: 1869 if verbose:
1849 if tarinfo.issym(): 1870 if tarinfo.issym():
1850 print("->", tarinfo.linkname, end=' ') 1871 _safe_print("-> " + tarinfo.linkname)
1851 if tarinfo.islnk(): 1872 if tarinfo.islnk():
1852 print("link to", tarinfo.linkname, end=' ') 1873 _safe_print("link to " + tarinfo.linkname)
1853 print() 1874 print()
1854 1875
1855 def add(self, name, arcname=None, recursive=True, exclude=None, *, filter=No ne): 1876 def add(self, name, arcname=None, recursive=True, exclude=None, *, filter=No ne):
1856 """Add the file `name' to the archive. `name' may be any type of file 1877 """Add the file `name' to the archive. `name' may be any type of file
1857 (directory, fifo, symbolic link, etc.). If given, `arcname' 1878 (directory, fifo, symbolic link, etc.). If given, `arcname'
1858 specifies an alternative name for the file in the archive. 1879 specifies an alternative name for the file in the archive.
1859 Directories are added recursively by default. This can be avoided by 1880 Directories are added recursively by default. This can be avoided by
1860 setting `recursive' to False. `exclude' is a function that should 1881 setting `recursive' to False. `exclude' is a function that should
1861 return True for each filename to be excluded. `filter' is a function 1882 return True for each filename to be excluded. `filter' is a function
1862 that expects a TarInfo object argument and returns the changed 1883 that expects a TarInfo object argument and returns the changed
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1989 if isinstance(member, str): 2010 if isinstance(member, str):
1990 tarinfo = self.getmember(member) 2011 tarinfo = self.getmember(member)
1991 else: 2012 else:
1992 tarinfo = member 2013 tarinfo = member
1993 2014
1994 # Prepare the link target for makelink(). 2015 # Prepare the link target for makelink().
1995 if tarinfo.islnk(): 2016 if tarinfo.islnk():
1996 tarinfo._link_target = os.path.join(path, tarinfo.linkname) 2017 tarinfo._link_target = os.path.join(path, tarinfo.linkname)
1997 2018
1998 try: 2019 try:
1999 drv, normalized_path = os.path.splitdrive(path) 2020 self._extract_member(tarinfo, os.path.join(path, tarinfo.name),
storchaka 2013/12/15 21:38:11 Why these changes are needed? They are not look re
vajrasky 2014/01/16 08:21:52 There is an underlying bug on Windows. Without the
storchaka 2014/01/16 08:31:23 Yes, please open a separate ticket.
2000 normalized_path = normalized_path.replace(os.sep, '/') 2021 set_attrs=set_attrs)
2001 joined_path = '/' + tarinfo.name
2002 # We don't want to join '/home/user' and 'home/user/file' to avoid
storchaka 2013/12/15 21:38:11 Why not?
vajrasky 2014/01/16 08:21:52 I'll explain it later when I get back to my Window
2003 # '/home/user/home/user/file'.
2004 native_tarinfo_name = tarinfo.name.replace('/', os.sep)
2005 if normalized_path != joined_path[:len(normalized_path)]:
2006 joined_path = os.path.join(path, native_tarinfo_name)
2007 else:
2008 # tarinfo.name is an absolute path
2009 if os.name == 'nt':
2010 joined_path = drv + os.sep + native_tarinfo_name
2011 else:
2012 joined_path = os.sep + native_tarinfo_name
2013 self._extract_member(tarinfo, joined_path, set_attrs=set_attrs)
2014 except OSError as e: 2022 except OSError as e:
2015 if self.errorlevel > 0: 2023 if self.errorlevel > 0:
2016 raise 2024 raise
2017 else: 2025 else:
2018 if e.filename is None: 2026 if e.filename is None:
2019 self._dbg(1, "tarfile: %s" % e.strerror) 2027 self._dbg(1, "tarfile: %s" % e.strerror)
2020 else: 2028 else:
2021 self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) 2029 self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
2022 except ExtractError as e: 2030 except ExtractError as e:
2023 if self.errorlevel > 1: 2031 if self.errorlevel > 1:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
2071 if upperdirs and not os.path.exists(upperdirs): 2079 if upperdirs and not os.path.exists(upperdirs):
2072 # Create directories that are not part of the archive with 2080 # Create directories that are not part of the archive with
2073 # default permissions. 2081 # default permissions.
2074 os.makedirs(upperdirs) 2082 os.makedirs(upperdirs)
2075 2083
2076 if tarinfo.islnk() or tarinfo.issym(): 2084 if tarinfo.islnk() or tarinfo.issym():
2077 self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) 2085 self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname))
2078 else: 2086 else:
2079 self._dbg(1, tarinfo.name) 2087 self._dbg(1, tarinfo.name)
2080 2088
2089 if os.path.exists(targetpath) and \
Martin Panter 2018/12/16 02:37:21 What about “lexists” for handling broken links? Se
2090 (not os.path.isdir(targetpath) or os.path.islink(targetpath)):
2091 os.remove(targetpath)
2092 else:
2093 # File should be able to overwrite empty directory
2094 try:
2095 os.rmdir(targetpath)
2096 except OSError:
2097 pass
2098
2081 if tarinfo.isreg(): 2099 if tarinfo.isreg():
2082 self.makefile(tarinfo, targetpath) 2100 self.makefile(tarinfo, targetpath)
2083 elif tarinfo.isdir(): 2101 elif tarinfo.isdir():
2084 self.makedir(tarinfo, targetpath) 2102 self.makedir(tarinfo, targetpath)
2085 elif tarinfo.isfifo(): 2103 elif tarinfo.isfifo():
2086 self.makefifo(tarinfo, targetpath) 2104 self.makefifo(tarinfo, targetpath)
2087 elif tarinfo.ischr() or tarinfo.isblk(): 2105 elif tarinfo.ischr() or tarinfo.isblk():
2088 self.makedev(tarinfo, targetpath) 2106 self.makedev(tarinfo, targetpath)
2089 elif tarinfo.islnk() or tarinfo.issym(): 2107 elif tarinfo.islnk() or tarinfo.issym():
2090 self.makelink(tarinfo, targetpath) 2108 self.makelink(tarinfo, targetpath)
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
2161 os.makedev(tarinfo.devmajor, tarinfo.devminor)) 2179 os.makedev(tarinfo.devmajor, tarinfo.devminor))
2162 2180
2163 def makelink(self, tarinfo, targetpath): 2181 def makelink(self, tarinfo, targetpath):
2164 """Make a (symbolic) link called targetpath. If it cannot be created 2182 """Make a (symbolic) link called targetpath. If it cannot be created
2165 (platform limitation), we try to make a copy of the referenced file 2183 (platform limitation), we try to make a copy of the referenced file
2166 instead of a link. 2184 instead of a link.
2167 """ 2185 """
2168 try: 2186 try:
2169 # For systems that support symbolic and hard links. 2187 # For systems that support symbolic and hard links.
2170 if tarinfo.issym(): 2188 if tarinfo.issym():
2171 if os.path.exists(targetpath):
storchaka 2013/12/15 21:38:11 I think we should remove targetpath in all cases.
2172 os.unlink(targetpath)
2173 if os.name == 'nt' and os.path.isdir(tarinfo.linkname): 2189 if os.name == 'nt' and os.path.isdir(tarinfo.linkname):
2174 os.symlink(tarinfo.linkname, targetpath, target_is_directory =True) 2190 os.symlink(tarinfo.linkname, targetpath, target_is_directory =True)
2175 else: 2191 else:
2176 os.symlink(tarinfo.linkname, targetpath) 2192 os.symlink(tarinfo.linkname, targetpath)
2177 else: 2193 else:
2178 # See extract(). 2194 # See extract().
2179 if os.path.exists(tarinfo._link_target): 2195 if os.path.exists(tarinfo._link_target):
2180 os.link(tarinfo._link_target, targetpath) 2196 os.link(tarinfo._link_target, targetpath)
2181 else: 2197 else:
2182 self._extract_member(self._find_link_target(tarinfo), 2198 self._extract_member(self._find_link_target(tarinfo),
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
2509 tf.add(file_name) 2525 tf.add(file_name)
2510 2526
2511 if args.verbose: 2527 if args.verbose:
2512 print('{!r} file created.'.format(tar_name)) 2528 print('{!r} file created.'.format(tar_name))
2513 2529
2514 else: 2530 else:
2515 parser.exit(1, parser.format_help()) 2531 parser.exit(1, parser.format_help())
2516 2532
2517 if __name__ == '__main__': 2533 if __name__ == '__main__':
2518 main() 2534 main()
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+