1. 程式人生 > >檔案重定向(採用檔案過濾驅動實現)

檔案重定向(採用檔案過濾驅動實現)

Windows的I/O管理器提供了一個方便的方法來重定向一個檔案物件。通常使用檔案過濾驅動(在檔案開啟和檔案建立的操作中)實現該方法。操作方法如下:

1、在IRP_MJ_CREATE的分發函式中,獲得FILE_OBJET的FileName屬性。

2、用目標檔案的完整路徑替換原有的檔名字。

這個全名,包括卷裝置物件的名字(例如,Device/HardDiskVolume0/Directory/MyFile.txt)。可以釋放掉原有的FileName.Buffer,同時用自己定義的緩衝區(buffer,以NonPagedPool方式申請)替換它。

3、設定IoStatus的status欄位為STATUS_REPARSE,然後設定Information欄位為IO_REPARSE.

4、完成該IRP請求。

5、返回STATUS_REPARSE

I/O管理器接收到該返回後,便會觸發另一個檔案開啟操作,併發送一個IRP_MJ_CREATE的請求。

而目標檔案可以是本地或遠端計算機。而若要重定向遠端檔案開啟操作,檔名要遵循以下語法:

"/??/UNC/HostName/Share/File"

"/Device/Mup/HostName/Share/File"

"/Device/LanmanagerRedirector/HostName/Share/File"(在你的目標檔案是CIFS/SMB/LanManager的情況下)

在你的首次開啟/建立檔案操作是相對於另一個檔案物件的時候,沒有必有修改FILE_OBJECT的RelatedFileObject域。在重定向時,I/O管理器只考慮FileName域,而不考慮RelatedFileObject域(在I/O管理器收到STATUS_REPARSE後,它便會釋放該域)。

I/O管理器為了避免重定向的無限迴圈,在巢狀迴圈中加了一些限制:重定向操作的最大巢狀次數是32.

程式碼

IRP_MJ_CREATE例程裡新增如下程式碼:

irpSp = IoGetCurrentIrpStackLocation(Irp);

   RtlInitUnicodeString(&cmpFileName, L"//hello.txt");

   KdPrint((">>> Create/Open FileName:%ws/n", irpSp->FileObject->FileName.Buffer));

   if (RtlCompareUnicodeString(&cmpFileName, &irpSp->FileObject->FileName, FALSE) == 0)

   {

    pusFileName = &(irpSp->FileObject->FileName);

    // 方法很簡單

    // 就是把FileObject->FileName.Buffer釋放掉

    // 然後自己ExAllocatePool...分配一個緩衝區用於儲存重定向的檔名 這裡需要是全檔名

    // FileObject->FileName指向新分配的緩衝區

    // 把新檔名拷貝到FileObject->FileName裡

    // 設定Irp->IoStatus的值如下

    // Irp->IoStatus.Status = STATUS_REPARSE;

    // Irp->IoStatus.Information = IO_REPARSE;

    // 返回STATUS_REPARSE

    // 經測試跨卷訪問也可以

    RtlInitUnicodeString(&usNewFileName, L"//??//E://123//hello.txt");

    pwNewNameBuffer = ExAllocatePool(PagedPool, usNewFileName.MaximumLength);

    if (pwNewNameBuffer == NULL)

    {

     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

     Irp->IoStatus.Information = 0;

     IoCompleteRequest( Irp, IO_NO_INCREMENT );

     return STATUS_INSUFFICIENT_RESOURCES;

    }

    ExFreePool( pusFileName->Buffer );

    pusFileName->Buffer = pwNewNameBuffer;

    pusFileName->MaximumLength = usNewFileName.MaximumLength;

    RtlCopyUnicodeString(pusFileName, &usNewFileName);

    Irp->IoStatus.Status = STATUS_REPARSE;

    Irp->IoStatus.Information = IO_REPARSE;

    IoCompleteRequest( Irp, IO_NO_INCREMENT );

    return STATUS_REPARSE;

}