📄 pdc.c
字号:
);
CloseHandle( File );
return;
}
}
//
// We have successfully opened the file and are ready to go.
// Allocate space for a search request and fill it in
// with the information needed by the ProcessSearchFile
// function when it runs.
//
SearchRequest = LocalAlloc( LMEM_ZEROINIT,
sizeof( *SearchRequest ) +
strlen( Path ) + 1
);
if (SearchRequest == NULL) {
fprintf( stderr, "PDC: Out of memory\n" );
exit( 1 );
}
SearchRequest->WorkItem.Reason = WORK_ITEM;
SearchRequest->File = File;
SearchRequest->FileSize = FileSize;
SearchRequest->FileData = FileData;
strcpy( SearchRequest->FullPathName, Path );
if (!ASyncIO) {
//
// If not using asynchronous I/O, then queue the search
// request to the work queue.
//
QueueWorkItem( WorkQueue, &SearchRequest->WorkItem );
}
else {
//
// Using asynchronous I/O, so queue the read operation.
// The file handle must remain open while the read operation
// is pending.
//
if (!ReadFileEx( File,
FileData,
FileSize,
&SearchRequest->OverlappedIO,
(LPOVERLAPPED_COMPLETION_ROUTINE) ProcessReadFileCompletion
)
) {
fprintf( stderr, "%s(0) : error %u: Unable to queue read of file.\n",
Path,
GetLastError()
);
VirtualFree( FileData, 0, MEM_RELEASE );
CloseHandle( File );
LocalFree( SearchRequest );
return;
}
//
// Successfully queued the read operation. Keep a count
// of outstanding read operations so we know when it is
// okay to terminate.
//
OutstandingIOOperations += 1;
}
//
// Return back to the EnumerateDirectoryTree function so that it
// can call us with the next file or directrry.
//
return;
}
VOID
ProcessRequest(
IN PWORK_QUEUE_ITEM WorkItem
)
/*++
Routine Description:
This function is called whenever a work item is removed from
the work queue by one of the worker threads. Which worker
thread context this function is called in is arbitrary.
This functions keeps a pointer to state information in
thread local storage.
This function is called once at the beginning with a
special initialization call. During this call, this
function allocates space for state information and
remembers the pointer to the state information in
a Thread Local Storage (TLS) slot.
This function is called once at the end with a special
termination call. During this call, this function
frees the state information allocated during the
initialization call.
In between these two calls are zero or more calls to
handle a work item. The work item is a search request
which is handled by the ProcessSearchFile function.
Arguments:
WorkItem - Supplies a pointer to the work item just removed
from the work queue. It is the responsibility of this
routine to free the memory used to hold the work item.
Return Value:
None.
--*/
{
DWORD BytesWritten;
PSEARCH_REQUEST_STATE State;
PSEARCH_REQUEST SearchRequest;
CHAR MessageBuffer[ 2 * MAX_PATH ];
if (WorkItem->Reason == WORK_INITIALIZE_ITEM) {
//
// First time initialization call. Allocate space for
// state information.
//
State = LocalAlloc( LMEM_ZEROINIT,
sizeof( *State )
);
if (State != NULL) {
//
// Now create a virtual buffer, with an initial commitment
// of zero and a maximum commitment of 128KB. This buffer
// will be used to accumulate the matched strings output
// during the search of a single file. This is so the
// output can be written to standard output with a single
// write call, thus insuring that it remains contiguous
// in the output stream, and is not intermingled with the
// output of the other worker threads.
//
if (CreateVirtualBuffer( &State->Buffer, 0, 2 * 64 * 1024 )) {
//
// The CurrentOutput field of the state block is
// a pointer to where the next output goes in the
// buffer. It is initialized here and reset each
// time the buffer is flushed to standard output.
//
State->CurrentOutput = State->Buffer.Base;
}
else {
LocalFree( State );
State = NULL;
}
}
//
// Remember the pointer to the state informaiton
// thread local storage.
//
TlsSetValue( TlsIndex, State );
return;
}
//
// Here to handle a work item or special terminate call.
// Get the state pointer from thread local storage.
//
State = (PSEARCH_REQUEST_STATE)TlsGetValue( TlsIndex );
if (State == NULL) {
return;
}
//
// If this is the special terminate work item, free the virtual
// buffer and state block allocated above and set the thread
// local storage value to NULL. Return to caller.
//
if (WorkItem->Reason == WORK_TERMINATE_ITEM) {
FreeVirtualBuffer( &State->Buffer );
LocalFree( State );
TlsSetValue( TlsIndex, NULL );
return;
}
//
// If not an initialize or terminate work item, then must be a
// search request. Calculate the address of the search request
// block, based on the position of the WorkItem field in the
// SEARCH_REQUEST structure.
//
SearchRequest = CONTAINING_RECORD( WorkItem, SEARCH_REQUEST, WorkItem );
//
// Actual search operation is protected by a try ... except
// block so that any attempts to store into the virtual buffer
// will be handled correctly by extending the virtual buffer.
//
_try {
//
// Perform the search against this file.
//
ProcessSearchFile( SearchRequest, State );
//
// Done with this file. If using asynchronous I/O, decrement the
// count of outstanding I/O operations and it if goes to zero,
// then signal the IoCompletedEvent as there are no more outstanding
// I/O operations.
//
if (ASyncIO && InterlockedDecrement( &OutstandingIOOperations ) == 0) {
SetEvent( IoCompletedEvent );
}
//
// If any output was written to the virtual buffer,
// flush the output to standard output. Trim the
// virtual buffer back to zero committed pages.
//
if (State->CurrentOutput > (LPSTR)State->Buffer.Base) {
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ),
State->Buffer.Base,
State->CurrentOutput - (LPSTR)State->Buffer.Base,
&BytesWritten,
NULL
);
TrimVirtualBuffer( &State->Buffer );
State->CurrentOutput = (LPSTR)State->Buffer.Base;
}
}
_except( VirtualBufferExceptionFilter( GetExceptionCode(),
GetExceptionInformation(),
&State->Buffer
)
) {
//
// We will get here if the exception filter was unable to
// commit the memory.
//
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ),
MessageBuffer,
sprintf( MessageBuffer,
"%s(0) : error 0: too many matches for file\n",
SearchRequest->FullPathName
),
&BytesWritten,
NULL
);
}
//
// Free the storage used by the SearchRequest
//
LocalFree( SearchRequest );
//
// All done with this request. Return to the worker thread that
// called us.
//
return;
}
VOID
ProcessReadFileCompletion(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
)
/*++
Routine Description:
This function is called whenever an asynchronous I/O operation,
queued by the previous function, completes. This function
calulates the address of the search request block and then
queue the request to the work queue, now that the data is
in memory.
Arguments:
dwErrorCode - Supplies the error code that the I/O completed with.
dwNumberOfBytesTransfered - Supplies the actual number of bytes
transferred.
lpOverlapped - Supplies a pointer to the structure given to
ReadFileEx when the I/O operation was queued.
Return Value:
None.
--*/
{
PSEARCH_REQUEST SearchRequest;
//
// Since the data we need is now in memory, queue the search
// request to the work queue.
//
SearchRequest = CONTAINING_RECORD( lpOverlapped, SEARCH_REQUEST, OverlappedIO );
QueueWorkItem( SearchRequest->WorkItem.WorkQueue, &SearchRequest->WorkItem );
}
VOID
ProcessSearchFile(
IN PSEARCH_REQUEST SearchRequest,
IN PSEARCH_REQUEST_STATE State
)
/*++
Routine Description:
This function performs the actual search of the contents of the
passed file for the search string given on the command line.
If we are using synchronous I/O, then do the read operation
now.
Search the contents of the file for any matches, and accumulate
the match output in the virtual buffer using sprintf, which is
multi-thread safe, even with the single threaded version of
the libraries.
Arguments:
SearchRequest - Supplies a pointer to the search request which
contains the relevant information.
State - Supplies a pointer to state information for the current
thread.
Return Value:
None.
--*/
{
LPSTR FileData, s, s1, BegLine, EndLine, EndOfFile;
DWORD LineNumber;
DWORD MatchesFound;
DWORD BytesRead;
// Get a pointer to the beginning of the file data in memory
// and calculate the address of the end of file point in
// memory.
//
FileData = SearchRequest->FileData;
EndOfFile = FileData + SearchRequest->FileSize;
//
// If using synchronous I/O, then we have not read in the
// file contents yet, so issue the synchronous read to get
// the data into memory.
//
if (SyncIO) {
if (!ReadFile( SearchRequest->File,
FileData,
SearchRequest->FileSize,
&BytesRead,
NULL
) ||
BytesRead != SearchRequest->FileSize
) {
State->CurrentOutput += sprintf( State->CurrentOutput,
"%s(0) : error %u: Unable to read file contents.\n",
SearchRequest->FullPathName,
GetLastError()
);
CloseHandle( SearchRequest->File );
return;
}
}
//
// Close any open file handle associated with this request.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -