NT4/private/ole32/stg/fsstg/ntenm.cxx
2020-09-30 17:12:29 +02:00

425 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: ntenm.cxx
//
// Contents: NT handle enumerator
//
// History: 12-Jul-93 DrewB Created
//
//----------------------------------------------------------------------------
#include "headers.cxx"
#pragma hdrstop
#include "ntenm.hxx"
//+---------------------------------------------------------------------------
//
// Member: CNtEnum::InitFromHandle, public
//
// Synopsis: Initialize from a handle
//
// Arguments: [h] - Handle
// [fReset] - Initial reset status
//
// Returns: Appropriate status code
//
// History: 12-Jul-93 DrewB Created
//
// Notes: Takes a new reference on the handle
//
//----------------------------------------------------------------------------
SCODE CNtEnum::InitFromHandle(HANDLE h, BOOL fReset)
{
SCODE sc = S_OK;
BOOL fClone = TRUE; // BUGBUG should be a parameter
ssDebugOut((DEB_ITRACE, "In CNtEnum::InitFromHandle:%p(%p, %d)\n",
this, h, fReset));
if (!fClone)
ssChk(DupNtHandle(h, &_h));
else
{
NTSTATUS nts; // if this is cloned enumerator
IO_STATUS_BLOCK iosb; // reopen handle to get new cursor
OBJECT_ATTRIBUTES oa;
UNICODE_STRING us = {0, 0, NULL};
DWORD accessMask = GENERIC_READ | DELETE | SYNCHRONIZE;
DWORD shareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, h, NULL);
if (!NT_SUCCESS(nts=NtOpenFile (&_h, accessMask, &oa, &iosb,
shareAccess, FILE_SYNCHRONOUS_IO_NONALERT)))
{
// BUGBUG it's probably not safe to dup the handle, since
// base storage object may do a CopyTo or DestroyTree
// but we need to create enumerators with share_exclusive handles
if (nts == STATUS_SHARING_VIOLATION || // local error
nts == STATUS_ACCESS_DENIED || // local error
nts == STATUS_OBJECT_TYPE_MISMATCH) // dfs error
sc = DupNtHandle(h, &_h);
else
{
ssDebugOut((DEB_ERROR,"CNtEnum pseudo-DUP open failed %x\n",nts));
sc = NtStatusToScode (nts);
}
}
}
ssAssert (fReset);
_nes = NES_RESET_PENDING;
EH_Err:
ssDebugOut((DEB_ITRACE, "Out CNtEnum::InitFromHandle\n"));
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CNtEnum::Next, public
//
// Synopsis: Retrieves the next enumeration entry
//
// Arguments: [pstat] - STATSTG to fill in
// [pwcsName] - Name buffer or NULL
// [dwNte] - NTE flag controlling name return
// [pfd] - Dir/file flag return
//
// Returns: Appropriate status code
//
// BUGBUG: This call should retrieve the storage type from the info class
// in order to set the PFD field.
//
// Note: Nt supports enumeration of storages/streams through two
// different calls. We maintain a state flag that indicates which
// of the two different API we are using.
//
// Worse, enumeration of children occurs through an enumerator
// while enumeration of streams through a get-all call. This
// latter call requires allocating a big buffer and hoping it's
// big enough to handle the data.
//
// Modifies: [pstat]
// [pwcsName]
// [pfDir]
//
// History: 12-Jul-93 DrewB Created
//
//----------------------------------------------------------------------------
SCODE CNtEnum::Next(STATSTG *pstat, WCHAR *pwcsName, DWORD dwNte, FILEDIR *pfd)
{
SCODE sc;
NTSTATUS nts;
IO_STATUS_BLOCK iosb;
FILE_DIRECTORY_INFORMATION *pfdi;
ULONG cbFdi;
WCHAR *pwcs;
UNICODE_STRING us, *pus;
BOOL fDotOrDotDot;
ssDebugOut((DEB_ITRACE, "In CNtEnum::Next:%p(%p, %p, %lu, %p)\n",
this, pwcsName, dwNte, pfd));
cbFdi = sizeof(FILE_DIRECTORY_INFORMATION)+
MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR);
ssMem(pfdi = (FILE_DIRECTORY_INFORMATION *)new BYTE[cbFdi]);
// Set up match string to force enumeration from beginning.
if (_nes == NES_RESET_PENDING)
{
pus = &us;
//
// The asterisk below is needed so the redirector won't
// return STATUS_INVALID_HANDLE after the first call (it
// optimizes the single shot query because it thinks
// OFS is not enumerating multiple files.)
//
RtlInitUnicodeString (pus, _fIsStorage ? L"\1*" : L"*");
}
else
pus = NULL;
do
{
// Retrieve next single content of directory
nts = NtQueryDirectoryFile(_h, NULL, NULL, NULL, &iosb, pfdi, cbFdi,
FileDirectoryInformation, TRUE,
_nes == NES_RESET_PENDING ? pus : NULL,
_nes == NES_RESET_PENDING);
if (nts == STATUS_NO_MORE_FILES || nts == STATUS_NO_SUCH_FILE)
{
sc = S_FALSE;
break;
}
if (!NT_SUCCESS (nts))
{
sc = NtStatusToScode (nts);
break;
}
sc = S_OK;
_nes = NES_ENUM_DIR;
fDotOrDotDot =
(pfdi->FileNameLength == 2 && pfdi->FileName[0] == L'.') ||
(pfdi->FileNameLength == 4 && pfdi->FileName[0] == L'.' && pfdi->FileName[1] == L'.');
if (!fDotOrDotDot)
{
pstat->pwcsName = NULL;
if (dwNte == NTE_STATNAME)
{
ssChkTo(EH_pdfi,
GetScode(CoMemAlloc(pfdi->FileNameLength+sizeof(WCHAR),
(void **)&pstat->pwcsName)));
pwcs = pstat->pwcsName;
}
else if (dwNte == NTE_BUFFERNAME)
{
ssAssert(pwcsName != NULL);
pwcs = pwcsName;
}
else
{
ssAssert(dwNte == NTE_NONAME);
pwcs = NULL;
}
if (pwcs)
{
memcpy(pwcs, pfdi->FileName, pfdi->FileNameLength);
*(WCHAR *)((BYTE *)pwcs+pfdi->FileNameLength) = 0;
}
if (SUCCEEDED(sc))
{
pstat->type =
(pfdi->FileAttributes & ~FILE_ATTRIBUTE_PROPERTY_SET) == 0?
STGTY_STREAM : STGTY_STORAGE;
LARGE_INTEGER_TO_FILETIME(&pfdi->LastWriteTime, &pstat->mtime);
LARGE_INTEGER_TO_FILETIME(&pfdi->CreationTime, &pstat->ctime);
LARGE_INTEGER_TO_FILETIME(&pfdi->LastAccessTime, &pstat->atime);
pstat->grfMode = 0;
pstat->grfLocksSupported = 0;
pstat->clsid = CLSID_NULL; // BUGBUG: BillMo, RAID# 13804, should return real clsid
// from file system.
pstat->grfStateBits = 0;
if (pfdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
pstat->STATSTG_dwStgFmt = STGFMT_DIRECTORY;
*pfd = FD_DIR;
pstat->cbSize.HighPart = pstat->cbSize.LowPart = 0;
}
else
{
pstat->STATSTG_dwStgFmt = STGFMT_DOCUMENT;
if ((pfdi->FileAttributes & ~FILE_ATTRIBUTE_PROPERTY_SET) == 0)
{
*pfd = FD_STREAM;
pstat->cbSize.HighPart = pfdi->EndOfFile.HighPart;
pstat->cbSize.LowPart = pfdi->EndOfFile.LowPart;
}
else
{
*pfd = FD_STORAGE;
pstat->cbSize.HighPart = pstat->cbSize.LowPart = 0;
}
}
}
}
} while (fDotOrDotDot);
ssDebugOut((DEB_ITRACE, "Out CNtEnum::Next\n"));
EH_pdfi:
delete pfdi;
EH_Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CNtEnum::NextOfs, public
//
// Synopsis: Retrieves the next enumeration entry
//
// Arguments: [pstat] - STATSTG to fill in
// [pwcsName] - Name buffer or NULL
// [dwNte] - NTE flag controlling name return
// [pfd] - Dir/file flag return
//
// Returns: Appropriate status code
//
// BUGBUG: This call should retrieve the storage type from the info class
// in order to set the PFD field.
//
// Note: Identical to Next,but return OLE info from OFS
// Can be optimized to use C++ templates
//
// Modifies: [pstat]
// [pwcsName]
// [pfDir]
//
// History: 18-Jul-1995 HenryLee created
//
//----------------------------------------------------------------------------
SCODE CNtEnum::NextOfs(STATSTG *pstat,WCHAR *pwcsName,DWORD dwNte,FILEDIR *pfd)
{
SCODE sc;
NTSTATUS nts;
IO_STATUS_BLOCK iosb;
FILE_OLE_DIR_INFORMATION *pfdi;
ULONG cbFdi;
WCHAR *pwcs;
UNICODE_STRING us, *pus;
BOOL fDotOrDotDot;
ssDebugOut((DEB_ITRACE, "In CNtEnum::NextOfs:%p(%p, %p, %lu, %p)\n",
this, pwcsName, dwNte, pfd));
cbFdi = sizeof(FILE_OLE_DIR_INFORMATION)+
MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR);
ssMem(pfdi = (FILE_OLE_DIR_INFORMATION *)new BYTE[cbFdi]);
// Set up match string to force enumeration from beginning.
if (_nes == NES_RESET_PENDING)
{
pus = &us;
//
// The asterisk below is needed so the redirector won't
// return STATUS_INVALID_HANDLE after the first call (it
// optimizes the single shot query because it thinks
// OFS is not enumerating multiple files.)
//
RtlInitUnicodeString (pus, _fIsStorage ? L"\1*" : L"*");
}
else
pus = NULL;
do
{
// Retrieve next single content of directory
nts = NtQueryDirectoryFile(_h, NULL, NULL, NULL, &iosb, pfdi, cbFdi,
FileOleDirectoryInformation, TRUE,
_nes == NES_RESET_PENDING ? pus : NULL,
_nes == NES_RESET_PENDING);
if (nts == STATUS_NO_MORE_FILES || nts == STATUS_NO_SUCH_FILE)
{
sc = S_FALSE;
break;
}
if (!NT_SUCCESS (nts))
{
sc = NtStatusToScode (nts);
break;
}
sc = S_OK;
_nes = NES_ENUM_DIR;
fDotOrDotDot =
(pfdi->FileNameLength == 2 && pfdi->FileName[0] == L'.') ||
(pfdi->FileNameLength == 4 && pfdi->FileName[0] == L'.' && pfdi->FileName[1] == L'.');
if (!fDotOrDotDot)
{
pstat->pwcsName = NULL;
if (dwNte == NTE_STATNAME)
{
ssChkTo(EH_pdfi,
GetScode(CoMemAlloc(pfdi->FileNameLength+sizeof(WCHAR),
(void **)&pstat->pwcsName)));
pwcs = pstat->pwcsName;
}
else if (dwNte == NTE_BUFFERNAME)
{
ssAssert(pwcsName != NULL);
pwcs = pwcsName;
}
else
{
ssAssert(dwNte == NTE_NONAME);
pwcs = NULL;
}
if (pwcs)
{
memcpy(pwcs, pfdi->FileName, pfdi->FileNameLength);
*(WCHAR *)((BYTE *)pwcs+pfdi->FileNameLength) = 0;
}
if (SUCCEEDED(sc))
{
pstat->type = STGTY_STORAGE;
LARGE_INTEGER_TO_FILETIME(&pfdi->LastWriteTime, &pstat->mtime);
LARGE_INTEGER_TO_FILETIME(&pfdi->CreationTime, &pstat->ctime);
LARGE_INTEGER_TO_FILETIME(&pfdi->LastAccessTime, &pstat->atime);
pstat->grfMode = 0;
pstat->grfLocksSupported = 0;
pstat->clsid = pfdi->OleClassId;
pstat->grfStateBits = pfdi->OleStateBits;
pstat->cbSize.HighPart = pstat->cbSize.LowPart = 0;
if (pfdi->StorageType == StorageTypeDirectory)
{
pstat->STATSTG_dwStgFmt = STGFMT_DIRECTORY;
*pfd = FD_DIR;
}
else if (pfdi->StorageType == StorageTypeJunctionPoint)
{
pstat->STATSTG_dwStgFmt = STGFMT_JUNCTION;
*pfd = FD_JUNCTION;
}
else
{
pstat->STATSTG_dwStgFmt = STGFMT_DOCUMENT;
if (pfdi->StorageType == StorageTypeStream)
{
if ((pfdi->FileAttributes &
FILE_ATTRIBUTE_PROPERTY_SET) == 0)
{
ssAssert(pfdi->FileAttributes == 0);
pstat->mtime.dwHighDateTime = pstat->mtime.dwLowDateTime = 0;
}
pstat->ctime.dwHighDateTime = pstat->ctime.dwLowDateTime = 0;
pstat->atime.dwHighDateTime = pstat->atime.dwLowDateTime = 0;
*pfd = FD_STREAM;
pstat->cbSize.QuadPart = pfdi->EndOfFile.QuadPart;
pstat->type = STGTY_STREAM;
}
else
{
*pfd = FD_STORAGE;
}
}
}
}
} while (fDotOrDotDot);
ssDebugOut((DEB_ITRACE, "Out CNtEnum::NextOfs\n"));
EH_pdfi:
delete pfdi;
EH_Err:
return sc;
}