mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
12 KiB
459 lines
12 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
|
//
|
|
// File: statprop.cxx
|
|
//
|
|
// Contents: Code that encapsulates the stat property set on Nt file systems
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <ntopen.hxx>
|
|
#include "statprop.hxx"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Construction/Destruction
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::CStatPropertyStorage
|
|
//
|
|
// Synopsis: Construct a stat property enumerator by querying the
|
|
// basic information from a handle
|
|
//
|
|
// Arguments: [FileHandle] - handle
|
|
//
|
|
// History: 10-Dec-97 KyleP Sum up streams to compute file size.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CStatPropertyStorage::CStatPropertyStorage( HANDLE FileHandle, unsigned cPathLength )
|
|
: _RefCount( 1 ),
|
|
_xBuf( (unsigned int)(1 +
|
|
( sizeof FILE_ALL_INFORMATION / sizeof LONGLONG ) +
|
|
( __max(
|
|
(MAX_PATH * sizeof WCHAR) / sizeof LONGLONG,
|
|
(cPathLength * sizeof WCHAR) / sizeof LONGLONG ) ) ) )
|
|
{
|
|
//
|
|
// We use the FileAllInformation info level which is a bit of overkill,
|
|
// but it has all the information we need to enumerate the properties.
|
|
//
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS Status = NtQueryInformationFile( FileHandle, // File handle
|
|
&IoStatus, // I/O Status
|
|
_xBuf.Get(), // Buffer
|
|
_xBuf.SizeOf(), // Buffer size
|
|
FileAllInformation );
|
|
|
|
Win4Assert( STATUS_DATATYPE_MISALIGNMENT != Status );
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
ciDebugOut(( DEB_IERROR, "Error 0x%x querying file info\n",
|
|
Status ));
|
|
QUIETTHROW( CException( Status ));
|
|
}
|
|
|
|
//
|
|
// Null-terminate in scratch buffer just beyond path
|
|
//
|
|
|
|
WCHAR * pwcsPathName = GetInfo().NameInformation.FileName;
|
|
pwcsPathName[GetInfo().NameInformation.FileNameLength/sizeof(WCHAR)] = 0;
|
|
|
|
//
|
|
// Setup filename by looking for a '\'
|
|
//
|
|
_FileName = pwcsPathName;
|
|
for ( int i = GetInfo().NameInformation.FileNameLength/sizeof(WCHAR) - 1; i >= 0; i-- )
|
|
{
|
|
if ( pwcsPathName[i] == L'\\' )
|
|
{
|
|
_FileName = &pwcsPathName[i+1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No longer necessary to sum the streams, now that CNSS uses sparse files to make
|
|
// docfiles look larger. Using CiNtFileSize results in different file sizes depending
|
|
// on which tool is used to look at the size (e.g. CI and 'dir' report differently).
|
|
//
|
|
|
|
#if 0
|
|
//
|
|
// Get the real file size (all streams)
|
|
//
|
|
|
|
LONGLONG llSize = CiNtFileSize( FileHandle );
|
|
|
|
if ( -1 != llSize )
|
|
GetInfo().StandardInformation.EndOfFile.QuadPart = llSize;
|
|
#endif
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IUnknown method implementations
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::QueryInterface
|
|
//
|
|
// Synopsis: Supports IID_IUnknown and IID_IPropertyStorage
|
|
//
|
|
// Arguments: [riid] - desired interface id
|
|
// [ppvObject] - output interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CStatPropertyStorage::QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
Win4Assert( 0 != ppvObject );
|
|
|
|
if ( IID_IPropertyStorage == riid )
|
|
*ppvObject = (void *)((IPropertyStorage *)this);
|
|
else if ( IID_IUnknown == riid )
|
|
*ppvObject = (void *)((IUnknown *)this);
|
|
else
|
|
{
|
|
*ppvObject = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
} //QueryInterface
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CStatPropertyStorage::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_RefCount);
|
|
} // AddRef
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CStatPropertyStorage::Release()
|
|
{
|
|
Win4Assert( _RefCount > 0 );
|
|
|
|
LONG RefCount = InterlockedDecrement(&_RefCount);
|
|
|
|
if ( RefCount <= 0 )
|
|
delete this;
|
|
|
|
return (ULONG) RefCount;
|
|
} // Release
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::ReadMultiple
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK if successful
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CStatPropertyStorage::ReadMultiple (
|
|
THIS_ ULONG cpspec,
|
|
const PROPSPEC __RPC_FAR rgpspec[ ],
|
|
PROPVARIANT __RPC_FAR rgpropvar[ ] )
|
|
{
|
|
//
|
|
// Walk through the prop specs looking for PID-identified
|
|
// properties
|
|
//
|
|
|
|
for (ULONG i = 0; i < cpspec; i++) {
|
|
|
|
//
|
|
// String named properties are not found
|
|
//
|
|
|
|
PROPID PropertyId;
|
|
|
|
if (rgpspec[i].ulKind == PRSPEC_LPWSTR) {
|
|
PropertyId = 0xFFFFFFFF;
|
|
} else {
|
|
PropertyId = rgpspec[i].propid;
|
|
}
|
|
|
|
//
|
|
// Fetch the appropriate property value
|
|
//
|
|
|
|
switch (PropertyId) {
|
|
case PID_STG_SIZE:
|
|
rgpropvar[i].vt = VT_I8;
|
|
rgpropvar[i].hVal = GetInfo().StandardInformation.EndOfFile;
|
|
break;
|
|
|
|
case PID_STG_NAME:
|
|
rgpropvar[i].vt = VT_LPWSTR;
|
|
rgpropvar[i].pwszVal =
|
|
(WCHAR *) CoTaskMemAlloc( (wcslen( _FileName ) + 1) * sizeof( WCHAR ));
|
|
|
|
if ( 0 == rgpropvar[i].pwszVal )
|
|
return E_OUTOFMEMORY;
|
|
|
|
wcscpy( rgpropvar[i].pwszVal, _FileName );
|
|
break;
|
|
|
|
case PID_STG_ATTRIBUTES:
|
|
rgpropvar[i].vt = VT_UI4;
|
|
rgpropvar[i].ulVal = GetInfo().BasicInformation.FileAttributes;
|
|
break;
|
|
|
|
case PID_STG_WRITETIME:
|
|
rgpropvar[i].vt = VT_FILETIME;
|
|
rgpropvar[i].filetime =
|
|
*(UNALIGNED FILETIME *)&GetInfo().BasicInformation.LastWriteTime.QuadPart;
|
|
break;
|
|
|
|
case PID_STG_CREATETIME:
|
|
rgpropvar[i].vt = VT_FILETIME;
|
|
rgpropvar[i].filetime =
|
|
*(UNALIGNED FILETIME *)&GetInfo().BasicInformation.CreationTime.QuadPart;
|
|
break;
|
|
|
|
case PID_STG_ACCESSTIME:
|
|
rgpropvar[i].vt = VT_FILETIME;
|
|
rgpropvar[i].filetime =
|
|
*(UNALIGNED FILETIME *)&GetInfo().BasicInformation.LastAccessTime.QuadPart;
|
|
break;
|
|
|
|
case PID_STG_CHANGETIME:
|
|
rgpropvar[i].vt = VT_FILETIME;
|
|
rgpropvar[i].filetime =
|
|
*(UNALIGNED FILETIME *)&GetInfo().BasicInformation.ChangeTime.QuadPart;
|
|
break;
|
|
|
|
//
|
|
// No other properties exist. They are Not Found.
|
|
//
|
|
|
|
default:
|
|
rgpropvar[i].vt = VT_EMPTY;
|
|
}
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
} //ReadMultiple
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyStorage::Enum
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: S_OK if successful
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CStatPropertyStorage::Enum (
|
|
THIS_ IEnumSTATPROPSTG __RPC_FAR *__RPC_FAR *ppenum )
|
|
{
|
|
*ppenum = new CStatPropertyEnum( IsNTFS() );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IUnknown method implementations
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyEnum::QueryInterface
|
|
//
|
|
// Synopsis: Supports IID_IUnknown and IID_IEnumSTATPROPSTG
|
|
//
|
|
// Arguments: [riid] - desired interface id
|
|
// [ppvObject] - output interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CStatPropertyEnum::QueryInterface(
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
Win4Assert( 0 != ppvObject );
|
|
|
|
if ( IID_IEnumSTATPROPSTG == riid )
|
|
*ppvObject = (void *)((IEnumSTATPROPSTG *)this);
|
|
else if ( IID_IUnknown == riid )
|
|
*ppvObject = (void *)((IUnknown *)this);
|
|
else
|
|
{
|
|
*ppvObject = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
} //QueryInterface
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyEnum::AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CStatPropertyEnum::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_RefCount);
|
|
} // AddRef
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyEnum::Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CStatPropertyEnum::Release()
|
|
{
|
|
Win4Assert( _RefCount > 0 );
|
|
|
|
LONG RefCount = InterlockedDecrement(&_RefCount);
|
|
|
|
if ( RefCount <= 0 )
|
|
delete this;
|
|
|
|
return RefCount;
|
|
} // Release
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IEnumSTATPROPSTG method implementations
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatPropertyEnum::Enum
|
|
//
|
|
// Synopsis: Enumerate through the stat properties
|
|
//
|
|
// Arguments: [celt] - maximum number of elements to return
|
|
// [rgelt] - output stat structures
|
|
// [pceltFetched] - number of elements returned
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CStatPropertyEnum::Next(
|
|
ULONG celt,
|
|
STATPROPSTG __RPC_FAR *rgelt,
|
|
ULONG __RPC_FAR *pceltFetched )
|
|
{
|
|
//
|
|
// We update the user's counter in place. Start it off at zero
|
|
//
|
|
|
|
*pceltFetched = 0;
|
|
|
|
//
|
|
// While we have more elements to return
|
|
//
|
|
|
|
while (celt--)
|
|
{
|
|
//
|
|
// No stat properties have names
|
|
//
|
|
|
|
rgelt->lpwstrName = NULL;
|
|
|
|
//
|
|
// Retrieve the appropriate value from the enumeration
|
|
//
|
|
|
|
switch (_Index++)
|
|
{
|
|
case 0:
|
|
rgelt->propid = PID_STG_CHANGETIME;
|
|
rgelt->vt = VT_FILETIME;
|
|
break;
|
|
|
|
case 1:
|
|
rgelt->propid = PID_STG_SIZE;
|
|
rgelt->vt = VT_I8;
|
|
break;
|
|
|
|
case 2:
|
|
rgelt->propid = PID_STG_NAME;
|
|
rgelt->vt = VT_LPWSTR;
|
|
break;
|
|
|
|
case 3:
|
|
rgelt->propid = PID_STG_ATTRIBUTES;
|
|
rgelt->vt = VT_UI4;
|
|
break;
|
|
|
|
case 4:
|
|
rgelt->propid = PID_STG_WRITETIME;
|
|
rgelt->vt = VT_FILETIME;
|
|
break;
|
|
|
|
case 5:
|
|
rgelt->propid = PID_STG_CREATETIME;
|
|
rgelt->vt = VT_FILETIME;
|
|
break;
|
|
|
|
case 6:
|
|
rgelt->propid = PID_STG_ACCESSTIME;
|
|
rgelt->vt = VT_FILETIME;
|
|
break;
|
|
|
|
default:
|
|
celt = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Note that we have fetched a value and advance to the next
|
|
// one.
|
|
//
|
|
|
|
(*pceltFetched)++;
|
|
rgelt++;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|