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
Change-Id: Ia7d6ac8ffb03807680a36ff648aa11afafb7f481
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index e29af60..49ef84d 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -34,6 +34,7 @@
import shutil
import subprocess
import sys
+import stat
import tempfile
import threading
import time
@@ -2025,6 +2026,26 @@
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.
@@ -2070,9 +2091,11 @@
# 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):