2015-01-09 32 views
3

我有兩個文件,分別爲AB,每個文件都有自己的內容。在Linux上原子交換兩個文件的內容

我想交換這兩個文件,所以A會變成B,而B會變成A。但是我想保證沒有其他進程會發現這兩個文件處於不一致的狀態,即使很短的時間,任何進程都不會找到這些文件丟失的任何文件。所以,作爲一項副業務,我還想保證,如果在操作過程中出現任何問題,什麼都不會改變(有點像我猜想的交易)。

在OS X上有一個exchangedata()函數,所以我想我正在尋找一個相當於它的Linux,或者至少是一個用於執行原子文件交換的等價方法。

+0

@FrédéricHamidi - 您發佈的問題的答案根本不符合我的標準,所以我想它不是重複的。 – antonone

+0

我認爲那裏的答案適合你,但我想如果出現問題,你不想留下臨時文件? –

+2

是的,以及我想有一個保證,我不會刪除原始文件。如果第一步移動成功,我將有效移除文件。那麼,如果第二招將失敗,我將不得不回滾。如果回滾也失敗了,我就會因爲破壞客戶系統而陷入困境;) – antonone

回答

6

可以使用(相當最近)linux syscall renameat2

這裏的定義是:

int renameat2(int olddir, const char *oldname, 
     int newdir, const char *newname, unsigned int flags); 

您可以在需要時對the kernel's Git repo找到它的源代碼。

它與renameat基本相同,但是如果您傳遞標誌RENAME_EXCHANGE,它將交換兩個文件,而不是將另一個重命名爲另一個。

該操作是原子操作。

1

我依賴於你的意思是「不一致的狀態」。如果可以接受爲了有一段時間,在此期間這兩個文件是相同的,那麼你可以簡單地做:

ln A C 
ln B D 
ln -f D A 
# now, A and B have the same content 
ln -f C B 

這也取決於你想要的已經有文件打開程序的行爲。請記住,路徑是而不是文件,但僅指向文件的鏈接,因此如果進程1通過路徑「A」打開文件,然後交換名稱A和B,則進程1仍將打開文件以名稱A提到。

+1

歡迎您提供解釋。這就解決了所問的問題,並解決了問題中含糊不清的問題。 –

+1

我做了一些實驗,似乎使用'-f'標誌不符合'原子性'約束,因爲'ln'工具使用'unlink'去除目標路徑,然後創建一個帶有'link'的鏈接功能。所以'ln -f'並不是真正的原子,當文件不存在時,會有一個(非常簡短但仍然)的時間窗口。考慮到這一點,只需使用臨時文件名進行重命名即可完成同樣的操作。 – antonone