在linux系統(tǒng)中如果誤刪除了某個文件,但是文件句柄還被某些進(jìn)程占用著唤殴,這種情況下文件還能恢復(fù)嗎般婆?如果可以,那該怎么恢復(fù)被刪除的文件呢?
首先我們先來理解下朵逝,【文件被刪除了蔚袍,但是文件句柄還被某些進(jìn)程占用著】是什么意思?
先上個圖
當(dāng)我們創(chuàng)建一個文件后配名,linux文件系統(tǒng)會將文件的數(shù)據(jù)存儲到磁盤的數(shù)據(jù)區(qū)(data area)啤咽,文件根據(jù)其大小可能會占用多個磁盤扇區(qū);
每個文件都會對應(yīng)一個inode渠脉,inode存在于磁盤的索引表部分(inode table)宇整,inode中存儲著文件的元數(shù)據(jù)信息,文件系統(tǒng)通過inode里存儲的元數(shù)據(jù)讀寫磁盤芋膘;
每個inode都會分配一個唯一的inode編號鳞青,即索引節(jié)點編號;
文件系統(tǒng)會將文件名與inode編號建立映射關(guān)系,存儲在內(nèi)存中为朋,便于快速訪問臂拓。
上面說了這么一些,那實際上文件系統(tǒng)訪問文件的流程是怎樣的呢习寸?
1)我們平常查看或修改文件都是通過文件名來操作的胶惰,上邊說到了文件名與inode之間存在映射關(guān)系,而這個映射關(guān)系存儲在內(nèi)存中融涣,通過文件名可以找到與之關(guān)聯(lián)的inode編號童番;
2)拿到了inode編號后,就可以查找到該編號對應(yīng)的inode威鹿,進(jìn)而從磁盤里讀取到inode中存儲的文件元數(shù)據(jù)剃斧;
3)通過文件元數(shù)據(jù),再訪問忽你。
大概流程就是這樣幼东。
那這個與我們所要理解的【文件被刪除了,但是文件句柄還被某些進(jìn)程占用著】有什么關(guān)系呢科雳?其實是有關(guān)系的根蟹。
我們常說文件名、文件名糟秘,都知道它是一個文件的名稱简逮,但實際上文件名只是一個指向文件inode的硬鏈接(可以理解為文件的一個別名),可以真正恒久不變地標(biāo)識一個文件的是inode編號尿赚;
從一個文件被創(chuàng)建后散庶,它就會對應(yīng)著一個inode蕉堰,在它的生命周期內(nèi)(即一個文件被刪除之前),文件的inode都是不會發(fā)生改變的悲龟;而文件名是可以隨意改變的屋讶,文件名發(fā)生了改變,文件內(nèi)容是不會受影響的须教;
就像一個人的微信皿渗,它的微信號是唯一的,但是微信昵稱卻是可以變來變?nèi)サ摹?/p>
當(dāng)一個文件正被某個進(jìn)程讀寫時轻腺,我們執(zhí)行rm操作將其刪除乐疆,此時我們執(zhí)行cat filename,查看文件文件內(nèi)容的話约计,肯定會報【No such file or directory】的錯誤诀拭。
銜接上面說到的文件名只是一個指向文件inode的硬鏈接(它與inode之間建立的聯(lián)系),文件系統(tǒng)訪問文件是先通過文件名在內(nèi)存中存儲的映射關(guān)系中找到inode編號煤蚌,然后再找到inode耕挨,接著讀取出inode中文件的元數(shù)據(jù),然后文件系統(tǒng)再通過元數(shù)據(jù)訪問磁盤進(jìn)行IO操作尉桩。
我們把文件名刪除后筒占,相當(dāng)于在內(nèi)存中刪除了文件名與inode之間建立的映射關(guān)系,這樣文件系統(tǒng)就找不到inode了蜘犁;
但是如果此時還有進(jìn)程在占用著文件翰苫,那么文件不會徹底刪除,因為此時該文件的句柄還沒釋放这橙,文件屬于標(biāo)記刪除狀態(tài)奏窑;
而如果文件沒有被進(jìn)程占用且文件也沒有其他的硬鏈接指向它的inode了(即文件只有一個別名),那么此時該文件會被徹底刪除(包括文件名屈扎、inode以及磁盤中存儲的文件數(shù)據(jù))埃唯;
如果此時還有其他的硬鏈接指向文件的inode(文件有多個別名,類似于一個人可以擁有多個花名)鹰晨,那么僅是刪除這個這個硬鏈接(即此次rm操作只是刪除這個文件名墨叛,對文件數(shù)據(jù)沒影響)。
所以模蜡,【文件被刪除了漠趁,但是文件句柄還被某些進(jìn)程占用著】的意思是:雖然你在linux系統(tǒng)上訪問文件時報【No such file or directory】錯誤,但是別慌忍疾,文件還沒真正刪除的闯传,還可以找回來。那怎么找回來呢卤妒?這就需要從進(jìn)程以及其占用的文件句柄(文件句柄其實是一個文件描述符丸边,即符號鏈接)入手了叠必。
linux系統(tǒng)上跑著的每個進(jìn)程都在/proc目錄下存在著一個記錄,記錄格式為:/proc/pid妹窖,即每個進(jìn)程在/proc目錄下都會對應(yīng)一個目錄,目錄名為進(jìn)程的id號收叶。
例如骄呼,進(jìn)程tail -f ldapbak.ldif的進(jìn)程id為15603
我們到/proc目錄下查看下是否真的有這樣的一個目錄,切換到/proc判没,執(zhí)行l(wèi)s 15603
可以看到這個目錄下還是有挺多文件的蜓萄,其中有一個目錄為fd。
fd這個目錄的作用是存儲著該進(jìn)程占用著的文件句柄澄峰,例如:
其中嫉沽,0、1俏竞、2绸硕、3、4這些就是文件描述符魂毁,它們其實本質(zhì)就是符號鏈接(即軟鏈接)玻佩,指向被該進(jìn)程打開的文件。
所以進(jìn)程打開的文件描述符的存儲路徑是:/proc/pid/fd/文件描述符
如果一個進(jìn)程占用的文件描述符沒有被釋放席楚,那么執(zhí)行rm操作刪除文件時咬崔,文件尚未真正被刪除。
那么當(dāng)我們執(zhí)行rm操作誤刪了文件烦秩,我們怎么判斷這個文件是否正被某些進(jìn)程占用著以判斷文件能否恢復(fù)呢垮斯?
如果你知道文件名,那么可以直接執(zhí)行l(wèi)sof | grep filename只祠,如果能夠查到記錄兜蠕,那么說明還有進(jìn)程在占用著這個文件;
否則沒有進(jìn)程占用了铆农,文件可能很難恢復(fù)了牺氨。
如果不知道確切的文件名,那么可以執(zhí)行l(wèi)sof | grep deleted墩剖,來查找記錄猴凹。
此時ldapbak.ldif文件正被tail進(jìn)程占用著,我們對其執(zhí)行rm -f操作岭皂,然后再通過lsof | grep filename或者lsof | grep deleted來查找郊霎,由于這里我明確知道文件名,所以我就直接使用lsof | grep ldapbak.ldif來查找了爷绘,如下圖:
可以看到书劝,如果一個被進(jìn)程占用著进倍,這種情況下對其執(zhí)行rm操作,lsof得到的記錄中會有(deleted)標(biāo)簽购对,所以我們才可以通過lsof | grep deleted來查找猾昆。
要想恢復(fù)文件,首先得知道占用著這個文件的進(jìn)程id以及其創(chuàng)建的文件描述符骡苞,為什么垂蜗?因為我們需要根據(jù)/proc/pid/fd/文件描述符,找到被進(jìn)程占用的文件句柄解幽;
如上圖所示贴见,第二列是tail進(jìn)程的pid:34095(這里因為我kill了進(jìn)程,重新打開了一個躲株,所以pid不是之前的15603了)片部,第四列是文件句柄(文件描述符)3。
好了霜定,現(xiàn)在找到了pid档悠,也找到了文件描述符,我們可以切換到/proc/34095/fd目錄然爆,找到文件描述符3站粟,然后通過cp命令即可恢復(fù)被刪除的文件;
例如我刪除的文件是ldapbak.ldif曾雕,那么就可以執(zhí)行cp 3 /home/test/ldapbak.ldif就可以恢復(fù)文件ldapbak.ldif到指定目錄了奴烙。