Share Notes

chundev

View the Project on GitHub latteouka/share-notes

macOS 的 quarantine xattr 如何造成 NAS 同步風暴

日期:2026-06-19 環境:macOS Sequoia + Synology NAS(SMB 掛載)+ Synology Drive Client


TL;DR

從 Mail.app 拖曳存出的附件會帶 com.apple.quarantine extended attribute。這個 xattr 會被 macOS 背景程序(Gatekeeper、Spotlight)反覆讀寫,每次都更新檔案的 ctime,導致 Synology Drive 誤判為「檔案已修改」而重複上傳。在 SMB 掛載的 NAS 上問題更嚴重,因為 xattr 是以 ._ sidecar 檔案的形式儲存,額外觸發同步事件。


背景

在 macOS 上透過 SMB 掛載 Synology NAS 作為日常工作目錄,用 Synology Drive 做雙向同步。偶爾觀察到某些檔案會不明原因地重新同步,特別是從 Mail.app 拖出來的附件。這些檔案在 Finder 中會有一個小小的 Mail 圖示標記。


問題

Synology Drive Client 會週期性地重新上傳某些檔案,即使檔案內容完全沒有變動。用 xattr -l 檢查這些檔案:

$ xattr -l /path/to/mail-attachment.pdf
com.apple.quarantine: 0083;6a33e047;Mail;4248A508-8C13-4101-B12A-A083273B847C
com.apple.metadata:kMDLabel_xn6o5jlcs3x2dfgarrhz3pcaym: (binary data)

com.apple.quarantine 的檔案就是問題來源。


根本原因:三層機制的連鎖反應

第一層:xattr 變動更新 ctime

macOS 檔案有三個關鍵時間戳:

時間戳 意義 什麼時候更新
mtime 內容修改時間 檔案內容被寫入
ctime metadata 變更時間 任何 inode 屬性變動(含 xattr)
atime 最後存取時間 檔案被讀取

重點:xattr 被修改 → ctime 更新 → 即使 mtime 不變,同步工具仍可能偵測到「檔案有變化」

Synology Drive 偵測檔案變更時,不只看 mtime,也參考 ctime 和檔案大小。ctime 一變,就被視為需要同步的對象。

第二層:macOS 背景程序會反覆「碰」quarantine

com.apple.quarantine 不是設了就靜止不動的標記。macOS 有多個背景機制會讀取或修改它:

Gatekeeper 驗證流程:

Spotlight indexer(mds/mdworker):

Finder 預覽:

每次被碰 → ctime 更新 → Synology Drive 又偵測到變更。

第三層:SMB 上的 xattr 是用 ._ 檔案存的

這是在 NAS 場景下問題放大的關鍵。

macOS 原生檔案系統(APFS、HFS+)內建支援 extended attributes,xattr 直接存在檔案系統的 inode 中。但在非 Apple 檔案系統上(包括 SMB/CIFS 掛載的 NAS),macOS 會把 xattr 存成 AppleDouble sidecar 檔案

報告.pdf        ← 本體(內容沒變)
._報告.pdf      ← xattr 資料(被背景程序改寫)

這個 ._ 檔案的建立和修改,對 NAS 來說就是一次真實的檔案寫入事件。Synology Drive server 端偵測到 ._報告.pdf 被修改 → 觸發同步 → 可能連帶重新處理 報告.pdf 本體。

完整連鎖反應

Mail.app 存出附件(自動帶 quarantine xattr)
  ↓
macOS 在 SMB 上建立 ._ sidecar 檔案存放 xattr
  ↓
Spotlight indexer 掃到新檔案,讀取 quarantine xattr
  ↓
ctime 更新 + ._ 檔案可能被改寫
  ↓
Synology Drive 偵測到變更 → 重新上傳
  ↓
NAS 端檔案更新 → 其他同步 client 偵測到變更
  ↓
其他 client 下載更新 → 可能觸發該端 Spotlight 重新索引
  ↓
(如果 Spotlight 又碰了 xattr...循環繼續)

解法

治標:存出附件後清除 quarantine

# 清除單一檔案
xattr -d com.apple.quarantine /path/to/file.pdf

# 清除整個目錄(只刪 quarantine,不動其他 xattr)
xattr -dr com.apple.quarantine /path/to/directory/

-d 指定只刪除 com.apple.quarantine 這一個 xattr,不影響 Finder 標籤等其他 metadata。

檢查現有檔案

先看有多少檔案帶 quarantine(不做任何修改):

find /path/to/nas/mount/ -maxdepth 4 -type f \
  -exec sh -c 'xattr -p com.apple.quarantine "$1" 2>/dev/null && echo "  → $1"' _ {} \; \
  | grep -c "→"

⚠️ 不建議的做法

不要對整個 NAS 目錄跑 xattr -cr(清除所有 xattr):

正確做法是只清 quarantine(-d com.apple.quarantine),或養成從 Mail 存出附件後就立刻清的習慣。


com.apple.quarantine 的格式

quarantine xattr 的值是一個分號分隔的字串:

0083;6a33e047;Mail;4248A508-8C13-4101-B12A-A083273B847C
│     │         │     │
│     │         │     └─ 下載事件 UUID(對應 LaunchServices 資料庫)
│     │         └─ 來源應用程式名稱
│     └─ 時間戳(hex,Unix epoch)
└─ 狀態 flag(0083=未驗證, 00C3=已驗證通過)

macOS 將完整的 quarantine 事件記錄在 SQLite 資料庫:

~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2

學到的事


參考資料