Source code of Windows XP (NT5)
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

//+---------------------------------------------------------------------------
//
// 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;
}