191 lines
6.9 KiB
C++
191 lines
6.9 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
clifile.cpp
|
|
|
|
Abstract:
|
|
|
|
Implements CLI FILE sub-interface
|
|
|
|
Author:
|
|
|
|
Ran Kalach [rankala] 3-March-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "rpdata.h"
|
|
|
|
HRESULT
|
|
FileRecall(
|
|
IN LPWSTR *FileSpecs,
|
|
IN DWORD NumberOfFileSpecs
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Recalls all the files that match the given specification (path + wildcards)
|
|
|
|
Arguments:
|
|
|
|
FileSpecs -
|
|
NumberOfFileSpecs -
|
|
|
|
Return Value:
|
|
|
|
S_OK - If all the files are recalled successfully.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL bExistingFiles = FALSE;
|
|
|
|
WsbTraceIn(OLESTR("FileRecall"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
// Verify that input parameters are valid
|
|
if (0 == NumberOfFileSpecs) {
|
|
WsbTraceAndPrint(CLI_MESSAGE_NO_FILES, NULL);
|
|
WsbThrow(E_INVALIDARG);
|
|
}
|
|
|
|
// Enumerate over the file specifications
|
|
for (ULONG i = 0; i < NumberOfFileSpecs; i++) {
|
|
CWsbStringPtr nameSpace;
|
|
WCHAR* pathEnd;
|
|
WIN32_FIND_DATA findData;
|
|
BOOL bMoreFiles = TRUE;
|
|
|
|
WsbAssert(NULL != FileSpecs[i], E_INVALIDARG);
|
|
|
|
// Enumerate over files in each specification
|
|
nameSpace = FileSpecs[i];
|
|
WsbAffirmHr(nameSpace.Prepend(OLESTR("\\\\?\\")));
|
|
pathEnd = wcsrchr(nameSpace, L'\\');
|
|
WsbAssert(pathEnd != NULL, E_INVALIDARG);
|
|
|
|
hSearchHandle = FindFirstFile((WCHAR *)nameSpace, &findData);
|
|
if (INVALID_HANDLE_VALUE != hSearchHandle) {
|
|
// Found at least one file that matches an input file specification
|
|
bExistingFiles = TRUE;
|
|
}
|
|
|
|
while ((INVALID_HANDLE_VALUE != hSearchHandle) && bMoreFiles) {
|
|
if ( findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
|
|
// File may be managed by HSM:
|
|
CWsbStringPtr fileName;
|
|
BYTE ReparseBuffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
|
PREPARSE_DATA_BUFFER pReparseBuffer;
|
|
DWORD outSize;
|
|
BOOL bRecall = FALSE;
|
|
|
|
// Create full name based on the path and the find-data
|
|
*(pathEnd+1) = L'\0';
|
|
fileName = nameSpace;
|
|
*(pathEnd+1) = L'\\';
|
|
WsbAffirmHr(fileName.Append(findData.cFileName));
|
|
|
|
// Open the file
|
|
hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_OPEN_NO_RECALL | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
|
|
if (INVALID_HANDLE_VALUE == hFile) {
|
|
// Report on an error
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
WsbTraceAndPrint(CLI_MESSAGE_ERROR_FILE_RECALL, (WCHAR *)fileName, WsbHrAsString(hr), NULL);
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
// Get reparse data and check if the file is offline (if not, just ignore it and continue)
|
|
if (0 == DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
|
ReparseBuffer, sizeof(ReparseBuffer), &outSize, NULL)) {
|
|
// Report on an error
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
WsbTraceAndPrint(CLI_MESSAGE_ERROR_FILE_RECALL, (WCHAR *)fileName, WsbHrAsString(hr), NULL);
|
|
WsbThrow(hr);
|
|
}
|
|
pReparseBuffer = (PREPARSE_DATA_BUFFER)ReparseBuffer;
|
|
if (IO_REPARSE_TAG_HSM == pReparseBuffer->ReparseTag) {
|
|
PRP_DATA pHsmData = (PRP_DATA) &pReparseBuffer->GenericReparseBuffer.DataBuffer[0];
|
|
if( RP_FILE_IS_TRUNCATED( pHsmData->data.bitFlags ) ) {
|
|
// File is managed by HSM and truncated
|
|
bRecall = TRUE;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
// Recall the file if required
|
|
if (bRecall) {
|
|
// Open the file again for recall
|
|
hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE == hFile) {
|
|
// Report on an error
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
WsbTraceAndPrint(CLI_MESSAGE_ERROR_FILE_RECALL, (WCHAR *)fileName, WsbHrAsString(hr), NULL);
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
// Recall the file
|
|
if (0 == DeviceIoControl(hFile, FSCTL_RECALL_FILE, NULL, 0,
|
|
NULL, 0, &outSize, NULL)) {
|
|
// Report on an error
|
|
// TEMPORARY: Should we abort or continue recalling other files?
|
|
DWORD dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
WsbTraceAndPrint(CLI_MESSAGE_ERROR_FILE_RECALL, (WCHAR *)fileName, WsbHrAsString(hr), NULL);
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
// Get next file
|
|
bMoreFiles = FindNextFile(hSearchHandle, &findData);
|
|
}
|
|
|
|
// Prepare for next file specification
|
|
nameSpace.Free();
|
|
if (INVALID_HANDLE_VALUE != hSearchHandle) {
|
|
FindClose(hSearchHandle);
|
|
hSearchHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
// Print warning message if no valid file was specified
|
|
if (FALSE == bExistingFiles) {
|
|
WsbTraceAndPrint(CLI_MESSAGE_NO_FILES, NULL);
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
// Ensure cleanup in case of an error
|
|
if (INVALID_HANDLE_VALUE != hSearchHandle) {
|
|
FindClose(hSearchHandle);
|
|
hSearchHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
if (INVALID_HANDLE_VALUE != hFile) {
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("FileRecall"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|