Update Windows Python3 prebuilt
Fusion2: http://fusion2/e1653ce5-a00b-4501-8f0f-1cb270563905
GCS path: gs://ndk-kokoro-release-artifacts/prod/ndk/python3/windows_release/4/20220830-004242
Prebuilt updated using: ndk/scripts/update_kokoro_prebuilts.py
Test: Treehugger, Kokoro presubmit
Bug: 244197859
Change-Id: I7e3cb5b8add31fd59e4085dba550c6fb436f1ed8
diff --git a/Lib/shutil.py b/Lib/shutil.py
index f0e833d..37bf98d 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -32,16 +32,6 @@
except ImportError:
_LZMA_SUPPORTED = False
-try:
- from pwd import getpwnam
-except ImportError:
- getpwnam = None
-
-try:
- from grp import getgrnam
-except ImportError:
- getgrnam = None
-
_WINDOWS = os.name == 'nt'
posix = nt = None
if os.name == 'posix':
@@ -261,28 +251,37 @@
if not follow_symlinks and _islink(src):
os.symlink(os.readlink(src), dst)
else:
- with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
- # macOS
- if _HAS_FCOPYFILE:
- try:
- _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
- return dst
- except _GiveupOnFastCopy:
- pass
- # Linux
- elif _USE_CP_SENDFILE:
- try:
- _fastcopy_sendfile(fsrc, fdst)
- return dst
- except _GiveupOnFastCopy:
- pass
- # Windows, see:
- # https://github.com/python/cpython/pull/7160#discussion_r195405230
- elif _WINDOWS and file_size > 0:
- _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
- return dst
+ with open(src, 'rb') as fsrc:
+ try:
+ with open(dst, 'wb') as fdst:
+ # macOS
+ if _HAS_FCOPYFILE:
+ try:
+ _fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
+ return dst
+ except _GiveupOnFastCopy:
+ pass
+ # Linux
+ elif _USE_CP_SENDFILE:
+ try:
+ _fastcopy_sendfile(fsrc, fdst)
+ return dst
+ except _GiveupOnFastCopy:
+ pass
+ # Windows, see:
+ # https://github.com/python/cpython/pull/7160#discussion_r195405230
+ elif _WINDOWS and file_size > 0:
+ _copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
+ return dst
- copyfileobj(fsrc, fdst)
+ copyfileobj(fsrc, fdst)
+
+ # Issue 43219, raise a less confusing exception
+ except IsADirectoryError as e:
+ if not os.path.exists(dst):
+ raise FileNotFoundError(f'Directory does not exist: {dst}') from e
+ else:
+ raise
return dst
@@ -647,6 +646,7 @@
if is_dir:
try:
dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd)
+ dirfd_closed = False
except OSError:
onerror(os.open, fullname, sys.exc_info())
else:
@@ -654,6 +654,8 @@
if os.path.samestat(orig_st, os.fstat(dirfd)):
_rmtree_safe_fd(dirfd, fullname, onerror)
try:
+ os.close(dirfd)
+ dirfd_closed = True
os.rmdir(entry.name, dir_fd=topfd)
except OSError:
onerror(os.rmdir, fullname, sys.exc_info())
@@ -667,7 +669,8 @@
except OSError:
onerror(os.path.islink, fullname, sys.exc_info())
finally:
- os.close(dirfd)
+ if not dirfd_closed:
+ os.close(dirfd)
else:
try:
os.unlink(entry.name, dir_fd=topfd)
@@ -710,6 +713,7 @@
return
try:
fd = os.open(path, os.O_RDONLY)
+ fd_closed = False
except Exception:
onerror(os.open, path, sys.exc_info())
return
@@ -717,6 +721,8 @@
if os.path.samestat(orig_st, os.fstat(fd)):
_rmtree_safe_fd(fd, path, onerror)
try:
+ os.close(fd)
+ fd_closed = True
os.rmdir(path)
except OSError:
onerror(os.rmdir, path, sys.exc_info())
@@ -727,7 +733,8 @@
except OSError:
onerror(os.path.islink, path, sys.exc_info())
finally:
- os.close(fd)
+ if not fd_closed:
+ os.close(fd)
else:
try:
if _rmtree_islink(path):
@@ -813,6 +820,12 @@
if _destinsrc(src, dst):
raise Error("Cannot move a directory '%s' into itself"
" '%s'." % (src, dst))
+ if (_is_immutable(src)
+ or (not os.access(src, os.W_OK) and os.listdir(src)
+ and sys.platform == 'darwin')):
+ raise PermissionError("Cannot move the non-empty directory "
+ "'%s': Lacking write permission to '%s'."
+ % (src, src))
copytree(src, real_dst, copy_function=copy_function,
symlinks=True)
rmtree(src)
@@ -830,10 +843,21 @@
dst += os.path.sep
return dst.startswith(src)
+def _is_immutable(src):
+ st = _stat(src)
+ immutable_states = [stat.UF_IMMUTABLE, stat.SF_IMMUTABLE]
+ return hasattr(st, 'st_flags') and st.st_flags in immutable_states
+
def _get_gid(name):
"""Returns a gid, given a group name."""
- if getgrnam is None or name is None:
+ if name is None:
return None
+
+ try:
+ from grp import getgrnam
+ except ImportError:
+ return None
+
try:
result = getgrnam(name)
except KeyError:
@@ -844,8 +868,14 @@
def _get_uid(name):
"""Returns an uid, given a user name."""
- if getpwnam is None or name is None:
+ if name is None:
return None
+
+ try:
+ from pwd import getpwnam
+ except ImportError:
+ return None
+
try:
result = getpwnam(name)
except KeyError:
@@ -1148,20 +1178,16 @@
if name.startswith('/') or '..' in name:
continue
- target = os.path.join(extract_dir, *name.split('/'))
- if not target:
+ targetpath = os.path.join(extract_dir, *name.split('/'))
+ if not targetpath:
continue
- _ensure_directory(target)
+ _ensure_directory(targetpath)
if not name.endswith('/'):
# file
- data = zip.read(info.filename)
- f = open(target, 'wb')
- try:
- f.write(data)
- finally:
- f.close()
- del data
+ with zip.open(name, 'r') as source, \
+ open(targetpath, 'wb') as target:
+ copyfileobj(source, target)
finally:
zip.close()