2012-12-13 195 views
8

問題Getting Filename from file descriptor in C的變體。這是關於Linux的。從文件描述符重命名?

如果我有一個指的是普通文件的文件描述符,我可以給它一個新的文件名「保存」文件描述符(某處在同一臺設備上爲它生活的地方,當然)?我正在尋找類似於重命名(2)或鏈接(2)的東西,但它會接受文件描述符作爲輸入而不是文件名。

與重命名的問題(2)和鏈路(2),即使你可以嘗試從文件descritor到文件名中去,這可能會失敗。我更精確地考慮了打開的文件描述符是指已經被取消鏈接的文件的情況 - 在這種情況下,文件沒有更多的名稱。當我們關閉()文件描述符時,似乎沒有辦法阻止文件被刪除。但我錯了嗎?我們可以用Posix甚至Linux API再次給它一個名字嗎?

更新:我們實際上可以在/proc/<pid>/fd/<fd>的Linux上看到已刪除文件的內容,即使它看起來像一個破碎的符號鏈接。我們不能用鏈接(2)或LN(1)這種重新實現一個文件,但是,因爲它認爲我們正在試圖做一個跨設備的鏈路。

+0

但是,您可以複製fd/文件中的內容。很傻,你不能重新鏈接它。 –

+1

基本上同樣的問題在這裏有很好的答案:http://stackoverflow.com/q/4171713/4421 – pixelbeat

回答

3

如果問題是關於linux,並且關於linux> 2.6.39,那麼可以使用linkat命令和AT_EMPTY_PATH標誌爲文件描述符指定一個名稱。參見手冊頁(http://man7.org/linux/man-pages/man2/link.2.html

linkat(fd,"",destdirfd,"filename",AT_EMPTY_PATH); 

注意事項:

  • 您需要定義_GNU_SOURCE得到了AT_EMPTY_PATH定義,
  • 對於零此鏈接數的文件是不能保證工作。我不確定我瞭解手冊頁上對此所說的內容。我的猜測是,當文件鏈接數量爲零時,文件系統上的inode已被刪除,以避免文件系統崩潰時出現不一致。
  • 當然,如果舊文件不在目標目錄的相同文件系統上,我不希望它能夠正常工作。

如果發生故障,你有沒有其他的機會,而不是創建一個新的文件和內容複製使用sendfile過(檢查省略錯誤,請參閱可能的誤差值,每個函數的手冊頁):

struct stat s; 
off_t offset = 0; 
int targetfd = open("target/filename", O_WRONLY | O_CREAT | O_EXCL); 
fstat(fd,&s); 
sendfile(targetfd,fd,&offset, s.st_size); 
+0

謝謝!它仍然不是完全一般的,但它是向「正確」方向邁出的一步 - 並不是說​​我暗示我要求的東西確實是對的,甚至是需要的。 (我的原始問題只是一個好奇心問題。) –

+0

我認爲linux真的會幫助「給這個文件描述符一個名字」通用api,只有當文件描述符沒有引用一個普通文件或者引用另一個分區中的文件。另外,應該有辦法以原子的方式替換現有的文件,現在可以通過使用'rename',但只有當源文件具有文件系統名時纔可以。 – pqnet

2

問題:一個假設的系統調用frename,需要一個文件描述符存在,如果一個文件有多個名字(硬鏈接),它的名字會得到移動/重命名文件時對文件描述使用這個系統調用是指這個文件?

沒有很好地回答這個問題,那就是這個系統調用不存在的原因之一。

rename涉及目錄條目,它們指向的文件(i節點)。打開的文件描述符不與任何特定的目錄條目關聯,只與文件本身(inode)關聯。從這個角度來看,你所要求的系統調用並沒有什麼意義。沒有可移植的方式將inode追溯回指向它的目錄條目(並且可能還有不止一個)。某些操作系統可能會提供各種不可移植的手段來查找這種後向鏈接,可能會或可能不會保證總是得到一個結果(通常不能保證),但這些手段不回答哪個目錄條目返回的問題當有不止一個,並且據我所知,他們中沒有一個已經擴展到系統調用,比如你正在尋找的東西。

+0

對不起,混淆。這對我來說很清楚,這就是爲什麼我還建議'flink()'。我不應該提到'frename()'。 –

+2

'flink()'確實很好。這是唯一可以重新連接0鏈接但仍然存在的文件。但是,是的......它不存在於任何我知道的操作系統下。 – Celada