Handle symlinks when extracting zipfiles
python3.11's zipfile implementation does not handle symlinks. This causes important symlinks in ramdisk to be broken, and later causing a boo failure. Test: unzip a target files with symlinks, make sure symlinks are created Bug: 287896098 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2b2de0375faf9e23094f6238c38f9a49906b1882) Merged-In: Ia7d6ac8ffb03807680a36ff648aa11afafb7f481 Change-Id: Ia7d6ac8ffb03807680a36ff648aa11afafb7f481
This commit is contained in:
committed by
Android Build Coastguard Worker
parent
f604d01ba4
commit
48b23028a4
@@ -35,6 +35,7 @@ import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import stat
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
@@ -2102,6 +2103,26 @@ def Gunzip(in_filename, out_filename):
|
||||
shutil.copyfileobj(in_file, out_file)
|
||||
|
||||
|
||||
def UnzipSingleFile(input_zip: zipfile.ZipFile, info: zipfile.ZipInfo, dirname: str):
|
||||
# According to https://stackoverflow.com/questions/434641/how-do-i-set-permissions-attributes-on-a-file-in-a-zip-file-using-pythons-zip/6297838#6297838
|
||||
# higher bits of |external_attr| are unix file permission and types
|
||||
unix_filetype = info.external_attr >> 16
|
||||
|
||||
def CheckMask(a, mask):
|
||||
return (a & mask) == mask
|
||||
|
||||
def IsSymlink(a):
|
||||
return CheckMask(a, stat.S_IFLNK)
|
||||
# python3.11 zipfile implementation doesn't handle symlink correctly
|
||||
if not IsSymlink(unix_filetype):
|
||||
return input_zip.extract(info, dirname)
|
||||
if dirname is None:
|
||||
dirname = os.getcwd()
|
||||
target = os.path.join(dirname, info.filename)
|
||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||
os.symlink(input_zip.read(info).decode(), target)
|
||||
|
||||
|
||||
def UnzipToDir(filename, dirname, patterns=None):
|
||||
"""Unzips the archive to the given directory.
|
||||
|
||||
@@ -2147,9 +2168,11 @@ def UnzipToDir(filename, dirname, patterns=None):
|
||||
# There isn't any matching files. Don't unzip anything.
|
||||
if not filtered:
|
||||
return
|
||||
input_zip.extractall(dirname, filtered)
|
||||
for info in filtered:
|
||||
UnzipSingleFile(input_zip, info, dirname)
|
||||
else:
|
||||
input_zip.extractall(dirname, entries)
|
||||
for info in entries:
|
||||
UnzipSingleFile(input_zip, info, dirname)
|
||||
|
||||
|
||||
def UnzipTemp(filename, patterns=None):
|
||||
|
Reference in New Issue
Block a user