EaseFilter Demo Project
ControlFilterHandler.cpp
Go to the documentation of this file.
1 //
3 // (C) Copyright 2011 EaseFilter Technologies Inc.
4 // All Rights Reserved
5 //
6 // This software is part of a licensed software product and may
7 // only be used or copied in accordance with the terms of that license.
8 //
10 
11 #include "stdafx.h"
12 #include "Tools.h"
13 #include "FilterAPI.h"
14 #include "UnitTest.h"
15 
16 
17 #define PrintMessage wprintf //ToDebugger
18 
19 BOOL
20 ProcessControlFilter( IN PMESSAGE_SEND_DATA pSendMessage,IN OUT PMESSAGE_REPLY_DATA pReplyMessage )
21 {
22  BOOL ret = TRUE;
23 
24 
25  try
26  {
27 
28  switch( pSendMessage->MessageType )
29  {
30 
31  case PRE_CREATE:
32  {
33  //
34  //For reparse file/folder open.
35  //
36  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
37  {
38  PrintMessage(L"File:%ws will be redirected to new file:%ws open",pSendMessage->FileName,GetTestReparseFileName());
39 
40  //the file name must be unicode string, file name length must be less than MAX_PATH.
41  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,GetTestReparseFileName(),(ULONG)wcslen(GetTestReparseFileName())*sizeof(WCHAR));
42  pReplyMessage->ReplyData.Data.DataBufferLength =(ULONG)wcslen(GetTestReparseFileName())*sizeof(WCHAR);
43 
45  pReplyMessage->ReturnStatus = STATUS_REPARSE;
46  }
47 
48  break;
49  }
50 
52  {
53 
54  //
55  //Return your own information without go down to the file system.
56  //
57 
58  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
59  {
60  FILE_BASIC_INFORMATION basicInfo;
61 
62  if( pSendMessage->InfoClass == FileBasicInformation )
63  {
64  basicInfo.ChangeTime = basicInfo.LastWriteTime
65  = basicInfo.CreationTime = basicInfo.LastAccessTime = GetTestFileTime();
66 
67  basicInfo.FileAttributes = FILE_ATTRIBUTE_READONLY;
68 
69  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,&basicInfo,sizeof(FILE_BASIC_INFORMATION));
70  pReplyMessage->ReplyData.Data.DataBufferLength = sizeof(FILE_BASIC_INFORMATION);
71 
73  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
74 
75  PrintMessage(L"File:%ws is test file with pre-query-information-basicInfo,return with status:%0x.",pSendMessage->FileName,pReplyMessage->FilterStatus);
76  }
77 
78 
79  //for other information class is the same process.
80  }
81 
82  break;
83 
84  }
85 
87  {
88 
89  //
90  //Change the information which returns from the file system.
91  //
92 
93  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
94  {
95  if( pSendMessage->InfoClass == FileBasicInformation )
96  {
97  PFILE_BASIC_INFORMATION basicInfo = (PFILE_BASIC_INFORMATION)pSendMessage->DataBuffer;
98 
99  basicInfo->ChangeTime = basicInfo->LastWriteTime = GetTestFileTime();
100  basicInfo->FileAttributes |= FILE_ATTRIBUTE_READONLY;
101 
102  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,basicInfo,sizeof(FILE_BASIC_INFORMATION));
103  pReplyMessage->ReplyData.Data.DataBufferLength = sizeof(FILE_BASIC_INFORMATION);
104 
105  pReplyMessage->FilterStatus = FILTER_MESSAGE_IS_DIRTY|FILTER_DATA_BUFFER_IS_UPDATED;
106  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
107  }
108 
109  //for other information class is the same process.
110  }
111 
112 
113  break;
114  }
115 
116 
117  case PRE_SET_INFORMATION:
118  {
119 
120 
121  //
122  //Change the information before write down to the file system.
123  //
124 
125  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
126  {
127 
128  if( pSendMessage->InfoClass == FileBasicInformation )
129  {
130  PFILE_BASIC_INFORMATION basicInfo = (PFILE_BASIC_INFORMATION)pSendMessage->DataBuffer;
131 
132  basicInfo->ChangeTime = basicInfo->LastWriteTime = GetTestFileTime();
133  basicInfo->FileAttributes = FILE_ATTRIBUTE_READONLY;
134 
135  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,basicInfo,sizeof(FILE_BASIC_INFORMATION));
136  pReplyMessage->ReplyData.Data.DataBufferLength = sizeof(FILE_BASIC_INFORMATION);
137 
138  pReplyMessage->FilterStatus = FILTER_MESSAGE_IS_DIRTY|FILTER_DATA_BUFFER_IS_UPDATED;
139  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
140 
141  }
142 
143  //for other information class is the same process.
144  }
145 
146 
147  break;
148  }
149 
150  //For POST_SET_INFORMATION, you can't change anything, since the data was written to the file system.
151 
152  //
153  //For PRE_DIRECTORY,you can complete it and return your own directory data,the data structure format
154  //must be the same as information class from the request,you can reference POST_DIRECTORY.
155 
156  case POST_DIRECTORY:
157  {
158  //
159  //Change the information which returns from the file system.
160  //
161  if(STATUS_SUCCESS == pSendMessage->Status && IsTestFolder(pSendMessage->FileName) )
162  {
163 
164 
165  //here we use FileBothDirectoryInformation as example, for other classes, you can do the same operation.
166  if( pSendMessage->InfoClass == FileBothDirectoryInformation )
167  {
168  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,pSendMessage->DataBuffer,pSendMessage->DataBufferLength);
169  pReplyMessage->ReplyData.Data.DataBufferLength = pSendMessage->DataBufferLength;
170  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
171 
172  PFILE_BOTH_DIR_INFORMATION fileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)pReplyMessage->ReplyData.Data.DataBuffer;
173  ULONG returnBufferLength = 0;
174  ULONG totalBufferLength = pReplyMessage->ReplyData.Data.DataBufferLength;
175 
176  if( NULL == fileBothDirInfo )
177  {
178  PrintErrorMessage(L"POST_DIRECTORY return empty databuffer",0);
179  }
180 
181  BOOL isDatabufferUpdated = FALSE;
182 
183  while( fileBothDirInfo )
184  {
185  ULONG nextOffset = fileBothDirInfo->NextEntryOffset;
186 
187  PrintMessage(L"FileName:%ws Attributes:0x%0x FileSize:%I64d\n"
188  ,fileBothDirInfo->FileName,fileBothDirInfo->FileAttributes,fileBothDirInfo->EndOfFile.QuadPart);
189 
190  //You can modify the data of the fileBothDirInfo, but must be careful to change the size of the entry.
191  //This structure must be aligned on a LONGLONG (8-byte) boundary. If a buffer contains two or more of these structures,
192  //the NextEntryOffset value in each entry, except the last, falls on an 8-byte boundary.
193 
194  //Test: Hide all the files whose file size greater than 1024 bytes.
195  if( fileBothDirInfo->EndOfFile.QuadPart > 1024 )
196  {
197  if( nextOffset != 0 )
198  {
199  PrintMessage(L"File %ws is filtered",fileBothDirInfo->FileName);
200  memmove (fileBothDirInfo,(PUCHAR)fileBothDirInfo + nextOffset,totalBufferLength - returnBufferLength - nextOffset );
201  isDatabufferUpdated = TRUE;
202  continue;
203  }
204  else
205  {
206  fileBothDirInfo->NextEntryOffset = 0;
207  }
208  }
209 
210  //Test: Add ReadOnly to the FileAttributes, change FileSize to test file size for all files;
211  if(NULL == (fileBothDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
212  {
213  PrintMessage(L"File %ws attributs:0x%0x was added ReadOnly,Filesize:%I64d was changed to 1234567890"
214  ,fileBothDirInfo->FileName,fileBothDirInfo->FileAttributes,fileBothDirInfo->EndOfFile.QuadPart);
215 
216  fileBothDirInfo->FileAttributes |= FILE_ATTRIBUTE_READONLY;
217  fileBothDirInfo->EndOfFile.QuadPart = GetTestFileSize();
218  isDatabufferUpdated = TRUE;
219  }
220 
221  returnBufferLength += nextOffset;
222 
223  if( nextOffset == 0)
224  {
225  returnBufferLength += sizeof(FILE_BOTH_DIR_INFORMATION) + fileBothDirInfo->FileNameLength - sizeof(WCHAR);
226  fileBothDirInfo = NULL;
227  }
228  else
229  {
230  fileBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)fileBothDirInfo + nextOffset);
231  }
232 
233  }
234 
235  pReplyMessage->ReplyData.Data.DataBufferLength = returnBufferLength;
236 
237  //if you filter out all the files, you can return no more files status. The system won't generate another request.
238  if( returnBufferLength == 0 )
239  {
240  pReplyMessage->ReturnStatus = STATUS_NO_MORE_FILES;
241  }
242 
243  if( isDatabufferUpdated )
244  {
245  PrintMessage(L"Update directory buffer,original length:%d new length:%d",pSendMessage->DataBufferLength,pReplyMessage->ReplyData.Data.DataBufferLength);
246  pReplyMessage->FilterStatus = FILTER_MESSAGE_IS_DIRTY|FILTER_DATA_BUFFER_IS_UPDATED;
247  }
248  }
249  }
250 
251  break;
252  }
253 
254  case PRE_FASTIO_READ:
255  case PRE_CACHE_READ:
256  case PRE_NOCACHE_READ:
257  case PRE_PAGING_IO_READ:
258  {
259  //
260  //Return your own data without go down to the file system.
261  //
262  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
263  {
264  ULONG dataLength = (ULONG)strlen(GetReplaceData());
265 
266  if( pSendMessage->Length < dataLength )
267  {
268  dataLength = pSendMessage->Length;
269  }
270 
271  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,GetReplaceData(),dataLength);
272  pReplyMessage->ReplyData.Data.DataBufferLength = dataLength;
273 
275  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
276  }
277 
278  break;
279  }
280 
281  case POST_FASTIO_READ:
282  case POST_CACHE_READ:
283  case POST_NOCACHE_READ:
284  case POST_PAGING_IO_READ:
285  {
286  //
287  //Modify the data which returns from the file system.
288  //
289 
290  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
291  {
292 
293  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,pSendMessage->DataBuffer,pSendMessage->DataBufferLength);
294  //merge test data to the beginning of the buffer.
295  ULONG dataLength = (ULONG)strlen(GetReplaceData());
296 
297  if( pSendMessage->Length < dataLength )
298  {
299  dataLength = pSendMessage->Length;
300  }
301 
302  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,GetReplaceData(),dataLength);
303  pReplyMessage->ReplyData.Data.DataBufferLength = dataLength;
304 
305 
306  pReplyMessage->FilterStatus = FILTER_MESSAGE_IS_DIRTY|FILTER_DATA_BUFFER_IS_UPDATED;
307  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
308  }
309 
310 
311  break;
312  }
313 
314 
315  case PRE_FASTIO_WRITE:
316  case PRE_CACHE_WRITE:
317  case PRE_NOCACHE_WRITE:
318  case PRE_PAGING_IO_WRITE:
319  {
320  //
321  //Modiy the write data buffer before it goes down to the file system.
322  //
323 
324  if( IsTestFile(pSendMessage->FileName,pSendMessage->FileNameLength) )
325  {
326  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,pSendMessage->DataBuffer,pSendMessage->DataBufferLength);
327  //merge test data to the beginning of the buffer.
328  ULONG dataLength = (ULONG)strlen(GetReplaceData());
329 
330  if( pSendMessage->Length < dataLength )
331  {
332  dataLength = pSendMessage->Length;
333  }
334 
335  memcpy(pReplyMessage->ReplyData.Data.DataBuffer,GetReplaceData(),dataLength);
336  pReplyMessage->ReplyData.Data.DataBufferLength = dataLength;
337 
338 
339  pReplyMessage->FilterStatus = FILTER_MESSAGE_IS_DIRTY|FILTER_DATA_BUFFER_IS_UPDATED;
340  pReplyMessage->ReturnStatus = STATUS_SUCCESS;
341  }
342 
343  break;
344  }
345 
346  //For post write operation, the data was written to the file system,at this point, we can't change anything.
347 
348  default: break;
349 
350  }
351  }
352  catch(...)
353  {
354  PrintErrorMessage( L"ProcessControlFilter exception.",GetLastError());
355  ret = FALSE;
356  }
357 
358  return ret;
359 }
struct _FILE_BASIC_INFORMATION FILE_BASIC_INFORMATION
struct _FILE_BASIC_INFORMATION * PFILE_BASIC_INFORMATION
void PrintErrorMessage(LPWSTR message, DWORD errorCode)
Definition: Tools.cpp:93
BOOL IsTestFolder(WCHAR *fileName)
Definition: FeatureDemo.cpp:43
CHAR * GetReplaceData()
Definition: FeatureDemo.cpp:68
BOOL IsTestFile(WCHAR *fileName, ULONG fileNameLength)
Definition: FeatureDemo.cpp:30
IN LONGLONG IN LONGLONG IN OUT PFILE_ALLOCATED_RANGE_BUFFER IN ULONG OUT ULONG * returnBufferLength
Definition: FilterAPI.h:722
struct _FILE_BOTH_DIR_INFORMATION * PFILE_BOTH_DIR_INFORMATION
LARGE_INTEGER GetTestFileTime()
Definition: FeatureDemo.cpp:80
LONGLONG GetTestFileSize()
Definition: FeatureDemo.cpp:74
BOOL ProcessControlFilter(IN PMESSAGE_SEND_DATA pSendMessage, IN OUT PMESSAGE_REPLY_DATA pReplyMessage)
#define PrintMessage
WCHAR * GetTestReparseFileName()
Definition: FeatureDemo.cpp:62
#define STATUS_REPARSE
struct _FILE_BOTH_DIR_INFORMATION FILE_BOTH_DIR_INFORMATION
#define STATUS_NO_MORE_FILES
#define STATUS_SUCCESS

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com