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

Delta Between Two Patch Sets: Lib/tarfile.py

Issue 19974: tarfile doesn't overwrite symlink by directory
Left Patch Set: Created 5 years, 8 months ago
Right Patch Set: Created 5 years, 6 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 189 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 1570 matching lines...) Expand 10 before | Expand all | Expand 10 after
1839 1846
1840 def list(self, verbose=True): 1847 def list(self, verbose=True):
1841 """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
1842 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
1843 output is produced. 1850 output is produced.
1844 """ 1851 """
1845 self._check() 1852 self._check()
1846 1853
1847 for tarinfo in self: 1854 for tarinfo in self:
1848 if verbose: 1855 if verbose:
1849 print(stat.filemode(tarinfo.mode), end=' ') 1856 _safe_print(stat.filemode(tarinfo.mode))
1850 print("%s/%s" % (tarinfo.uname or tarinfo.uid, 1857 _safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid,
1851 tarinfo.gname or tarinfo.gid), end=' ') 1858 tarinfo.gname or tarinfo.gid))
1852 if tarinfo.ischr() or tarinfo.isblk(): 1859 if tarinfo.ischr() or tarinfo.isblk():
1853 print("%10s" % ("%d,%d" \ 1860 _safe_print("%10s" %
1854 % (tarinfo.devmajor, tarinfo.devminor)), end =' ') 1861 ("%d,%d" % (tarinfo.devmajor, tarinfo.devminor)))
1855 else: 1862 else:
1856 print("%10d" % tarinfo.size, end=' ') 1863 _safe_print("%10d" % tarinfo.size)
1857 print("%d-%02d-%02d %02d:%02d:%02d" \ 1864 _safe_print("%d-%02d-%02d %02d:%02d:%02d" \
1858 % time.localtime(tarinfo.mtime)[:6], end=' ') 1865 % time.localtime(tarinfo.mtime)[:6])
1859 1866
1860 print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') 1867 _safe_print(tarinfo.name + ("/" if tarinfo.isdir() else ""))
1861 1868
1862 if verbose: 1869 if verbose:
1863 if tarinfo.issym(): 1870 if tarinfo.issym():
1864 print("->", tarinfo.linkname, end=' ') 1871 _safe_print("-> " + tarinfo.linkname)
1865 if tarinfo.islnk(): 1872 if tarinfo.islnk():
1866 print("link to", tarinfo.linkname, end=' ') 1873 _safe_print("link to " + tarinfo.linkname)
1867 print() 1874 print()
1868 1875
1869 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):
1870 """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
1871 (directory, fifo, symbolic link, etc.). If given, `arcname' 1878 (directory, fifo, symbolic link, etc.). If given, `arcname'
1872 specifies an alternative name for the file in the archive. 1879 specifies an alternative name for the file in the archive.
1873 Directories are added recursively by default. This can be avoided by 1880 Directories are added recursively by default. This can be avoided by
1874 setting `recursive' to False. `exclude' is a function that should 1881 setting `recursive' to False. `exclude' is a function that should
1875 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
1876 that expects a TarInfo object argument and returns the changed 1883 that expects a TarInfo object argument and returns the changed
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
2072 if upperdirs and not os.path.exists(upperdirs): 2079 if upperdirs and not os.path.exists(upperdirs):
2073 # Create directories that are not part of the archive with 2080 # Create directories that are not part of the archive with
2074 # default permissions. 2081 # default permissions.
2075 os.makedirs(upperdirs) 2082 os.makedirs(upperdirs)
2076 2083
2077 if tarinfo.islnk() or tarinfo.issym(): 2084 if tarinfo.islnk() or tarinfo.issym():
2078 self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) 2085 self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname))
2079 else: 2086 else:
2080 self._dbg(1, tarinfo.name) 2087 self._dbg(1, tarinfo.name)
2081 2088
2082 if os.path.exists(targetpath): 2089 if os.path.exists(targetpath) and \
Martin Panter 2018/12/16 02:37:21 What about “lexists” for handling broken links? Se
2083 if os.path.isdir(targetpath) and not os.path.islink(targetpath): 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:
2084 os.rmdir(targetpath) 2095 os.rmdir(targetpath)
2085 else: 2096 except OSError:
2086 os.remove(targetpath) 2097 pass
2098
2087 if tarinfo.isreg(): 2099 if tarinfo.isreg():
2088 self.makefile(tarinfo, targetpath) 2100 self.makefile(tarinfo, targetpath)
2089 elif tarinfo.isdir(): 2101 elif tarinfo.isdir():
2090 self.makedir(tarinfo, targetpath) 2102 self.makedir(tarinfo, targetpath)
2091 elif tarinfo.isfifo(): 2103 elif tarinfo.isfifo():
2092 self.makefifo(tarinfo, targetpath) 2104 self.makefifo(tarinfo, targetpath)
2093 elif tarinfo.ischr() or tarinfo.isblk(): 2105 elif tarinfo.ischr() or tarinfo.isblk():
2094 self.makedev(tarinfo, targetpath) 2106 self.makedev(tarinfo, targetpath)
2095 elif tarinfo.islnk() or tarinfo.issym(): 2107 elif tarinfo.islnk() or tarinfo.issym():
2096 self.makelink(tarinfo, targetpath) 2108 self.makelink(tarinfo, targetpath)
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
2513 tf.add(file_name) 2525 tf.add(file_name)
2514 2526
2515 if args.verbose: 2527 if args.verbose:
2516 print('{!r} file created.'.format(tar_name)) 2528 print('{!r} file created.'.format(tar_name))
2517 2529
2518 else: 2530 else:
2519 parser.exit(1, parser.format_help()) 2531 parser.exit(1, parser.format_help())
2520 2532
2521 if __name__ == '__main__': 2533 if __name__ == '__main__':
2522 main() 2534 main()
LEFTRIGHT

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