檢測並刪除被占用的檔案

2021-06-22 13:12:12 字數 2920 閱讀 3070

在作業系統使用過程中,經常會遇到一些檔案被某些程式占用而無法被刪除的事情。這個時候,如果是手動進行的刪除可能影響還小,因為有很多方式可以解除引用,比如借助於其它的某軟體工具。但是在實際程式設計中,如果給乙個檔案重新命名,公升級的時候替換掉原來老的檔案等等就成了乙個致命的缺陷,由於一些不必要操作或其它軟體造成的這種情況而使得我們程式不能完整進行,就會成為比較棘手的問題。恰巧這樣的問題就在我們開發的軟體公升級過程中會經常遇到,那麼**一下這其中的原理並嘗試解決,無疑是一件非常有趣且有用的事情。

在公升級過程中,刪除某些程式產生的檔案必不可少的操作。但我們經常遇到某些檔案無法被替換成功。一來可能是因為使用者用其它軟體開啟了某檔案而造成檔案被占用,二來可能是某些程式後台讀取到這個檔案而造成了占用。總而言之,檔案被其它程序開啟。這些都會導致這個檔案無法被刪除。但有些時候刪除這樣的檔案是安全且是使用者友好的行為。

那麼作業系統如何判斷檔案被占用而不讓使用者進行刪除操作呢?

答案就是控制代碼表。

在 windows 作業系統中,如果乙個程序開啟了乙個檔案,系統就會建立乙個檔案物件,並且在該程序的控制代碼表中插入這個檔案的乙個控制代碼表示該程序對檔案的合法訪問許可權。因為控制代碼是相對安全的,所以使用者程式都是通過控制代碼來操作檔案。檔案物件的引用計數也會隨著控制代碼的新增而進行累加,這樣就可以記錄每個檔案有多少程序引用。當使用者嘗試刪除乙個檔案時,如果檔案物件的引用計數不能清為零,即還有其它程序正在使用這個檔案,那麼系統將不會將其刪除且給出檔案被占用的提示。

那麼要想刪除被占用的檔案的解決就非常明朗了,那就是解除其它程序對該檔案的引用。所以解決該問題的方法就可以分為兩步。

1 .      找到占用該檔案的程序;

2.      解除該程序對該檔案的引用。

解決方法:

1.      找到用該檔案的程序

如何找到有哪些程序占用了該檔案呢?其實系統提供了相應的介面,不過這些介面都是 undocument 的。這個介面就是

[cpp]view plain

copy

ntstatus  

ntapi   

ntquerysysteminformation (  

in system_information_class systeminformationclass,  

out pvoid systeminformation,  

in ulong systeminformationlength,  

out pulong returnlength optional  

);  

該函式的第二個引數傳入 0x10 就是查詢系統中所有控制代碼表的意思。它會返回一些系統中所有控制代碼的一些資訊,包括這些控制代碼的值,以及擁有該控制代碼的程序的 id。那麼如何判斷該控制代碼指向的就是我們所要查詢的檔案物件呢,接下來還有個介面。

[cpp]view plain

copy

ntstatus  

ntapi  

ntqueryobject(  

__in_opt handle handle,  

__in object_information_class objectinformationclass,  

__out_bcount_opt(objectinformationlength) pvoid objectinformation,  

__in ulong objectinformationlength,  

__out_opt pulong returnlength  

);  

這個介面可以查詢本程序中某個控制代碼的名字,只需要給第二個引數傳入 0x01 即可。由於上乙個介面中返回的是整個系統中控制代碼的資訊。

1.      解除該程序對該檔案的引用

ntqueryobject 只能查詢本程序的控制代碼的名字,所以還需一步操作就是,把控制代碼從其它程序中複製過來,就是下面的介面

[cpp]view plain

copy

bool duplicatehandle(  

handle hsourceprocesshandle,  

handle hsourcehandle,  

handle htargetprocesshandle,  

lphandle lptargethandle,  

dword dwdesiredaccess,  

bool binherithandle,  

dword dwoptions);  

這個介面可以將其它程序中的控制代碼複製到本程序中,如果 hsourceprocesshandle 傳入 0,dwoptions 傳入 duplicate_close_source ,就會把控制代碼從其它程序中清除。

這樣問題就變得簡單了,通過查詢控制代碼的名字以確定是否為我們想要得到的檔案的物件,然後清除掉目標程序中對該控制代碼的引用,那麼就沒有程序會占用我們將要刪除的檔案了。 

經過測試,上面的方法是可以解決掉某些檔案被其它程序占用的情況的。

不過,這種方法還是存在一些不足的地方。

1.      hsourceprocesshandle 必須具備 process_dup_handle 的許可權;

2.      該方法對一些資料檔案的占用有效,對一些程式檔案,如 dll 的占用會更複雜一些;

3.      由於第乙個介面是未文件化的,也就是作業系統不保證它的穩定和有效性,結果證明,在遍歷控制代碼的時候會出現系統死鎖這樣的已知 bug,使得程序無法退出。但可以在核心態安全地完成相同的操作。

控制代碼表是 windows 系統中乙個非常重要的概念,它透明地向使用者態程式授予了一些核心物件的操作許可權,在它背後建立起來的複雜的名字空間機制也給這些物件通過控制代碼來快速引用提供了可靠的保證。本案例中只使用了一種簡單的方法來解決一些通用的問題,還有其它一些更加有效的方法也陸續被一些安全廠商發現並產品化。而種種這些方法的發現,都是建立在對程式的理解之上。所以要想編寫出強大穩定的程式,這些機制也是我們必須掌握的。

檢測檔案被占用

使用場景 匯出檔案,在相同路徑下有同名檔案已經被開啟,檔案被占用,crash 檢測匯出的檔案是否已被占用在決定檔案是否允許匯出。dllimport kernel32.dll public static extern intptr lopen string lppathname,int ireadwr...

刪除被占用的串列埠

第一步 我們可以通過刪除登錄檔中的乙個數值項來清除這些配置 在 執行 對話方塊中輸入 regedit 進入登錄檔 然後進入 hkey local machine system currentcontrolset control com name arbiter這時我們可以找到該數值項 comdb,它...

c 檔案被占用如何移除 檔案被占用,

檔案被占用,求助 有兩個程式a和b,在a程式的登入窗體啟動b程式 定時自動上傳資料 如果資料自動上傳成功之後,再在a程式中點手工上傳就出出現檔案正在被另一程式 b 占用,在b程式中上傳完之後已經關閉檔案了,怎麼還會出現這個錯誤?求解 a程式frmlogion 啟動自動上傳程式 if file.exi...