Watch at Ease看見世界,讀懂生活。

技術 · 實用指南

zipfile.Path.is_symlink()總回傳False?核對執行版本與成員類型

20項本機測試區分Python 3.12的方法占位實作、ZIP的Unix類型標記、CRC完整性,以及標準解壓縮器實際建立的物件。

原創示意圖:3.12中alias的存在、檔案與連結判斷及Unix類型位元。
原創示意圖:實際3.12.14結果;方法回傳False與儲存的連結標記可同時出現。 Watch at Ease

在CPython 3.12.14中,一個標記為Unix符號連結的合成ZIP成員確實存在,zipfile.Path.is_file()也回傳True,但is_symlink()回傳False。查看儲存的模式位元才能識別連結標記。False不能證明壓縮檔只包含一般檔案。

先確認執行版本與壓縮檔的中繼資料約定,再考慮變更檔案。我們在Linux使用751位元組、含7個成員的合成ZIP完成20項斷言,也證實CRC通過、解壓縮成功與成員類型檢查回答不同問題。

1. 檢查實作,而不只是方法存在

輸出sys.version,確認物件是zipfile.Path,不是指向已解壓縮檔案的pathlib.Path。在實際3.12.14直譯器中,查看zipfile.Path.is_symlink原始碼可見它直接回傳False。方法可呼叫,因此只檢查屬性存在無法發現限制。

Python分版本文件記錄3.13的行為變更:先前is_symlink無條件回傳False。我們讀過文件,但未執行3.13。應在實際部署版本上,用已知且無害的連結標記樣本檢查,不要僅憑最新文件或方法名稱推斷行為。

2. 在明確的中繼資料約定下逐項檢查

遍歷已開啟壓縮檔的infolist(),保留每個ZipInfo。記錄filename、create_system及模式運算式info.external_attr >>16。在本測試的Unix主機約定中,先要求create_system==3,再以stat.S_ISLNK、stat.S_ISREG或stat.S_ISDIR解讀模式。它們檢查儲存的類型位元,並非目前檔案系統。

PKWARE規定外部屬性的意義取決於主機系統。我們的有限分類器將非Unix主機及缺乏可識別類型的模式標為unknown。unknown不等於一般檔案,也不代表沒有問題。其他產生程式與主機約定需要另外驗證,不能強制當成否定結果。

3. 檔名、目標文字與類型位元分開判斷

樣本中alias與dangling皆有連結標記,即使dangling指向不存在的目標。讀取成員只得到儲存的target.txt與absent.txt文字。名為ordinary.link的一般成員,依明確Unix類型位元仍歸為一般檔案;副檔名不能證明連結類型。

folder/成員同時有目錄式名稱與目錄模式。ZipInfo.is_dir依名稱結尾斜線判斷,不等同檢查所有Unix類型位元。僅有權限位元的成員沒有可識別類型,所以維持unknown;權限本身不能證明它是一般檔案。

4. 另外測量解壓縮結果

testzip()對整個樣本回傳None,表示所測成員通過該CRC及標頭檢查,但連結中繼資料仍然存在。完整性檢查未回答成員是否為符號連結,也未證明其他解壓縮器會建立什麼物件。

我們僅以標準ZipFile.extract將無害的alias解壓縮至全新的暫存目錄。在本次3.12.14/Linux測試,產物是內容為target.txt的一般檔案,而非作業系統符號連結。未執行外部解壓縮程式。不要將結果推廣至其他工具,也不要為了讓方法回傳預期值而改寫中繼資料。

5. 依實際交付目標定義完成

20項測試檢查方法可用性、exists/is_file/is_symlink、7成員類型矩陣、懸空目標及副檔名對照、未知中繼資料、CRC通過、目標文字、缺失成員,以及解壓縮檔案的類型與精確內容。報告保留執行版本、方法原始碼、腳本與壓縮檔雜湊。

自己的流程亦應保留未變更壓縮檔與小型已知樣本。核對成員清單,只依規則實際支援的約定分類,並按照規則調查或拒絕未知類型。再檢查預定解壓縮器建立的物件類型與內容。這是成員類型診斷,不是完整的不可信壓縮檔解壓縮驗證器,也不是跨平台相容保證。

原創示意圖:7個成員的類型分類、未知項、CRC與解壓縮結果。
原創示意圖:類型、完整性及解壓縮是三種結果;unknown不等於一般檔案。 Watch at Ease