Meddelanden om filsystemåtgärder
Förutom nödvändiga återanrop för hantering av uppräkning, returnering av filmetadata och filinnehåll kan en leverantör eventuellt registrera en PRJ_NOTIFICATION_CB återanrop i sitt anrop till PrjStartVirtualizing. Återanropet tar emot meddelanden om filsystemåtgärder som utförs på filer och kataloger under instansens virtualiseringsrot. Vissa av meddelandena är "meddelanden efter åtgärden" som meddelar leverantören att en åtgärd just har slutförts. De andra meddelandena är "pre-operation"-meddelanden, vilket innebär att providern meddelas innan åtgärden utförs. I ett meddelande före åtgärden kan providern lägga in sitt veto mot åtgärden genom att returnera en felkod från återanropet. Detta gör att åtgärden misslyckas med den returnerade felkoden.
Så här anger du meddelanden som ska ta emot
Om leverantören tillhandahåller en implementering av PRJ_NOTIFICATION_CB när en virtualiseringsinstans startas, bör den även ange vilka meddelanden den vill ta emot. De meddelanden som providern kan registrera för definieras i PRJ_NOTIFICATION enumerationstyp.
När providern anger de meddelanden som den vill ta emot gör den det med hjälp av en matris med en eller flera PRJ_NOTIFICATION_MAPPING strukturer. Dessa definierar "meddelandemappningar". En meddelandemappning är en parkoppling mellan en katalog som kallas "meddelanderot" och en uppsättning meddelanden, uttryckta som en bitmask, som ProjFS bör skicka för den katalogen och dess underordnade. En meddelandemappning kan också upprättas för en enda fil. En fil eller katalog som anges i en meddelandemappning behöver inte redan finnas när providern anropar PrjStartVirtualizing, providern kan ange vilken sökväg som helst och mappningen gäller för den om den någonsin har skapats.
Om providern anger flera meddelandemappningar och vissa är underordnade till andra måste mappningarna anges i fallande djup. Meddelandemappningar på djupare nivåer åsidosätter de på högre nivå för sina underordnade.
Om providern inte anger någon uppsättning meddelandemappningar skickar ProjFS som standard den PRJ_NOTIFY_FILE_OPENED, PRJ_NOTIFY_NEW_FILE_CREATED och PRJ_NOTIFY_FILE_OVERWRITTEN för alla filer och kataloger under virtualiseringsroten.
Följande kodfragment visar hur du registrerar en uppsättning meddelanden när du startar en virtualiseringsinstans.
PRJ_CALLBACKS callbackTable;
// Supply required callbacks.
callbackTable.StartDirectoryEnumerationCallback = MyStartEnumCallback;
callbackTable.EndDirectoryEnumerationCallback = MyEndEnumCallback;
callbackTable.GetDirectoryEnumerationCallback = MyGetEnumCallback;
callbackTable.GetPlaceholderInfoCallback = MyGetPlaceholderInfoCallback;
callbackTable.GetFileDataCallback = MyGetFileDataCallback;
// The rest of the callbacks are optional. We want notifications, so specify
// our notification callback.
callbackTable.QueryFileNameCallback = nullptr;
callbackTable.NotificationCallback = MyNotificationCallback;
callbackTable.CancelCommandCallback = nullptr;
// Assume the provider has created a new virtualization root at C:\VirtRoot and
// initialized it with this layout:
//
// C:\VirtRoot
// +--- baz
// \--- foo
// +--- subdir1
// \--- subdir2
//
// The provider wants these notifications:
// * Notification of new file/directory creates for all locations within the
// virtualization root that are not subject to one of the following more
// specific notification mappings.
// * Notification of new file/directory creates, file opens, post-renames, and
// pre- and post-deletes for C:\VirtRoot\foo
// * No notifications for C:\VirtRoot\foo\subdir1
PRJ_STARTVIRTUALIZING_OPTIONS startOpts = {};
PRJ_NOTIFICATION_MAPPING notificationMappings[3];
// Configure default notifications - notify of new files for most of the tree.
notificationMappings[0].NotificationRoot = L"";
notificationMappings[0].NotificationBitMask = PRJ_NOTIFY_NEW_FILE_CREATED;
// Override default notifications - notify of new files, opened files, and file
// deletes for C:\VirtRoot\foo and its descendants.
notificationMappings[1].NotificationRoot = L"foo";
notificationMappings[1].NotificationBitMask = PRJ_NOTIFY_NEW_FILE_CREATED |
PRJ_NOTIFY_FILE_OPENED |
PRJ_NOTIFY_PRE_DELETE |
PRJ_NOTIFY_FILE_HANDLE_CLOSED_FILE_DELETED |
PRJ_NOTIFY_FILE_RENAMED;
// Override all notifications for C:\VirtRoot\foo\subdir1 and its descendants.
notificationMappings[2].NotificationRoot = L"foo\\subdir1";
notificationMappings[2].NotificationBitMask = PRJ_NOTIFY_SUPPRESS_NOTIFICATIONS;
startOpts.NotificationMappings = notificationMappings;
startOpts.NotificationMappingsCount = ARRAYSIZE(notificationMapping);
// Start the instance and provide our notification mappings.
HRESULT hr;
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT instanceHandle;
hr = PrjStartVirtualizing(rootName,
&callbackTable,
nullptr,
&startOpts,
&instanceHandle);
if (FAILED(hr))
{
wprintf(L"Failed to start the virtualization instance (0x%08x)\n", hr);
return;
}
Ta emot meddelanden
ProjFS skickar meddelanden om filsystemåtgärder genom att anropa leverantörens PRJ_NOTIFICATION_CB återanrop. Den gör detta för varje åtgärd som providern har registrerat sig för. Om, som i exemplet ovan, leverantören hade registrerat sig för PRJ_NOTIFY_NEW_FILE_CREATED | PRJ_NOTIFY_FILE_OPENED | PRJ_NOTIFY_PRE_DELETE | PRJ_NOTIFY_FILE_HANDLE_CLOSED_FILE_DELETED | PRJ_NOTIFY_FILE_RENAMED, och när ett program skapade en ny fil i meddelanderoten, så skulle ProjFS anropa PRJ_NOTIFICATION_CB återuppringning med den nya filens sökvägsnamn och meddelande parameter inställd på PRJ_NOTIFICATION_NEW_FILE_CREATED.
ProjFS skickar meddelandena i följande lista innan den associerade filsystemåtgärden äger rum. Om leverantören returnerar en felkod från PRJ_NOTIFICATION_CB-återanropet, misslyckas filsystemåtgärden och returnerar felkoden som leverantören angav.
- PRJ_NOTIFICATION_PRE_DELETE – Filen är på väg att tas bort.
- PRJ_NOTIFICATION_PRE_RENAME – Filen håller på att byta namn.
- PRJ_NOTIFICATION_PRE_SET_HARDLINK – En hård länk är på väg att skapas för filen.
- PRJ_NOTIFICATION_FILE_PRE_CONVERT_TO_FULL – En fil är på väg att utökas från en platshållare till en fullständig fil, vilket indikerar att dess innehåll sannolikt kommer att ändras.
ProjFS skickar meddelandena i följande lista när den associerade filsystemåtgärden har slutförts.
- PRJ_NOTIFICATION_FILE_OPENED – En befintlig fil har öppnats.
- Även om det här meddelandet skickas efter att filen har öppnats kan providern returnera en felkod. Som svar avbryter ProjFS öppningen och returnerar felet till anroparen.
- PRJ_NOTIFICATION_NEW_FILE_CREATED – En ny fil har skapats.
- PRJ_NOTIFICATION_FILE_OVERWRITTEN – En befintlig fil har skrivits över, till exempel genom att anropa CreateFileW med flaggan CREATE_ALWAYSdwCreationDisposition.
- PRJ_NOTIFICATION_FILE_RENAMED – En fil har bytt namn.
- PRJ_NOTIFICATION_HARDLINK_CREATED – En hård länk har skapats för en fil.
- PRJ_NOTIFICATION_FILE_HANDLE_CLOSED_NO_MODIFICATION – Ett filhandtag har stängts och filens innehåll har inte ändrats och filen har inte heller tagits bort.
- PRJ_NOTIFICATION_FILE_HANDLE_CLOSED_FILE_MODIFIED – Ett filhandtag har stängts och filens innehåll har ändrats.
- PRJ_NOTIFICATION_FILE_HANDLE_CLOSED_FILE_DELETED – Ett filhandtag har stängts och filen togs bort som en del av stängningen av handtaget.
Mer information om varje meddelande finns i dokumentationen för PRJ_NOTIFICATION.
Parametern PRJ_NOTIFICATION_CB callback-funktionens notificationParameters specificerar extra parametrar för vissa meddelanden. Om en provider får ett PRJ_NOTIFICATION_FILE_OPENED, PRJ_NOTIFICATION_NEW_FILE_CREATED eller PRJ_NOTIFICATION_FILE_OVERWRITTEN eller PRJ_NOTIFICATION_FILE_RENAMED meddelande kan leverantören ange en ny uppsättning meddelanden som ska ta emot för filen. Mer information finns i dokumentationen för PRJ_NOTIFICATION_CB.
Följande exempel visar enkla exempel på hur en provider kan bearbeta de meddelanden som den registrerade för i kodfragmentet ovan.
#include <windows.h>
HRESULT
MyNotificationCallback(
_In_ const PRJ_CALLBACK_DATA* callbackData,
_In_ BOOLEAN isDirectory,
_In_ PRJ_NOTIFICATION notification,
_In_opt_z_ PCWSTR destinationFileName,
_Inout_ PRJ_NOTIFICATION_PARAMETERS* operationParameters
)
{
HRESULT hr = S_OK;
switch (notification)
{
case PRJ_NOTIFY_NEW_FILE_CREATED:
wprintf(L"A new %ls was created at [%ls].\n",
isDirectory ? L"directory" : L"file",
callbackData->FilePathName);
// Let's stop getting notifications inside newly-created directories.
if (isDirectory)
{
operationParameters->PostCreate.NotificationMask = PRJ_NOTIFY_SUPPRESS_NOTIFICATIONS;
}
break;
case PRJ_NOTIFY_FILE_OPENED:
wprintf(L"Handle opened to %ls [%ls].\n",
isDirectory ? L"directory": L"file",
callbackData->FilePathName);
break;
case PRJ_NOTIFY_PRE_DELETE:
wprintf(L"Attempt to delete %ls [%ls]: ",
isDirectory ? L"directory": L"file",
callbackData->FilePathName);
// MyAllowDelete is a routine the provider might implement to decide
// whether to allow a given file/directory to be deleted.
if (!MyAllowDelete(callbackData->FilePathName, isDirectory))
{
wprintf(L"DENIED\n");
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
}
else
{
wprintf(L"ALLOWED\n");
}
break;
case PRJ_NOTIFY_FILE_HANDLE_CLOSED_FILE_DELETED:
wprintf(L"The %ls [%ls] was deleted.\n",
isDirectory ? L"directory": L"file",
callbackData->FilePathName);
break;
case PRJ_NOTIFY_FILE_RENAMED:
if (wcslen(callbackData->FilePathName) == 0)
{
// If callbackData->FilePathName is an empty string, then the item
// that was renamed was originally in a location not under the
// virtualization root.
wprintf(L"A %ls was renamed into the virtualization root,\n",
isDirectory ? L"directory": L"file");
wprintf(L"Its new location is [%ls].\n",
destinationFileName);
}
else if (wcslen(destinationFileName) == 0)
{
// If destinationFileName is an empty string, then the item that was
// renamed is now in a location not under the virtualization root.
wprintf(L"A %ls was renamed out of the virtualization root.\n",
isDirectory ? L"directory": L"file");
wprintf(L"Its original location was [%ls].\n",
callbackData->FilePathName);
}
else
{
// If both names are specified, both the new and old names are under
// the virtualization root (it is never the case that nether name is
// specified).
wprintf(L"A %ls [%ls] was renamed.\n",
isDirectory ? L"directory": L"file",
callbackData->FilePathName);
wprintf(L"Its new name is [%ls].\n", destinationFileName);
}
break;
default:
wprintf(L"Unrecognized notification: 0x%08x");
}
// Note that this may be a failure code from MyAllowDelete().
return hr;
}