Windows File System filter driver development tutorial (9)

Source: Internet
Author: User
Windows File System filter driver development tutorial

Note: If you have any questions and suggestions, please add qq16191935, email MFC_Tan_Wen@163.com

9. Complete the read operation.

Unless it is a complete file system, it seems unnecessary to complete the read operation. Generally, the filter driver only needs to send requests to the underlying file system. But sometimes, for example, I want to read data from the lower layer. After decryption, I will complete this IRP request myself.

Minor Function Code of IRP. We have discussed previously that if the major function code is irp_mj_read, It is a read request. In fact, there are some sub-function numbers under some main function numbers. If it is irp_mj_read, check its minor, there should be several situations: irp_mn_normal, irp_mn_mdl, irp_mn_mdl | irp_complete (this is irp_mn_mdl ). there are several other cases where I have explained the information, but I have not debugged it myself. Let's talk about the situations that I have debugged.

Write a function first to obtain the next function number.

_ Inline wd_uchar wd_irpsp_minor (wd_io_stack * irpsp)
{
Return irpsp-> minorfunction;
}

Enum {
Wd_mn_mdl = irp_mn_mdl,
Wd_mn_mdl_comp = irp_mn_mdl_complete,
Wd_mn_normal = irp_mn_normal
};

I hope you will like the feature number that I have redefined.

The situation of wd_mn_normal is exactly the same as that of the previous section (the reader may be scolded. This is what we mentioned in the previous section, and there are other situations in the results. Isn't that a lie? However, there are many exceptions for Microsoft, and I can't take him ...).

Note that as described in the preceding section, wd_mn_normal may either return data in IRP> mdladdress or return data in IRP> userbuffer, depending on the identifier of the device.

However, if the sub-function number is wd_mn_mdl, this is not the case at all. When we look at this type of IRP data, we suddenly find that IRP-> mdladdress and IRP-> userbuffer are empty. Where can you copy the data after obtaining it?

Wd_mn_mdl means allocate an MDL by yourself, point the MDL to the space where your data is located, and return it to the upper layer. Naturally, MDL is to be released. In other words, after the service is used, it must be returned. Therefore, wd_mn_mdl_comp is available, meaning that an MDL has been used and can be released.

MDL is used to describe the memory location. It is said that it uses the same structure as ndis_buffer. I will not go into it here. I will write some functions to allocate and release MDL, and point MDL to the memory location or get the memory pointed to by MDL:

// Release MDL
_ Inline wd_void wd_mdl_free (wd_mdl * MDL)
{
Iofreemdl (MDL );
}

// Allocate MDL for this object. The buffer must be non-paging. You can run at dispatch level.
_ Inline wd_mdl * wd_mdl_alloc (wd_void * Buf,
Wd_ulong length)
{
Wd_mdl * pmdl = ioallocatemdl (BUF, length, wd_false, wd_false, null );
If (pmdl = NULL)
Return NULL;
Mmbuildmdlfornonpagedpool (pmdl );
Return pmdl;
}

// This function allocates an MDL with a memory.
_ Inline wd_mdl * wd_mdl_malloc (wd_ulong length)
{
Wd_mdl * MDL;
Wd_void * point = wd_malloc (wd_false, length );
If (point = NULL)
Return NULL;
MDL = wd_mdl_alloc (point, length );
If (MDL = NULL)
{
Wd_free (point );
Return NULL;
}
Return MDL;
}

// This function releases the MDL and the memory carried by the MDL.
_ Inline wd_void wd_mdl_mfree (wd_mdl * MDL)
{
Wd_void * point = wd_mdl_vaddr (MDL );
Wd_mdl_free (MDL );
Wd_free (point );
}

// Obtain the address. If you want to copy data to a mdladdress...
_ Inline wd_void * wd_mdl_vaddr (wd_mdl * MDL)
{
Return mmgetsystemaddressformdlsafe (MDL, normalpagepriority );
}

In addition, I use these two functions to set and obtain the MDL on the IRP.

_ Inline wd_mdl * wd_irp_mdl (wd_irp * IRP)
{
Return IRP-> mdladdress;
}

_ Inline wd_void wd_irp_mdl_set (wd_irp * IRP,
Wd_mdl * MDL)
{
IRP-> mdladdress = MDL;
}

A function obtains userbuffer.
_ Inline wd_void * wd_irp_user_buf (wd_irp * IRP)
{
Return IRP-> userbuffer;
}

There is another problem to complete the request. It is IRP-> iostatus. Information. here you must fill in the bytes actually read. Otherwise, the upper layer does not know how much data is returned. This number is not necessarily the same as the length of your request (in fact, I think that almost everything is successful, it should be the same, the only exception is reading to the end of the file, length is not enough ). I use the following two functions to obtain and set this value:

_ Inline wd_void wd_irp_infor_set (wd_irp * IRP,
Wd_ulong INFOR)
{
IRP-> iostatus. Information = infor;
}

_ Inline wd_ulong wd_irp_infor (wd_irp * IRP)
{
Return IRP-> iostatus. Information;
}

You may be bored, but there is still something to do. As a case of reading files, if you complete the request by yourself, you cannot forget to move the file pointer. Otherwise, the operating system will not know how to move the file pointer and will never find the end of the file after reading the same place repeatedly. I have encountered this situation.

This is generally the case. If the file fails to be read, keep the original file pointer position unchanged. If the file is read successfully, point the file pointer to the position of "Read Request Offset + successful read length.

This so-called pointer refers to IRP-> fileobject-> currentbyteoffset.

I have tracked the reading behavior of a normal Windows File System. I don't think it must be said to me. The situation is complex, sometimes it is dynamic, sometimes it is not moving (I don't understand the complexity of course), but I have not found any errors in the method I mentioned above.

I use the following functions to set and obtain this.

_ Inline wd_void wd_file_offset_add (wd_file * file, wd_ulong Len)
{
File-> currentbyteoffset. quadpart + = Len;
}

_ Inline wd_void wd_file_offset_set (wd_file * file, wd_lgint offset)
{
File-> currentbyteoffset = offset;
}

_ Inline wd_lgint wd_file_offset (wd_file * file)
{
Return file-> currentbyteoffset;
}

Now let's take a look at how to complete these requests. Suppose I already have data. Now, assume that the buffer of this device is marked as 0, that is, normally data is returned using IRP-> userbuffer. of course, these are all done in my_disp_read or in other places that want to complete this IRP (I hope you still remember how we came here). Assuming that all other necessary judgments have been done:

Wd_irpsp * irpsp = wd_irp_cur_io_stack (IRP );
Switch (wd_irpsp_minor (irpsp ))
{
// Retain the offset of the object first
Case wd_mn_normal:
{
Wd_void * point = wd_irp_user_buf (IRP );

// If there is data, copy it to point...

Wd_irp_infor_set (IRP, length );
Wd_irp_status_set (IRP, wd_suc );
Wd_file_offset_set (wd_irp_file (IRP), offset + length );

Return wd_irp_over (IRP );
}
Case wd_mn_mdl:
{
Wd_void * MDL = wd_mdl_malloc (length); // The situation is more complex than the preceding one. Allocate MDL first
If (MDL = NULL)
{
//... The returned resource is insufficient...
}

Wd_irp_mdl_set (IRP, MDL );
Wd_irp_infor_set (IRP, length );
Wd_irp_status_set (IRP, wd_suc );

Wd_file_offset_set (wd_irp_file (IRP), offset + length );

Return wd_irp_over (IRP );

}
Case wd_mn_mdl_comp:
{
// If no other task exists, the MDL is released.
Wd_mdl_mfree (wd_irp_mdl (IRP ));
Wd_irp_mdl_set (IRP, 0 );
Wd_irp_infor_set (IRP, 0 );
Wd_irp_status_set (IRP, wd_status_suc );

Return wd_irp_over (IRP );
}
Default:
{
// I think it is relatively simple not to filter other cases...
}
}

Important: in the case of wd_mn_mdl, an MDL needs to be allocated, and the memory contained in this MDL has a certain length. This length must be the same as that of later IRP-> iostatus. Information! It seems that the upper layer does not follow the length returned by IRP> iostatus. Information. For example, if you read 50 bytes but return an MDL pointing to the Memory Length of 60 bytes, the operating system considers that 60 bytes have been read! This is terrible.

Finally, let's talk about how the file ends. If a successful response is returned, but the data actually read is not long, then wd_status_suc (STATUS_SUCCESS) is returned ), however, the operating system will immediately send an IRP to read the last position. The returned length is 0, and the returned status is status_file_end.

A huge amount of space is required to explain read requests. I will not explain the write request any more. I believe that the reader has the ability to figure it out on his own.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.