Windows檔案系統過濾驅動開發教程(11)

來源:互聯網
上載者:User
11.檔案和目錄的產生開啟,關閉與刪除

我們已經分析了讀,寫與讀類似。檔案系統還有其他的操作。比如檔案或目錄的開啟(開啟已經存在的或者建立新的),關閉。檔案或目錄的移動,刪除。

實際上FILE_OBJECT並不僅僅指檔案對象。在windows檔案系統中,目錄和檔案都是用FileObject來抽象的。這裡產生一個問題,對於一個已經有的FileObject,我如何判斷這是一個目錄還是一個檔案呢?

對於一個已經存在的FileObject,我沒有找到除了發送IRP來向卷裝置詢問這個FileObject的資訊之外更好的辦法。自己發送IRP很麻 煩。不是我很樂意做的那種事情。但是FileObject都是在CreateFile的時候誕生的。在誕生的過程中,確實有機會得到這個即將誕生的 FileObject,是一個檔案還是一個目錄。

Create的時候,獲得當前IO_STACK_LOCATION,假設為irpsp,那麼irpsp->Parameters.Create的結構為:

struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT FileAttributes;
USHORT ShareAccess;
ULONG EaLength;
};

這個結構中的參數是與CreateFile這個api中的參數對應的,請自己研究。我先寫一些函數封裝來方便讀取irpsp.

_inline wd_ulong wd_irpsp_file_opts(wd_irpsp *irpsp)
{
return irpsp->Parameters.Create.Options;
}

_inline wd_ushort wd_irpsp_file_attrs(wd_irpsp *irpsp)
{
return irpsp->Parameters.Create.FileAttributes;
}

enum {wd_file_opt_dir = FILE_DIRECTORY_FILE};
enum {wd_file_attr_dir = FILE_ATTRIBUTE_DIRECTORY};

然後我們搞清上邊Options和FileAttributes的意思。是不是Options裡邊有FILE_DIRECTORY_FILE標記就表示這 是一個目錄?實際上,CreateOpen是一種嘗試性的動作。無論如何,我們只有當CreateOpen成功的時候,判斷FileObject才有意 義。否則是空談。

成功有兩種可能,一是已經開啟了原有的檔案或者目錄,另一種是建立立了檔案或者目錄。Options裡邊帶有FILE_DIRECTORY_FILE表示 開啟或者產生的對象是一個目錄。那麼,如果在Create的完成函數中,證實產生或者開啟是成功的,那麼返回得到的FILE_OBJECT,確實應該是一 個目錄。

當我經常要使用我過濾時得到的檔案或者目錄對象的時候,我一般在Create成功的的時候捕獲他們,並把他們記錄在一個“集合”中。這時你得寫一個用來表 示“集合”的資料結構。你可以用鏈表或者數組,只是注意保證多執行緒安全性。因為Create的時候已經得到了屬性工作表示FileObject是否是目錄,你 就沒有必要再發送IRP來詢問FileObject的Attribute了。

對了上邊有FileAttributes。但是這個東西並不可靠。因為在產生或者開啟的時候,你只需要設定Options。我認為這個欄位並無法說明你開啟的檔案對象是目錄。

這你需要設定一下Create的完成函數。如果設定這裡不再重複,請參考上邊對檔案讀操作。

wd_stat my_create_comp(in wd_dev *dev,
in wd_irp *irp,
in wd_void *context)
{
wd_irpsp *irpsp = wd_irp_cur_sp(irp);
wd_file *file = wd_irpsp_file(irpsp);

UNREFERENCED_PARAMETER(dev);

if(wd_suc(wd_irp_status(irp))
{
// 如果成功了,把這個FileObject記錄到集合裡,這是一個
// 剛剛開啟或者產生的目錄
if(file &&
(wd_irpsp_file_opts(irpsp) & wd_file_opt_dir))
add_obj_to_set(file);
}
return wd_irp_status(irp);
}

這裡順便解釋一下UNREFERENCED_PARAMETER宏。我曾經不理解這個宏的意思。其實就是因為本函數傳入了三個參數,這些參數你未必會用 到。如果你不用的話,大家知道c編譯器會發出一條警告。一般認為驅動應該去掉所有的警告,所以用了這個宏來“使用”一下沒有用到過的參數。你完全可以不用 他們。

現在所有的目錄都被你記錄。那麼得到一個FileObject的時候,判斷一下這個FileObject在不在你的集合裡,如果在,就說明是目錄,反之是檔案。

當這個FileObject被關閉的時候你應該把它從你的集合中刪除。你可以捕獲Close的IRP來做這個。記得本教程很早以前,我們已經安裝過 my_close函數的來處理IRP(請回憶或者翻閱第3節的內容),那麼很簡單了,在該函數中從你的集合中刪除該FileObject即可。作為保險的 做法,應該觀察一下關閉是否成功。如果成功的話,再進行你的從集合中刪除元素工作。

因為判斷FileObject是檔案還是目錄的問題,我們已經見識了檔案的開啟和關閉工作。現在看一下檔案是如何被刪除的。

刪除的操作,第一步是開啟檔案,開啟檔案的時候必須設定為可以刪除。如果開啟失敗,則直接導致無法刪除檔案。第二步設定檔案屬性為用於刪除,第三步關閉檔案即可。關閉的時候,檔案被系統刪除。

不過請注意這裡的“刪除”並非把檔案刪除到資源回收筒。如果要測試,你必須按住shift徹底刪除檔案。檔案刪除到資源回收筒只是一種改名操作。改名操作我們留到以後再討論。

第一步是開啟檔案,我應該可以在檔案被開啟的時候,捕獲到的irpsp的參數,記得前邊的參數結構,中間有:

PIO_SECURITY_CONTEXT SecurityContext;

相關的結構如下:

typedef struct _IO_SECURITY_CONTEXT {
PSECURITY_QUALITY_OF_SERVICE SecurityQos;
PACCESS_STATE AccessState;
ACCESS_MASK DesiredAccess;
ULONG FullCreateOptions;
} IO_SECURITY_CONTEXT, *PIO_SECURITY_CONTEXT;

注意其中的DesiredAccess,其中必須有DELETE標記,才可以刪除檔案。

第二步是設定為”關閉時刪除”。這是通過發送一個IRP(Set Information)來設定的。捕獲主功能碼為IRP_MJ_SET_INFORMATION的IRP後:
首先,IrpSp->Parameters.SetFile.FileInformationClass應該為FileDispositionInformation。

然後,Irp->AssociatedIrp.SystemBuffer指向一個如下的結構:

typedef struct _FILE_DISPOSITION_INFORMATION {
BOOLEAN DeleteFile;
} FILE_DISPOSITION_INFORMATION;

如果DeleteFile為TRUE,那麼這是一個刪除檔案的操作。檔案將在這個FileObject Close的時候被刪除。

以上的我都未實際調試,也不再提供樣本的代碼。有興趣的讀者請自己完成。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.