windows-nt/Source/XPSP1/NT/base/fs/dfs/dfsm/server/idfsvsup.cxx
2020-09-26 16:20:57 +08:00

1873 lines
49 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (CC) Microsoft Corporation 1992, 1992
//
// File: idfsvsup.cxx
//
// Contents: This contains support methods for the IDfsVol interface
// implementation.
//
//-------------------------------------------------------------
//#include <ntos.h>
//#include <ntrtl.h>
//#include <nturtl.h>
//#include <dfsfsctl.h>
//#include <windows.h>
#include <headers.hxx>
#pragma hdrstop
#include <dfserr.h>
#include "cdfsvol.hxx"
#include "dfsmwml.h"
NTSTATUS
DfspCreateExitPoint (
IN HANDLE DriverHandle,
IN LPGUID Uid,
IN LPWSTR Prefix,
IN ULONG Type,
IN ULONG ShortPrefixLen,
OUT LPWSTR ShortPrefix);
NTSTATUS
DfspDeleteExitPoint (
IN HANDLE DriverHandle,
IN LPGUID Uid,
IN LPWSTR Prefix,
IN ULONG Type);
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::CreateObject, public
//
// Synopsis: This method merely creates a volume object. This has no
// distributed operations associated with this operation.
//
// Arguments: [pwzVolObjName] -- VOlume object Name
// [EntryPath] -- The EntryPath
// [VolType] -- VolumeType
// [pReplicaInfo] -- ReplicaInfo. This is optional.
//
// Returns:
//
// Notes: Raid: 455299 This function could potentially fail and leave an
// object hanging around??
//
// History: 17-May-1993 SudK Created.
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::CreateObject(
PWSTR pwszVolObjName,
LPWSTR pwszPrefix,
ULONG ulVolType,
PDFS_REPLICA_INFO pReplicaInfo,
PWCHAR pwszComment,
GUID *pUid
)
{
DWORD dwErr = ERROR_SUCCESS;
CDfsService *pService;
SYSTEMTIME st;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateVolObject(%ws,%ws,0x%x,%ws)\n",
pwszVolObjName, pwszPrefix, ulVolType, pwszComment));
//
// First put this name in the private section.
//
ULONG volLen = wcslen(pwszVolObjName);
if (volLen > MAX_PATH) {
_pwzFileName = new WCHAR[volLen + 1];
} else {
_pwzFileName = _FileNameBuffer;
}
if (_pwzFileName == NULL)
return( ERROR_OUTOFMEMORY );
wcscpy(_pwzFileName, pwszVolObjName);
IDfsVolInlineDebOut((DEB_TRACE, "Creating Object%ws\n", pwszVolObjName));
//
// Create the storage object.
//
dwErr = DfsmCreateStorage(
pwszVolObjName,
&_pStorage);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR,
"Unable to create directory storage object %08lx %ws\n",
dwErr, pwszVolObjName));
return(dwErr);
}
//
// First thing we do now is to setup the Class.
//
dwErr = _pStorage->SetClass(CLSID_CDfsVolume);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR,
"Unable to set Class on this %ws\n", pwszVolObjName));
return(dwErr);
}
//
// This is where we need to init and create the dummy property sets
// so that next time around we can set them and dont need to create them.
//
dwErr = SetVersion( TRUE );
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR,
"Unable to create version propset for %ws Error: %08lx\n",
pwszVolObjName, dwErr));
return(dwErr);
}
GUID Uid;
if (pUid == NULL) {
dwErr = UuidCreate(&Uid);
_peid.Uid = Uid;
} else {
_peid.Uid = *pUid;
}
_EntryType = ulVolType;
ULONG epLen = wcslen(pwszPrefix);
if (epLen > MAX_PATH) {
_peid.Prefix.Buffer = new WCHAR[epLen + 1];
_peid.Prefix.MaximumLength = (USHORT) ((epLen + 1)*sizeof(WCHAR));
} else {
_peid.Prefix.MaximumLength = sizeof(_EntryPathBuffer);
_peid.Prefix.Buffer = _EntryPathBuffer;
}
if (_peid.Prefix.Buffer == NULL)
return( ERROR_OUTOFMEMORY );
_peid.Prefix.Length = (USHORT) epLen*sizeof(WCHAR);
wcscpy(_peid.Prefix.Buffer, pwszPrefix);
//
// We don't yet know the short name of this volume, so simply allocate
// enough room and fill it with the full prefix. When an exit point
// corresponding to this volume is created, the short prefix might be
// modified.
//
// Note that it is tempting to think that the short prefix is <= the full
// prefix in size. This, however, is not a valid assumption, because
// names like A.BCDE qualify as LFNs, and their 8.3 equivalents look like
// A12345~1.BCD!
//
ULONG i, sepLen;
for (i = 0, sepLen = 0; i < epLen; i++) {
if (pwszPrefix[i] == UNICODE_PATH_SEP)
sepLen ++;
}
sepLen *= (1+8+1+3); // For \8.3
if (sepLen < epLen)
sepLen = epLen;
if (sepLen > MAX_PATH) {
_peid.ShortPrefix.Buffer = new WCHAR[sepLen + 1];
_peid.ShortPrefix.MaximumLength = (USHORT) ((sepLen + 1)*sizeof(WCHAR));
} else {
_peid.ShortPrefix.Buffer = _ShortPathBuffer;
_peid.ShortPrefix.MaximumLength = sizeof(_ShortPathBuffer);
}
if (_peid.ShortPrefix.Buffer == NULL)
return( ERROR_OUTOFMEMORY );
_peid.ShortPrefix.Length = (USHORT) epLen*sizeof(WCHAR);
wcscpy(_peid.ShortPrefix.Buffer, pwszPrefix);
//
// We need to deal with a NULL comment as well.
//
if (pwszComment != NULL) {
_pwszComment = new WCHAR[wcslen(pwszComment) + 1];
if (_pwszComment != NULL) {
wcscpy(_pwszComment, pwszComment);
}
} else {
_pwszComment = new WCHAR[1];
if (_pwszComment != NULL) {
*_pwszComment = UNICODE_NULL;
}
}
if (_pwszComment == NULL) {
return( ERROR_OUTOFMEMORY );
}
GetSystemTime( &st );
SystemTimeToFileTime( &st, &_ftEntryPath );
_ftComment = _ftState = _ftEntryPath;
dwErr = SetIdProps(
ulVolType,
_State,
pwszPrefix,
pwszPrefix,
_peid.Uid,
_pwszComment,
_Timeout,
_ftEntryPath,
_ftState,
_ftComment,
TRUE);
if (dwErr != ERROR_SUCCESS)
return(dwErr);
_Recover.Initialize(_pStorage);
_Recover.SetDefaultProps();
//
// Now let us set a NULL service List property. This method will create
// the stream as well. We dont need to bother.
//
dwErr = _DfsSvcList.SetNullSvcList(_pStorage);
if (dwErr != ERROR_SUCCESS)
return(dwErr);
_Deleted = FALSE;
//
// Everything is setup now. We can set the appropriate service etc.
//
if (pReplicaInfo != NULL) {
pService = new CDfsService(pReplicaInfo, FALSE, &dwErr);
if (pService == NULL) {
dwErr = ERROR_OUTOFMEMORY;
}
if (dwErr == ERROR_SUCCESS) {
dwErr = _DfsSvcList.SetNewService(pService);
if (dwErr != ERROR_SUCCESS) {
delete pService;
}
}
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateVolObject() exit\n"));
return(dwErr);
}
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::GetDfsVolumeFromStg, private
//
// Synopsis: This method takes a STATDIR structure and returns a CDfsVol
// pointer to the object corresponding to that.
//
// Arguments: [rgelt] -- Pointer to the DFSMSTATDIR structure.
// [ppDfsVol] -- This is where the DfsVol is returned.
//
// Returns: [ERROR_SUCCESS] -- If successfully set the parent's path.
//
// [ERROR_OUTOFMEMORY] -- If unable to allocate memory for parent's
// path.
//
// Error from loading the volume object
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::GetDfsVolumeFromStg(
DFSMSTATDIR *rgelt,
CDfsVolume **ppDfsVol)
{
DWORD dwErr = ERROR_SUCCESS;
PWCHAR pwszFullName;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetDfsVolumeFromStg()\n"));
//
// Allocate a new CDfsVolume and initialize with appropriate name.
//
*ppDfsVol = new CDfsVolume();
if (*ppDfsVol == NULL)
return( ERROR_OUTOFMEMORY );
pwszFullName = new WCHAR[wcslen(_pwzFileName) + wcslen(rgelt->pwcsName) + 2];
if (pwszFullName != NULL) {
wcscpy(pwszFullName, _pwzFileName);
wcscat(pwszFullName, L"\\");
wcscat(pwszFullName, rgelt->pwcsName);
dwErr = (*ppDfsVol)->LoadNoRegister(pwszFullName, 0);
delete [] pwszFullName;
} else {
dwErr = ERROR_OUTOFMEMORY;
}
if (dwErr != ERROR_SUCCESS) {
(*ppDfsVol)->Release();
*ppDfsVol = NULL;
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetDfsVolumeFromStg() exit\n"));
return(dwErr);
}
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::SetParentPath, private
//
// Synopsis: This method figures out the name of the parent object and
// sets it up in the private section of this instance.
//
// Arguments: None
//
// Returns: [ERROR_SUCCESS] -- If successfully set the parent's path.
//
// [ERROR_OUTOFMEMORY] -- If unable to allocate memory for parent's
// path.
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::SetParentPath(void)
{
PWCHAR pwszLastComponent;
ULONG parentLen;
pwszLastComponent = wcsrchr(_pwzFileName, L'\\');
if(pwszLastComponent == NULL) {
return ERROR_INVALID_DATA;
}
ASSERT(*(pwszLastComponent + 1) != UNICODE_NULL);
//
// Let us now figure out the length of the parent Name and copy over
// appropriate number of characters.
//
if (_pwszParentName != _ParentNameBuffer)
delete [] _pwszParentName;
parentLen = wcslen(_pwzFileName) - wcslen(pwszLastComponent);
if (parentLen > MAX_PATH) {
_pwszParentName = new WCHAR[parentLen + 1];
if (_pwszParentName == NULL)
return( ERROR_OUTOFMEMORY );
} else {
_pwszParentName = _ParentNameBuffer;
}
wcsncpy(_pwszParentName, _pwzFileName, parentLen);
_pwszParentName[parentLen] = UNICODE_NULL;
return(ERROR_SUCCESS);
}
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::GetParent, private
//
// Synopsis: This function returns a pointer to IDfsVolume to the parent
// of the present object. The release function on this
// should be called by the caller of this function. We use
// Ths IStorage interface to get to the parent.
//
// Arguments: [pIDfsParent] -- This is where the IDfsVolume for parent is
// returned.
//
// Returns: [ERROR_SUCCESS] -- If everything went well.
//
// [ERROR_OUTOFMEMORY] -- Unable to create parent instance.
//
// History: 14-Sep-92 SudK Created
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::GetParent(
CDfsVolume **parent)
{
DWORD dwErr = ERROR_SUCCESS;
CDfsVolume *pDfsVol;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetParent()\n"));
//
// First we get the parent's pathname and then we can do the appropriate.
//
dwErr = SetParentPath();
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((
DEB_ERROR, "Unable to get parentPath %ws %08lx\n",
_pwzFileName, dwErr));
return(dwErr);
}
//
// Now we instantiate a CDfsVolume structure and then initialise it.
//
pDfsVol = new CDfsVolume();
if (pDfsVol == NULL)
return( ERROR_OUTOFMEMORY );
dwErr = pDfsVol->LoadNoRegister(_pwszParentName, 0);
if (dwErr != ERROR_SUCCESS) {
pDfsVol->Release();
*parent = NULL;
return(dwErr);
}
*parent = pDfsVol;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetParent() exit\n"));
return(dwErr);
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::DeleteObject, private
//
// Synopsis: Support method to merely delete a volume object from
// persistent store.
//
// Arguments: None
//
// Returns: [ERROR_SUCCESS] -- If successfully deleted object.
//
// [ERROR_OUTOFMEMORY] -- Unable to get parent instance.
//
// History: 16-Sep-1992 SudK Created
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::DeleteObject()
{
DWORD dwErr = ERROR_SUCCESS;
CStorage *parentStg;
PWCHAR pwszLastComponent;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::DeleteObject()\n"));
//
// We are going to delete this object so let us release all our pointers.
//
ASSERT ((_pStorage != NULL));
_pStorage->Release();
_pStorage = NULL;
//
// Let us now release all the IStorage's which are with CRecover & SvcList
//
if (_Recover._pPSStg != NULL) {
_Recover._pPSStg->Release();
_Recover._pPSStg = NULL;
}
if (_DfsSvcList._pPSStg != NULL) {
_DfsSvcList._pPSStg->Release();
_DfsSvcList._pPSStg = NULL;
}
//
// First we get the parent's pathname and then we can do the appropriate.
//
dwErr = SetParentPath();
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((
DEB_ERROR, "Failed to get parent path for %ws\n", _pwzFileName));
return( dwErr );
}
dwErr = DfsmOpenStorage( _pwszParentName, &parentStg);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((
DEB_ERROR, "Unable to open [%ws] %08lx\n", _pwszParentName, dwErr));
return( dwErr );
}
//
// Now we have to delete ourselves using our parent's IStorage.
// So we extract the last component name from the file name.
//
pwszLastComponent = _pwzFileName + wcslen(_pwszParentName) + 1;
dwErr = parentStg->DestroyElement(pwszLastComponent);
parentStg->Release();
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((
DEB_ERROR, "Unable to delete [%ws] %08lx\n", _pwzFileName, dwErr));
return( dwErr );
} else {
//
// The storage object has really been deleted, so delete the mapping
// of this prefix from the storage directory.
//
dwErr = pDfsmStorageDirectory->_Delete( _peid.Prefix.Buffer );
ASSERT( dwErr == ERROR_SUCCESS );
}
_Deleted = TRUE;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::DeleteObject() exit\n"));
return( ERROR_SUCCESS );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsVolume::GetVersion, private
//
// Synopsis: Retrieves the version of the volume object from the property
// stamped on it.
//
// Arguments: [pVersion] -- The version is returned here.
//
// Returns: Result of reading the version property.
//
//-----------------------------------------------------------------------------
DWORD
CDfsVolume::GetVersion(
ULONG * pVersion)
{
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetVersion()\n"));
DWORD dwErr = ERROR_SUCCESS;
dwErr = _pStorage->GetVersionProps(pVersion);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR,
"Unable to read Version Properties %08lx\n",
dwErr));
return(dwErr);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetVersion() exit\n"));
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: SetVersion
//
// Synopsis: Sets the version property on the volume object to
// VOL_OBJ_VERSION_NUMBER
//
// Arguments: [bCreate] -- TRUE if the property set should be created,
// FALSE if the property set should be assumed to
// exist
//
// Returns: Result of setting the property
//
//-----------------------------------------------------------------------------
DWORD
CDfsVolume::SetVersion(
BOOL bCreate)
{
DWORD dwErr;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVersion()\n"));
dwErr = _pStorage->SetVersionProps( VOL_OBJ_VERSION_NUMBER );
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR,
"Unable to set Version Properties %08lx\n",
dwErr));
return(dwErr);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVersion() exit\n"));
return( dwErr );
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::GetIdProps, private
//
// Synopsis: Gets the ID Properties from a volume object.
// Memory for the string values is allocated using new. The
// caller is responsible for freeing it.
//
// Arguments: [pdwType] -- The Volume Type property is returned here.
// [ppwszEntryPath] -- EntryPath is returned here.
// [ppwszShortPath] -- The 8.3 form of EntryPath is returned here
// [ppwszComment] -- Comment is returned here.
// [pGuid] -- The Guid (VolumeID) is returned here.
// [pdwVolumeState] -- The volume state is returned here.
// [pftPathTime] -- Time that EntryPath was last modified.
// [pftStateTime] -- Time that Volume State was last modified.
// [pftCommentTime] -- Time that Comment was last modified.
//
// Returns:
//
// History: 16-Sep-1992 SudK Imported from PART.CXX
// 01-Jan-1996 Milans Ported to NT/SUR
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::GetIdProps(
ULONG *pdwType,
PWCHAR *ppwszEntryPath,
PWCHAR *ppwszShortPath,
PWCHAR *ppwszComment,
GUID *pGuid,
ULONG *pdwVolumeState,
ULONG *pdwTimeout,
FILETIME *pftPathTime,
FILETIME *pftStateTime,
FILETIME *pftCommentTime
)
{
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetIdProps()\n"));
DWORD dwErr = ERROR_SUCCESS;
dwErr = _pStorage->GetIdProps(
pdwType,
pdwVolumeState,
ppwszEntryPath,
ppwszShortPath,
pGuid,
ppwszComment,
pdwTimeout,
pftPathTime,
pftStateTime,
pftCommentTime);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((
DEB_ERROR, "Unable to read Id Props %08lx\n", dwErr));
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetIdProps() exit\n"));
return( dwErr );
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::SetIdProps, private
//
// Synopsis: Exact opposite of GetIdProps function. A wrapper around the
// property interface to set the appropriate properties that
// identify a volume.
//
// Arguments:
//
// Returns:
//
// History: 16-Sep-1992 SudK Imported from PART.CXX
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::SetIdProps(
ULONG Type,
ULONG State,
PWCHAR pwszPrefix,
PWCHAR pwszShortPath,
GUID & Guid,
PWSTR pwszComment,
ULONG Timeout,
FILETIME ftPrefix,
FILETIME ftState,
FILETIME ftComment,
BOOLEAN bCreate
)
{
DWORD dwErr;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetIdProps()\n"));
dwErr = _pStorage->SetIdProps(
Type,
State,
pwszPrefix,
pwszShortPath,
Guid,
pwszComment,
Timeout,
ftPrefix,
ftState,
ftComment);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR,
"Unable to Set IDProperties %08lx\n",
dwErr));
return(dwErr);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetIdProps() exit\n"));
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsVolume::SaveShortName
//
// Synopsis: Updates the short name for the volume entry path and saves it
// to the registry.
//
// Arguments: None - the short name is picked up from the _peid private
// member.
//
// Returns:
//
//-----------------------------------------------------------------------------
DWORD
CDfsVolume::SaveShortName()
{
DWORD dwErr;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetShortName()\n"));
dwErr = SetIdProps(
_EntryType,
_State,
_peid.Prefix.Buffer,
_peid.ShortPrefix.Buffer,
_peid.Uid,
_pwszComment,
_Timeout,
_ftEntryPath,
_ftState,
_ftComment,
FALSE);
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetShortName() exit\n"));
return( dwErr );
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::DeletePktEntry, private
//
// Synopsis: This method deletes an entry from the PKT. Given an ID to
// identify the entry this method deletes the entry.
//
// Arguments: victim - The entryID that identifies the PKT entry to go.
//
// Returns:
//
// History: 24-Nov-1992 SudK Created.
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume :: DeletePktEntry(
PDFS_PKT_ENTRY_ID victim
)
{
DWORD dwErr = ERROR_SUCCESS;
NTSTATUS status = STATUS_SUCCESS;
HANDLE pktHandle = NULL;
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::DeletePktEntry()\n"));
//
// Open the local PKT...
//
status = PktOpen(&pktHandle, 0, 0, NULL);
if(NT_SUCCESS(status)) {
status = PktDestroyEntry(
pktHandle,
*victim
);
PktClose(pktHandle);
if (status == DFS_STATUS_NO_SUCH_ENTRY) {
dwErr = ERROR_SUCCESS;
} else if (!NT_SUCCESS(status)) {
dwErr = RtlNtStatusToDosError(status);
}
} else {
dwErr = RtlNtStatusToDosError(status);
}
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::DeletePktEntry() exit\n"));
return( dwErr );
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::CreateSubordinatePktEntry, private
//
// Synopsis: This method is basically an interface into the driver to be
// able to manipulate the PKT. This creates an entry for the
// current volume object and at the same time links it with its
// superior volume object's PKT entry. This method makes one
// assumption that no services are associated with the service.
// It adds a NULL serviceList infact if the Boolean bWithService
// is FALSE else it puts in the servicelist also.
//
// Arguments: [pSuperior] -- The Superior's EntryID info is passed here to
// identify the superior in the PKT.
// [bWithService] -- Whether to include the serviceinfo in EINFO.
//
// Returns:
//
// History: 22-Nov-1992 SudK Created
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::CreateSubordinatePktEntry(
HANDLE pktHandle,
PDFS_PKT_ENTRY_ID pSuperior,
BOOLEAN bWithService)
{
ULONG etype = 0;
DFS_PKT_ENTRY_INFO einfo;
DWORD dwErr = ERROR_SUCCESS;
NTSTATUS status = STATUS_SUCCESS;
CDfsService *pDfsSvc = NULL;
DFS_SERVICE *pService;
ULONG count = 0;
UNICODE_STRING ustrShortName;
WCHAR ShortPrefix[MAX_PATH+1];
BOOLEAN CloseHandle = FALSE;
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::CreateSubordinatePktEntry()\n"));
//
// We setup the servicelist based on the CreateDisposition.
//
if (!bWithService) {
memset(&einfo, 0, sizeof(DFS_PKT_ENTRY_INFO));
einfo.ServiceList = NULL;
einfo.Timeout = _Timeout;
} else {
einfo.Timeout = _Timeout;
count = _DfsSvcList.GetServiceCount();
einfo.ServiceCount = count;
einfo.ServiceList = new DFS_SERVICE[count];
//447491, dont use null pointer.
if (einfo.ServiceList == NULL) {
dwErr = ERROR_OUTOFMEMORY;
return dwErr;
}
memset(einfo.ServiceList, 0, sizeof(DFS_SERVICE)*count);
pDfsSvc = _DfsSvcList.GetFirstService();
pService = einfo.ServiceList;
for (ULONG i=0; i<count; i++) {
*pService = *(pDfsSvc->GetDfsService());
pService++;
pDfsmSites->LookupSiteInfo((pDfsSvc->GetReplicaInfo())->pwszServerName);
pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
}
}
//
// Note: We depend upon the correspondence of certain bits between the DFS
// volume types and PKT entry types here.
//
#if (DFS_VOL_TYPE_ALL & (PKT_ENTRY_TYPE_LOCAL|PKT_ENTRY_TYPE_PERMANENT|PKT_ENTRY_TYPE_INUSE|PKT_ENTRY_TYPE_REFERRAL_SVC|PKT_ENTRY_TYPE_LOCAL_XPOINT))
#error (DFS_VOL_TYPE_ALL & (PKT_ENTRY_TYPE_LOCAL|PKT_ENTRY_TYPE_PERMANENT|PKT_ENTRY_TYPE_INUSE|PKT_ENTRY_TYPE_REFERRAL_SVC|PKT_ENTRY_TYPE_LOCAL_XPOINT))
#endif
etype = _EntryType | PKT_ENTRY_TYPE_PERMANENT;
//
// If the handle supplied is NULL, open the local pkt
//
if (pktHandle == NULL) {
status = PktOpen(&pktHandle, 0, 0, NULL);
if (NT_SUCCESS(status))
CloseHandle = TRUE;
}
if(NT_SUCCESS(status)) {
#if DBG
if (DfsSvcVerbose & 0x80000000) {
WCHAR wszGuid[sizeof(GUID)*2+1];
GuidToString(&_peid.Uid, wszGuid);
DbgPrint("CDfsVolume::CreateSubordinatePktEntry:\n"
"\tSupName=%ws\n"
"\tPrefix=%ws\n"
"\tShortPrefix=%ws\n"
"\tType=0x%x\n"
"\tCount=%d\n"
"\tGUID=%ws\n",
pSuperior->Prefix.Buffer,
_peid.Prefix.Buffer,
_peid.ShortPrefix.Buffer,
_EntryType,
einfo.ServiceCount,
wszGuid);
}
#endif
DfspCreateExitPoint(
pktHandle,
&_peid.Uid,
_peid.Prefix.Buffer,
_EntryType,
sizeof(ShortPrefix),
ShortPrefix);
status = PktCreateSubordinateEntry(
pktHandle,
pSuperior,
etype,
&_peid,
&einfo,
PKT_ENTRY_SUPERSEDE);
//
// If we opened the handle, close it
//
if (CloseHandle == TRUE) {
PktClose(pktHandle);
pktHandle = NULL;
}
}
if (!NT_SUCCESS(status)) {
dwErr = RtlNtStatusToDosError(status);
}
//
// Now before we leave we may have to delete the service list if we
// allocated it.
//
delete [] einfo.ServiceList;
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::CreateSubordinatePktEntry() exit\n"));
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Method: CDfsVolume::UpdatePktEntry, public
//
// Synopsis: This method updates the PKT with all the info regarding this
// volume. It however, does not bother about any kind of
// Relational Info at all.
//
// Arguments: None
//
// Returns: ERROR_SUCCESS -- If all went well.
//
// Notes:
//
// History: 03-Feb-93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD
CDfsVolume::UpdatePktEntry(
HANDLE pktHandle)
{
DFS_PKT_ENTRY_INFO einfo;
PDFS_SERVICE pService;
CDfsService *pDfsSvc;
DWORD dwErr = ERROR_SUCCESS;
NTSTATUS status = STATUS_SUCCESS;
ULONG EntryType, count;
UNICODE_STRING ustrShortName;
BOOLEAN CloseHandle = FALSE;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::UpdatePktEntry()\n"));
#if DBG
if (DfsSvcVerbose)
DbgPrint("CDfsVolume::UpdatePktEntry()\n");
#endif
memset(&einfo, 0, sizeof(DFS_PKT_ENTRY_INFO));
EntryType = _EntryType | PKT_ENTRY_TYPE_PERMANENT;
//
// Let us collect the service info now. Some memory allocation out here.
//
count = _DfsSvcList.GetServiceCount();
einfo.Timeout = _Timeout;
einfo.ServiceCount = count;
einfo.ServiceList = new DFS_SERVICE[count];
//447492, dont use null pointer.
if (einfo.ServiceList == NULL) {
dwErr = ERROR_OUTOFMEMORY;
return dwErr;
}
memset(einfo.ServiceList, 0, sizeof(DFS_SERVICE)*count);
pService = einfo.ServiceList;
pDfsSvc = _DfsSvcList.GetFirstService();
//
// In this loop we merely do an assignment of all the services. The
// conversion operator returns the DFS_SERVICE struct embedded in class.
//
for (ULONG i=0;i<count;i++) {
*pService = *(pDfsSvc->GetDfsService());
pService++;
pDfsmSites->LookupSiteInfo((pDfsSvc->GetReplicaInfo())->pwszServerName);
pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
}
#if DBG
if (DfsSvcVerbose) {
WCHAR wszGuid[sizeof(GUID)*2+1];
GuidToString(&_peid.Uid, wszGuid);
DbgPrint("CDfsVolume::UpdatePktEntry\n"
"\tPrefix=%ws\n"
"\tShortPrefix=%ws\n"
"\tType=0x%x\n"
"\tCount=%d\n"
"\tGUID=%ws\n",
_peid.Prefix.Buffer,
_peid.ShortPrefix.Buffer,
_EntryType,
einfo.ServiceCount,
wszGuid);
}
#endif
//
// If we weren't given a handle, create one
//
if (pktHandle == NULL) {
status = PktOpen(&pktHandle, 0, 0, NULL);
if (NT_SUCCESS(status))
CloseHandle = TRUE;
}
if (NT_SUCCESS(status)) {
status = PktCreateEntry(
pktHandle,
EntryType,
&_peid,
&einfo,
PKT_ENTRY_SUPERSEDE);
if (CloseHandle == TRUE) {
PktClose(pktHandle);
pktHandle = NULL;
}
}
if (!NT_SUCCESS(status)) {
#if DBG
if (DfsSvcVerbose)
DbgPrint("PktCreateEntry returned 0x%x\n", status);
#endif
dwErr = RtlNtStatusToDosError(status);
}
delete [] einfo.ServiceList;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::UpdatePktEntry() exit %d\n", dwErr));
#if DBG
if (DfsSvcVerbose)
DbgPrint("CDfsVolume::UpdatePktEntry() exit %d\n", dwErr);
#endif
//
// Cant blindly return this error. This needs to be processed.
//
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: GuidToString
//
// Synopsis: Converts a GUID to a 32 char wchar null terminated string.
//
// Arguments: [pGuid] -- Pointer to Guid structure.
// [pwszGuid] -- wchar buffer into which to put the string
// representation of the GUID. Must be atleast
// 2 * sizeof(GUID) + 1 long.
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
const WCHAR rgwchHexDigits[] = L"0123456789ABCDEF";
VOID GuidToString(
IN GUID *pGuid,
OUT PWSTR pwszGuid)
{
PBYTE pbBuffer = (PBYTE) pGuid;
USHORT i;
for(i = 0; i < sizeof(GUID); i++) {
pwszGuid[2 * i] = rgwchHexDigits[(pbBuffer[i] >> 4) & 0xF];
pwszGuid[2 * i + 1] = rgwchHexDigits[pbBuffer[i] & 0xF];
}
pwszGuid[2 * i] = UNICODE_NULL;
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::CreateChildPartition, private
//
// Synopsis: This is somewhat of a wrapper around the IStorage interface.
// It merely creates a new volume object and associates the
// properties passed in with the Volume Object. We use the
// IStorage interface for this purpose.
// This method generates a GUID and uses that. It also sets
// a NULL service list and Initial State on the volume object.
//
// Arguments: [Name] -- Child Volume Object's name.
// [Type] -- Type of this volume object.
// [EntryPath] -- Dfs prefix of child volume.
// [pwszComment] -- Comment associated with this new volume
// [pUid] -- Optional guid of child volume
// [pReplInfo] -- Info regarding the server\share supporting volume
// [NewIDfsVol] -- On successful return, pointer to new child
// volume object is returned here.
//
// Returns:
//
// Notes: This Method creates a GUID and uses it. It also sets a default
// state on the volume object and associates a NULL serviceList.
//
// History: 16-Sep-1992 SudK Imported from PART.CXX
//
//--------------------------------------------------------------------------
DWORD
CDfsVolume::CreateChildPartition(
PWCHAR Name,
ULONG Type,
PWCHAR EntryPath,
PWCHAR pwszComment,
GUID *pUid,
PDFS_REPLICA_INFO pReplInfo,
CDfsVolume **NewIDfsVol
)
{
DWORD dwErr = ERROR_SUCCESS;
CDfsVolume *pDfsVol;
PWSTR pwszChildName;
CDfsService *pService;
WCHAR wszChildElement[sizeof(GUID)*2+1];
GUID Uid, *pVolId;
PWCHAR pwszChild;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildPartition(%ws)\n", Name));
if (Name == NULL) {
//
// Get a guid first.
//
dwErr = UuidCreate(&Uid);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR, "UuidCreate failed %08lx\n", dwErr));
return(dwErr);
}
//
// Now figure out the last element of the child name from the GUID.
//
GuidToString(&Uid, wszChildElement);
pwszChild = wszChildElement;
pVolId = pUid == NULL ? &Uid : pUid;
} else {
pwszChild = Name;
pVolId = pUid;
}
//
// Now compose the full name of the child object.
//
pwszChildName = new WCHAR[wcslen(_pwzFileName)+wcslen(pwszChild)+2];
if (pwszChildName == NULL) {
*NewIDfsVol = NULL;
dwErr = ERROR_OUTOFMEMORY;
return dwErr;
}
wcscpy(pwszChildName, _pwzFileName);
wcscat(pwszChildName, L"\\");
wcscat(pwszChildName, pwszChild);
//
// Let us now instantiate a new instance of CDfsVolume and then we will
// initialise it with the appropriate Name.
//
pDfsVol = new CDfsVolume();
if (pDfsVol != NULL) {
dwErr = pDfsVol->CreateObject( pwszChildName,
EntryPath,
Type,
pReplInfo,
pwszComment,
pVolId);
//
// We set up recovery properties of creation here though this is also used
// by Move operation. This is OK however.
//
if (dwErr == ERROR_SUCCESS) {
dwErr = pDfsVol->_Recover.SetOperationStart( DFS_RECOVERY_STATE_CREATING, NULL);
if (dwErr == ERROR_SUCCESS) {
*NewIDfsVol = pDfsVol;
//
// Create object merely creates the object. We now need to call
// initPktSvc on the service inside the serviceList.
//
pService = pDfsVol->_DfsSvcList.GetFirstService();
ASSERT(((pService==NULL) && (pReplInfo==NULL)) ||
((pService!=NULL) && (pReplInfo!=NULL)));
if (pService != NULL)
pService->InitializePktSvc();
}
else {
pDfsVol->Release();
*NewIDfsVol = NULL;
}
} else {
pDfsVol->Release();
*NewIDfsVol = NULL;
}
} else {
*NewIDfsVol = NULL;
dwErr = ERROR_OUTOFMEMORY;
}
delete [] pwszChildName;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildPartition() exit\n"));
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Function: CDfsVolume::IsValidChildName,private
//
// Synopsis: Determines whether a prefix is a valid child prefix for this
// volume (ie, is hierarchically subordinate and there is no
// conflicting child.
//
// Arguments: [pwszChildPrefix] -- The prefix to test.
// [pidChild] -- The volume id of the proposed child volume.
//
// Returns: TRUE if the child prefix is legal, FALSE otherwise
//
//-----------------------------------------------------------------------------
BOOL CDfsVolume::IsValidChildName(
PWCHAR pwszChildPrefix,
GUID *pidChild)
{
NTSTATUS Status;
Status = PktIsChildnameLegal(
_peid.Prefix.Buffer,
pwszChildPrefix,
pidChild);
return( (BOOL) (Status == STATUS_SUCCESS) );
}
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::NotLeafVolume, private
//
// Synopsis: Uses IStorage to find if child exists.
//
// Arguments:None
//
// Returns: TRUE if NotLeafVolume else FALSE.
//
// History: 18-May-1993 SudK Created.
//
//--------------------------------------------------------------------------
BOOL
CDfsVolume::NotLeafVolume(void)
{
ULONG fetched = 0;
CEnumDirectory *pdir;
DFSMSTATDIR rgelt;
DWORD dwErr;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::NotLeafVolume()\n"));
ASSERT(!(VolumeDeleted()));
memset(&rgelt, 0, sizeof(DFSMSTATDIR));
//
// First, we get a hold of the IDirectory interface to our own volume
// object.
//
dwErr = _pStorage->GetEnumDirectory(&pdir);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR, "Failed to get IDirectory %08lx\n", dwErr));
return(FALSE);
}
//
// While there are children still to be handled we continue on.
//
while (TRUE) {
if (rgelt.pwcsName != NULL) {
delete [] rgelt.pwcsName;
rgelt.pwcsName = NULL;
}
dwErr = pdir->Next(&rgelt, &fetched);
//
// Will we get an error if there are no more children.
//
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate %08lx\n",dwErr));
pdir->Release();
return(FALSE);
}
//
// If we did not get back any children we are done.
//
if (fetched == 0) {
IDfsVolInlineDebOut((DEB_TRACE, "No Children Found\n",0));
pdir->Release();
return(FALSE);
}
//
// If the child is . or .. we look for next child.
//
ULONG cbLen = wcslen(rgelt.pwcsName);
if (cbLen < sizeof(L"..")/sizeof(WCHAR))
continue;
//
// If we got here it means that we came across a volume object
// and we have to return TRUE now.
//
IDfsVolInlineDebOut((DEB_ERROR, "Child Found - NotLeafVolume %ws\n",
rgelt.pwcsName));
pdir->Release();
delete [] rgelt.pwcsName;
return(TRUE);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::NotLeafVolume() exit\n"));
}
//+----------------------------------------------------------------------------
//
// Function: CDfsVolume::IsValidService
//
// Synopsis: Given a server name, indicates whether the server is a valid
// server for this volume.
//
// Arguments: [pwszServer] -- Name of server to verify.
//
// Returns: TRUE if server is a valid server for this volume, FALSE
// otherwise
//
//-----------------------------------------------------------------------------
BOOLEAN
CDfsVolume::IsValidService(
IN LPWSTR pwszServer)
{
DWORD dwErr;
CDfsService *pSvc;
dwErr = _DfsSvcList.GetServiceFromPrincipalName( pwszServer, &pSvc );
return( dwErr == ERROR_SUCCESS );
}
//+-------------------------------------------------------------------------
//
// Method: DeallocateCacheRelationInfo, private
//
// Synopsis: This function is used to deallocate relationInfo structures
// that were allocated by GetPktCacheRelationInfo.
//
// Arguments: RelationInfo - The relationInfo struct to deallocate.
//
// Returns:
//
// History: 24-Nov-1992 SudK Created.
//
//--------------------------------------------------------------------------
VOID
DeallocateCacheRelationInfo(
DFS_PKT_RELATION_INFO & RelationInfo
)
{
PDFS_PKT_ENTRY_ID peid = &RelationInfo.EntryId;
IDfsVolInlineDebOut((DEB_TRACE, "Dfsm::DeallocateCacheRelationInfo()\n"));
MarshalBufferFree(peid->Prefix.Buffer);
peid->Prefix.Buffer = NULL;
if (peid->ShortPrefix.Buffer) {
MarshalBufferFree(peid->ShortPrefix.Buffer);
peid->ShortPrefix.Buffer = NULL;
}
if(peid = RelationInfo.SubordinateIdList)
{
for(ULONG i = 0; i < RelationInfo.SubordinateIdCount; i++)
{
MarshalBufferFree(peid[i].Prefix.Buffer);
peid[i].Prefix.Buffer = NULL;
if (peid[i].ShortPrefix.Buffer != NULL) {
MarshalBufferFree(peid[i].ShortPrefix.Buffer);
peid[i].ShortPrefix.Buffer = NULL;
}
}
MarshalBufferFree(RelationInfo.SubordinateIdList);
RelationInfo.SubordinateIdList = NULL;
}
IDfsVolInlineDebOut((DEB_TRACE, "Dfsm::DeallocateCacheRelationInfo() exit\n"));
}
//+-------------------------------------------------------------------------
//
// Method: GetPktCacheRelationInfo, private
//
// Synopsis: This method retrieves the relational information regarding
// a particular volume (identified by the ENTRY_ID props)
// passed in to it.
//
// Arguments: [RelationInfo] -- The relational info is returned here.
// [peid] -- The EntryID is passed in here.
//
// Returns:
//
// History: 24-Nov-1992 SudK Created.
//
//--------------------------------------------------------------------------
DWORD
GetPktCacheRelationInfo(
PDFS_PKT_ENTRY_ID peid,
PDFS_PKT_RELATION_INFO RelationInfo
)
{
//
// Initialize all return values to be NULL...
//
HANDLE pktHandle;
DWORD dwErr = ERROR_SUCCESS;
NTSTATUS status;
memset(RelationInfo, 0, sizeof(DFS_PKT_RELATION_INFO));
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::GetPktCacheRelationInfo()\n"));
status = PktOpen(&pktHandle, 0, 0, NULL);
if (NT_SUCCESS(status))
{
//
// Create/Update the Entry...
//
status = PktGetRelationInfo(
pktHandle,
peid,
RelationInfo
);
PktClose(pktHandle);
pktHandle = NULL;
};
if (!NT_SUCCESS(status))
dwErr = RtlNtStatusToDosError(status);
else
dwErr = ERROR_SUCCESS;
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut((DEB_ERROR, "Failed GetRelationInfo %08lx\n",dwErr));
}
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::GetPktCacheRelationInfo() exit\n"));
return( dwErr );
}
NTSTATUS
DfspCreateExitPoint (
IN HANDLE DriverHandle,
IN LPGUID Uid,
IN LPWSTR Prefix,
IN ULONG Type,
IN ULONG Len,
OUT LPWSTR ShortPrefix)
{
NTSTATUS NtStatus;
IO_STATUS_BLOCK IoStatusBlock;
PDFS_CREATE_EXIT_POINT_ARG CreateArg;
ULONG Size = sizeof(*CreateArg);
PCHAR pWc;
if (Uid == NULL || Prefix == NULL) {
NtStatus = STATUS_INVALID_PARAMETER;
DFSM_TRACE_HIGH(ERROR, DfspCreateExitPoint_Error1,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
goto ExitWithStatus;
}
#if DBG
if (DfsSvcVerbose & 0x80000000) {
WCHAR wszGuid[sizeof(GUID)*2+1];
GuidToString(Uid, wszGuid);
DbgPrint("DfspCreateExitPoint(%ws,%ws,0x%x)\n",
wszGuid,
Prefix,
Type);
}
#endif
//
// Pack the args into a single buffer that can be sent to
// the dfs driver:
//
//
// First find the size...
//
if (Prefix != NULL) {
Size += (wcslen(Prefix) + 1) * sizeof(WCHAR);
}
//
// Now allocate the memory
//
CreateArg = (PDFS_CREATE_EXIT_POINT_ARG)malloc(Size);
if (CreateArg == NULL) {
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
DFSM_TRACE_HIGH(ERROR, DfspCreateExitPoint_Error2,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
goto ExitWithStatus;
}
RtlZeroMemory(CreateArg, Size);
//
// Put the fixed parameters into the buffer
//
CreateArg->Uid = *Uid;
CreateArg->Type = Type;
//
// Put the variable data in the buffer
//
pWc = (PCHAR)(CreateArg + 1);
CreateArg->Prefix = (LPWSTR)pWc;
RtlCopyMemory(CreateArg->Prefix, Prefix, wcslen(Prefix)*sizeof(WCHAR));
LPWSTR_TO_OFFSET(CreateArg->Prefix, CreateArg);
//
// Tell the driver!!
//
NtStatus = NtFsControlFile(
DriverHandle,
NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock,
FSCTL_DFS_CREATE_EXIT_POINT,
CreateArg,
Size,
ShortPrefix,
Len);
DFSM_TRACE_ERROR_HIGH(NtStatus, ALL_ERROR, DfspCreateExitPoint_Error_NtFsControlFile,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
free(CreateArg);
ExitWithStatus:
#if DBG
if (DfsSvcVerbose & 0x80000000)
DbgPrint("DfspCreateExitPoint exit 0x%x\n", NtStatus);
#endif
return NtStatus;
}
NTSTATUS
DfspDeleteExitPoint (
IN HANDLE DriverHandle,
IN LPGUID Uid,
IN LPWSTR Prefix,
IN ULONG Type)
{
NTSTATUS NtStatus;
IO_STATUS_BLOCK IoStatusBlock;
PDFS_DELETE_EXIT_POINT_ARG DeleteArg;
ULONG Size = sizeof(*DeleteArg);
PCHAR pWc;
if (Uid == NULL || Prefix == NULL) {
NtStatus = STATUS_INVALID_PARAMETER;
DFSM_TRACE_HIGH(ERROR, DfspDeleteExitPoint_Error1,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
goto ExitWithStatus;
}
#if DBG
if (DfsSvcVerbose & 0x80000000) {
WCHAR wszGuid[sizeof(GUID)*2+1];
GuidToString(Uid, wszGuid);
DbgPrint("DfspDeleteExitPoint(%ws,%ws,0x%x)\n",
wszGuid,
Prefix,
Type);
}
#endif
//
// Pack the args into a single buffer that can be sent to
// the dfs driver:
//
//
// First find the size...
//
if (Prefix != NULL) {
Size += (wcslen(Prefix) + 1) * sizeof(WCHAR);
}
//
// Now allocate the memory
//
DeleteArg = (PDFS_DELETE_EXIT_POINT_ARG)malloc(Size);
if (DeleteArg == NULL) {
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
DFSM_TRACE_HIGH(ERROR, DfspDeleteExitPoint_Error2,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
goto ExitWithStatus;
}
RtlZeroMemory(DeleteArg, Size);
//
// Put the fixed parameters into the buffer
//
DeleteArg->Uid = *Uid;
DeleteArg->Type = Type;
//
// Put the variable data in the buffer
//
pWc = (PCHAR)(DeleteArg + 1);
DeleteArg->Prefix = (LPWSTR)pWc;
RtlCopyMemory(DeleteArg->Prefix, Prefix, wcslen(Prefix)*sizeof(WCHAR));
LPWSTR_TO_OFFSET(DeleteArg->Prefix, DeleteArg);
//
// Tell the driver!!
//
NtStatus = NtFsControlFile(
DriverHandle,
NULL, // Event,
NULL, // ApcRoutine,
NULL, // ApcContext,
&IoStatusBlock,
FSCTL_DFS_DELETE_EXIT_POINT,
DeleteArg,
Size,
NULL,
0);
DFSM_TRACE_ERROR_HIGH(NtStatus, ALL_ERROR, DfspDeleteExitPoint_Error_NtFsControlFile,
LOGSTATUS(NtStatus)
LOGWSTR(Prefix));
free(DeleteArg);
ExitWithStatus:
#if DBG
if (DfsSvcVerbose & 0x80000000)
DbgPrint("DfspDeleteExitPoint exit 0x%x\n", NtStatus);
#endif
return NtStatus;
}