425 lines
14 KiB
C++
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;
|
|
}
|
|
|