From 9a52511c5997b9981e2e50d28647e2471bf45bec Mon Sep 17 00:00:00 2001 From: Stephanie Kim Date: Thu, 25 Apr 2024 16:00:14 +0000 Subject: [PATCH] [depot_tools] Set executable bit for downloaded GCS files The downloaded file may be a binary that needs to be executed Bug: b/328065301, b/336843583 Change-Id: I0f6c959cbe3d5cf7e2717da72c98c51bbe98f7b3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5484340 Reviewed-by: Joanna Wang Commit-Queue: Stephanie Kim --- download_from_google_storage.py | 42 +++++++++++++++++++-------------- gclient.py | 11 +++++++-- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/download_from_google_storage.py b/download_from_google_storage.py index 8a0d452e0..e114df9a5 100755 --- a/download_from_google_storage.py +++ b/download_from_google_storage.py @@ -51,6 +51,26 @@ def construct_migration_file_name(gcs_object_name): return f'.{gcs_file_name}{MIGRATION_TOGGLE_FILE_SUFFIX}' +def set_executable_bit(output_filename, file_url, gsutil): + # Set executable bit. + code, err = 0, '' + if sys.platform == 'cygwin': + # Under cygwin, mark all files as executable. The executable flag in + # Google Storage will not be set when uploading from Windows, so if + # this script is running under cygwin and we're downloading an + # executable, it will be unrunnable from inside cygwin without this. + st = os.stat(output_filename) + os.chmod(output_filename, st.st_mode | stat.S_IEXEC) + elif sys.platform != 'win32': + # On non-Windows platforms, key off of the custom header + # "x-goog-meta-executable". + code, out, err = gsutil.check_call('stat', file_url) + if re.search(r'executable:\s*1', out): + st = os.stat(output_filename) + os.chmod(output_filename, st.st_mode | stat.S_IEXEC) + return code, err + + class InvalidFileError(IOError): pass @@ -399,24 +419,10 @@ def _downloader_worker_thread(thread_num, os.remove(extract_dir + '.tmp') if os.path.exists(migration_file_name): os.remove(migration_file_name) - # Set executable bit. - if sys.platform == 'cygwin': - # Under cygwin, mark all files as executable. The executable flag in - # Google Storage will not be set when uploading from Windows, so if - # this script is running under cygwin and we're downloading an - # executable, it will be unrunnable from inside cygwin without this. - st = os.stat(output_filename) - os.chmod(output_filename, st.st_mode | stat.S_IEXEC) - elif sys.platform != 'win32': - # On non-Windows platforms, key off of the custom header - # "x-goog-meta-executable". - code, out, err = gsutil.check_call('stat', file_url) - if code != 0: - out_q.put('%d> %s' % (thread_num, err)) - ret_codes.put((code, err)) - elif re.search(r'executable:\s*1', out): - st = os.stat(output_filename) - os.chmod(output_filename, st.st_mode | stat.S_IEXEC) + code, err = set_executable_bit(output_filename, file_url, gsutil) + if code != 0: + out_q.put('%d> %s' % (thread_num, err)) + ret_codes.put((code, err)) class PrinterThread(threading.Thread): diff --git a/gclient.py b/gclient.py index 1bee6eed4..9f039c7c1 100755 --- a/gclient.py +++ b/gclient.py @@ -2676,6 +2676,8 @@ class GcsDependency(Dependency): if not os.path.exists(output_dir): os.makedirs(output_dir) + gsutil = download_from_google_storage.Gsutil( + download_from_google_storage.GSUTIL_DEFAULT_PATH) if os.getenv('GCLIENT_TEST') == '1': if 'no-extract' in output_file: with open(output_file, 'w+') as f: @@ -2692,8 +2694,6 @@ class GcsDependency(Dependency): with tarfile.open(output_file, "w:gz") as tar: tar.add(copy_dir, arcname=os.path.basename(copy_dir)) else: - gsutil = download_from_google_storage.Gsutil( - download_from_google_storage.GSUTIL_DEFAULT_PATH) code, _, err = gsutil.check_call('cp', self.url, output_file) if code and err: raise Exception(f'{code}: {err}') @@ -2746,6 +2746,13 @@ class GcsDependency(Dependency): self.WriteToFile(json.dumps(tar.getnames()), tar_content_file) tar.extractall(path=output_dir) + + if os.getenv('GCLIENT_TEST') != '1': + code, err = download_from_google_storage.set_executable_bit( + output_file, self.url, gsutil) + if code != 0: + raise Exception(f'{code}: {err}') + self.WriteToFile(calculated_sha256sum, hash_file) self.WriteToFile(str(1), migration_toggle_file)