1027 lines
24 KiB
C++
1027 lines
24 KiB
C++
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name :
|
||
lsaux.cxx
|
||
|
||
Abstract:
|
||
This modules defines the functions supporting list processing.
|
||
|
||
Author:
|
||
|
||
Murali R. Krishnan ( MuraliK ) 2-May-1995
|
||
|
||
Environment:
|
||
User Mode -- Win32
|
||
|
||
Project:
|
||
|
||
FTP Server DLL
|
||
|
||
Functions Exported:
|
||
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
/************************************************************
|
||
* Include Headers
|
||
************************************************************/
|
||
# include "ftpdp.hxx"
|
||
# include "lsaux.hxx"
|
||
|
||
/************************************************************
|
||
* Functions
|
||
************************************************************/
|
||
|
||
|
||
const FILETIME *
|
||
PickFileTime(IN const WIN32_FIND_DATA * pfdInfo,
|
||
IN const LS_OPTIONS * pOptions)
|
||
/*++
|
||
|
||
This function selects and returns proper FILETIME structure
|
||
to display based on the current sort method and filesystem
|
||
capabilities.
|
||
|
||
Arguments:
|
||
pfdInfo pointer to file information for a directory entry.
|
||
pOptions the current ls options
|
||
|
||
Returns:
|
||
FILETIME -- pointer to proper time required
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
|
||
This is a costly operation too. Given that this one is called once every
|
||
directory entry is getting formatted. Can we avoid the cost ?
|
||
YES, if we can use the offsets in the pfdInfo to chose the time object.
|
||
NYI
|
||
--*/
|
||
{
|
||
const FILETIME * pliTime;
|
||
|
||
switch ( pOptions->SortMethod) {
|
||
|
||
case LsSortByName:
|
||
case LsSortByWriteTime:
|
||
pliTime = &pfdInfo->ftLastWriteTime;
|
||
break;
|
||
|
||
case LsSortByCreationTime:
|
||
pliTime = &pfdInfo->ftCreationTime;
|
||
break;
|
||
|
||
case LsSortByAccessTime:
|
||
pliTime = &pfdInfo->ftLastAccessTime;
|
||
break;
|
||
|
||
default:
|
||
IF_DEBUG( ERROR) {
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"Invalid Sort %d!\n", pOptions->SortMethod ));
|
||
}
|
||
DBG_ASSERT( FALSE );
|
||
pliTime = &pfdInfo->ftLastWriteTime;
|
||
break;
|
||
|
||
} // switch()
|
||
|
||
//
|
||
// If the selected time field is not supported on
|
||
// the current filesystem, default to ftLastWriteTime
|
||
// (all filesystems support this field).
|
||
//
|
||
|
||
if( NULL_FILE_TIME( *pliTime ) ) {
|
||
|
||
pliTime = &pfdInfo->ftLastWriteTime;
|
||
}
|
||
|
||
return ( pliTime);
|
||
} // PickFileTime()
|
||
|
||
|
||
|
||
|
||
BOOL __cdecl
|
||
FtpFilterFileInfo(
|
||
IN const WIN32_FIND_DATA * pfdInfo,
|
||
IN LPVOID pContext
|
||
)
|
||
/*++
|
||
This function tries to filter out the file information using
|
||
Ftp service "ls" specific filter.
|
||
|
||
Arguments:
|
||
pfdInfo pointer to file information that contains the current
|
||
file information object for filtering.
|
||
pContext pointer to FTP_LS_FILTER_INFO used for filtering.
|
||
|
||
Returns:
|
||
TRUE if there is a match and that this file info should not be
|
||
eliminated.
|
||
FALSE if this file info object can be dropped out of generated list.
|
||
--*/
|
||
{
|
||
register FTP_LS_FILTER_INFO * pfls = (FTP_LS_FILTER_INFO *) pContext;
|
||
DWORD dwAttribs;
|
||
BOOL fReturn;
|
||
|
||
if ( pfdInfo == NULL ||
|
||
pfdInfo->dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||
|
||
return ( FALSE);
|
||
}
|
||
|
||
//
|
||
// We dont need to expose hidden/system files unless necessary.
|
||
//
|
||
|
||
dwAttribs = pfdInfo->dwFileAttributes;
|
||
|
||
if (pfls->fFilterHidden && IS_HIDDEN( dwAttribs) ||
|
||
pfls->fFilterSystem && IS_SYSTEM( dwAttribs)) {
|
||
|
||
return ( FALSE); // unwanted files.
|
||
}
|
||
|
||
// Always filter away "." and ".."
|
||
const CHAR * pszFileName = ( pfdInfo->cFileName);
|
||
|
||
if (pfls->fFilterDotDot && pszFileName[0] == '.' ||
|
||
strcmp( pszFileName, ".") == 0 ||
|
||
strcmp( pszFileName, "..") == 0) {
|
||
|
||
return ( FALSE);
|
||
}
|
||
|
||
DBG_ASSERT( pfls->pszExpression == NULL || *pfls->pszExpression != '\0');
|
||
|
||
//
|
||
// Check about the file name.
|
||
// If the expression is not a regular expression, use simple StringCompare
|
||
// else use a regular expression comparison.
|
||
// Return TRUE if there is a match else return FALSE.
|
||
//
|
||
|
||
return ( pfls->pszExpression == NULL || // null-expr ==> all match.
|
||
(( pfls->fRegExpression)
|
||
? IsNameInRegExpressionA(pfls->pszExpression, pszFileName,
|
||
pfls->fIgnoreCase)
|
||
: !strcmp(pszFileName, pfls->pszExpression)
|
||
));
|
||
|
||
} // FtpFilterFileInfo()
|
||
|
||
|
||
|
||
APIERR
|
||
GetDirectoryInfo(
|
||
IN LPUSER_DATA pUserData,
|
||
OUT TS_DIRECTORY_INFO * pTsDirInfo,
|
||
IN CHAR * pszSearchPath,
|
||
IN const FTP_LS_FILTER_INFO * pfls,
|
||
IN PFN_CMP_WIN32_FIND_DATA pfnCompare
|
||
)
|
||
/*++
|
||
This function creates a directory listing for given directory,
|
||
filters out unmatched files and sorts the resulting elements
|
||
using the sort function.
|
||
|
||
Arguments:
|
||
pUserData pointer to UserData structure.
|
||
pTsDirInfo pointer to Directory Information object that will be
|
||
filled in with the directory information.
|
||
|
||
pszSearchPath pointer to null-terminated string containing
|
||
the absolute path for directory along with
|
||
the possible filter specification.
|
||
eg: d:\foo\bar
|
||
|
||
pfls pointer to filter information used for filtering.
|
||
|
||
pfnCompare pointer to function used for sorting.
|
||
|
||
Returns:
|
||
NO_ERROR on success and Win32 error code if there are any failure.
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
DWORD dwError = NO_ERROR;
|
||
|
||
DBG_ASSERT( pTsDirInfo != NULL && pszSearchPath != NULL);
|
||
DBG_ASSERT( !pTsDirInfo->IsValid()); // no dir list yet.
|
||
|
||
IF_DEBUG(DIR_LIST) {
|
||
|
||
DBGPRINTF((DBG_CONTEXT,
|
||
"GetDirListing( dir=%s, Filter=%08x (Sz=%s), "
|
||
"user=%08x, cmp=%08x)\n",
|
||
pszSearchPath, pfls, pfls->pszExpression,
|
||
pUserData->QueryUserToken(), pfnCompare));
|
||
}
|
||
|
||
CHAR rgDirPath[MAX_PATH+10];
|
||
CHAR * pszDirPath;
|
||
DWORD len = strlen( pszSearchPath);
|
||
|
||
// check to see if the last character is a "\" in the dir path
|
||
// if not append one to make sure GetDirectoryListing works fine.
|
||
if ( *CharPrev( pszSearchPath, pszSearchPath + len ) != '\\') {
|
||
DBG_ASSERT( len < sizeof(rgDirPath) - 2);
|
||
wsprintf( rgDirPath, "%s\\", pszSearchPath);
|
||
pszDirPath = rgDirPath;
|
||
} else {
|
||
|
||
pszDirPath = pszSearchPath;
|
||
}
|
||
|
||
if ( !pTsDirInfo->GetDirectoryListingA(pszDirPath,
|
||
pUserData->QueryUserToken())
|
||
) {
|
||
|
||
dwError = GetLastError();
|
||
}
|
||
|
||
|
||
if ( dwError == NO_ERROR) {
|
||
|
||
//
|
||
// we got the directory listing.
|
||
// We need to apply filters to restrict the directory listing.
|
||
// Next we need to sort the resulting mix based on the
|
||
// sorting options requested by the list command.
|
||
//
|
||
|
||
//
|
||
// We need to identify the appropriate filter
|
||
// file spec to be applied. For present use *.*
|
||
// Filtering should not fail unless tsDirInfo is invalid.
|
||
//
|
||
|
||
if ( pfls != NULL) {
|
||
|
||
DBG_REQUIRE(pTsDirInfo->FilterFiles(FtpFilterFileInfo,
|
||
(LPVOID )pfls)
|
||
);
|
||
}
|
||
|
||
//
|
||
// Sort only if sort function specified
|
||
//
|
||
|
||
if ( pfnCompare != NULL) {
|
||
|
||
DBG_REQUIRE( pTsDirInfo->SortFileInfoPointers( pfnCompare));
|
||
}
|
||
}
|
||
|
||
return ( dwError);
|
||
} // GetDirectoryInfo()
|
||
|
||
|
||
|
||
|
||
/**************************************************
|
||
* Comparison Functions
|
||
**************************************************/
|
||
|
||
|
||
int __cdecl
|
||
CompareNamesInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the two directory entries by name of the files.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
const WIN32_FIND_DATA * pFileInfo1 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo1);
|
||
const WIN32_FIND_DATA * pFileInfo2 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo2);
|
||
|
||
ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
|
||
|
||
return ( lstrcmpi((LPCSTR )pFileInfo1->cFileName,
|
||
(LPCSTR )pFileInfo2->cFileName));
|
||
|
||
} // CompareNamesInFileInfo()
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareNamesRevInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the two directory entries by name of the files.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
-1 if pvFileInfo1 > pvFileInfo2
|
||
+1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
return -CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
|
||
} // CompareNamesRevInFileInfo()
|
||
|
||
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareWriteTimesInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the write times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
const WIN32_FIND_DATA * pFileInfo1 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo1);
|
||
const WIN32_FIND_DATA * pFileInfo2 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo2);
|
||
|
||
ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
|
||
|
||
|
||
INT nResult;
|
||
|
||
nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
|
||
&pFileInfo2->ftLastWriteTime );
|
||
|
||
if( nResult == 0 ) {
|
||
|
||
nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
|
||
}
|
||
|
||
return nResult;
|
||
|
||
} // CompareWriteTimesInFileInfo()
|
||
|
||
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareWriteTimesRevInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the write times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
-1 if pvFileInfo1 > pvFileInfo2
|
||
+1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
return -CompareWriteTimesInFileInfo( pvFileInfo1, pvFileInfo2);
|
||
|
||
} // CompareWriteTimesRevInFileInfo()
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareCreationTimesInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the creation times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
const WIN32_FIND_DATA * pFileInfo1 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo1);
|
||
const WIN32_FIND_DATA * pFileInfo2 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo2);
|
||
|
||
ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
|
||
|
||
|
||
INT nResult;
|
||
|
||
if ( NULL_FILE_TIME( pFileInfo1->ftCreationTime)) {
|
||
|
||
nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
|
||
&pFileInfo2->ftLastWriteTime );
|
||
} else {
|
||
|
||
nResult = CompareFileTime(&pFileInfo1->ftCreationTime,
|
||
&pFileInfo2->ftCreationTime );
|
||
}
|
||
|
||
if( nResult == 0 ) {
|
||
|
||
nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
|
||
}
|
||
|
||
return nResult;
|
||
|
||
} // CompareCreationTimesInFileInfo()
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareCreationTimesRevInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the creation times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
return -CompareCreationTimesInFileInfo( pvFileInfo1, pvFileInfo2 );
|
||
|
||
} // CompareCreationTimesRevInFileInfo()
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareAccessTimesInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
Compares the last access times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
const WIN32_FIND_DATA * pFileInfo1 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo1);
|
||
const WIN32_FIND_DATA * pFileInfo2 =
|
||
*((const WIN32_FIND_DATA **) pvFileInfo2);
|
||
|
||
ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
|
||
|
||
|
||
INT nResult;
|
||
|
||
if ( NULL_FILE_TIME( pFileInfo1->ftLastAccessTime)) {
|
||
|
||
nResult = CompareFileTime(&pFileInfo1->ftLastWriteTime,
|
||
&pFileInfo2->ftLastWriteTime );
|
||
} else {
|
||
|
||
nResult = CompareFileTime(&pFileInfo1->ftLastAccessTime,
|
||
&pFileInfo2->ftLastAccessTime );
|
||
}
|
||
|
||
if( nResult == 0 ) {
|
||
|
||
nResult = CompareNamesInFileInfo( pvFileInfo1, pvFileInfo2);
|
||
}
|
||
|
||
return nResult;
|
||
|
||
} // CompareAccessTimesInFileInfo()
|
||
|
||
|
||
|
||
int __cdecl
|
||
CompareAccessTimesRevInFileInfo(
|
||
IN const void * pvFileInfo1,
|
||
IN const void * pvFileInfo2)
|
||
/*++
|
||
|
||
Compares the last access times of two directory entries.
|
||
|
||
Arguments:
|
||
|
||
pvFileInfo1 pointer to FileBothDirInfo object 1.
|
||
pvFileInfo2 pointer to FileBothDirInfo object 2.
|
||
|
||
Returns:
|
||
0 if they are same
|
||
+1 if pvFileInfo1 > pvFileInfo2
|
||
-1 if pvFileInfo1 < pvFileInfo2
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
return -CompareAccessTimesInFileInfo( pvFileInfo1, pvFileInfo2 );
|
||
|
||
} // CompareAccessTimesRevInFileInfo()
|
||
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
ComputeModeBits(
|
||
IN HANDLE hUserToken,
|
||
IN const CHAR * pszPathPart,
|
||
IN const WIN32_FIND_DATA * pfdInfo,
|
||
IN DWORD * pcLinks,
|
||
IN BOOL fVolumeReadable,
|
||
IN BOOL fVolumeWritable
|
||
)
|
||
/*++
|
||
This function computes the mode buts r-w-x for a specific file.
|
||
|
||
Arguments:
|
||
hUserToken - The security token of the user that initiated the request.
|
||
pszPathPart - contains the search path for this directory.
|
||
pfdInfo - pointer to File information
|
||
pcLinks - will receive the count of symbolic links to this file.
|
||
fVolumeReadable - TRUE if volume is readable
|
||
fVolumeWritable - TRUE if volume is writable
|
||
|
||
Returns:
|
||
DWORD - A combination of FILE_MODE_R, FILE_MODE_W, and FILE_MODE_X bits.
|
||
|
||
HISTORY:
|
||
KeithMo 01-Jun-1993 Created.
|
||
MuraliK 26-Apr-1995 Modified to support new pfdInfo
|
||
--*/
|
||
{
|
||
APIERR err;
|
||
DWORD dwAccess;
|
||
DWORD dwMode = 0;
|
||
|
||
DBG_ASSERT( hUserToken != NULL );
|
||
DBG_ASSERT( pszPathPart != NULL );
|
||
DBG_ASSERT( pfdInfo != NULL );
|
||
DBG_ASSERT( pcLinks != NULL );
|
||
DBG_ASSERT( pszPathPart[1] == ':' );
|
||
DBG_ASSERT( pszPathPart[2] == '\\' );
|
||
|
||
if( !( GetFsFlags( *pszPathPart ) & FS_PERSISTENT_ACLS ) )
|
||
{
|
||
//
|
||
// Short-circuit if on a non-NTFS partition.
|
||
//
|
||
|
||
*pcLinks = 1;
|
||
dwAccess = FILE_ALL_ACCESS;
|
||
|
||
err = NO_ERROR;
|
||
}
|
||
else
|
||
{
|
||
CHAR szPath[MAX_PATH*2];
|
||
CHAR * pszEnd;
|
||
INT len;
|
||
|
||
//
|
||
// Determine the maximum file access allowed.
|
||
//
|
||
|
||
DBG_ASSERT( strlen( pszPathPart) +
|
||
strlen( pfdInfo->cFileName) < MAX_PATH * 2);
|
||
|
||
len = strlen( pszPathPart );
|
||
memcpy( szPath, pszPathPart, len );
|
||
szPath[len] = '\0';
|
||
pszEnd = CharPrev( szPath, szPath + len );
|
||
if( *pszEnd != '\\' && *pszEnd != '/' ) {
|
||
pszEnd = szPath + len;
|
||
*pszEnd = '\\';
|
||
}
|
||
strcpy( pszEnd + 1, pfdInfo->cFileName );
|
||
|
||
err = ComputeFileInfo( hUserToken,
|
||
szPath,
|
||
&dwAccess,
|
||
pcLinks );
|
||
}
|
||
|
||
if( err == NO_ERROR )
|
||
{
|
||
|
||
|
||
//
|
||
// Map various NT access to unix-like mode bits.
|
||
//
|
||
|
||
if( fVolumeReadable && ( dwAccess & FILE_READ_DATA ) )
|
||
{
|
||
dwMode |= FILE_MODE_R;
|
||
}
|
||
|
||
if( fVolumeReadable && ( dwAccess & FILE_EXECUTE ) )
|
||
{
|
||
dwMode |= FILE_MODE_X;
|
||
}
|
||
|
||
if( fVolumeWritable &&
|
||
!( pfdInfo->dwFileAttributes & FILE_ATTRIBUTE_READONLY ) &&
|
||
( dwAccess & FILE_WRITE_DATA ) &&
|
||
( dwAccess & FILE_APPEND_DATA ) )
|
||
{
|
||
dwMode |= FILE_MODE_W;
|
||
}
|
||
}
|
||
|
||
return dwMode;
|
||
|
||
} // ComputeModeBits()
|
||
|
||
|
||
|
||
|
||
#define DEFAULT_SECURITY_DESC_SIZE ( 2048)
|
||
#define DEFAULT_PRIV_SET_SIZE ( 1024)
|
||
|
||
|
||
APIERR
|
||
ComputeFileInfo(
|
||
HANDLE hUserToken,
|
||
CHAR * pszFile,
|
||
DWORD * pdwAccessGranted,
|
||
DWORD * pcLinks
|
||
)
|
||
/*++
|
||
This function uses internal Nt security api's to determine if the
|
||
valid access is granted.
|
||
|
||
BEWARE: this function is extremely costly! We need to simplify the cost.
|
||
==>> NYI
|
||
|
||
Arguments:
|
||
hUserToken - handle for the user, for whom we are determining the
|
||
access and links
|
||
pszFile - full path for the file.
|
||
pdwAccessGranted - pointer to DWORD which will receive the granted access.
|
||
pcLinks - pointer to count of links for the file.
|
||
|
||
Returns:
|
||
Win32 Error code if there is any failure.
|
||
NO_ERROR on success.
|
||
--*/
|
||
{
|
||
NTSTATUS NtStatus;
|
||
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||
APIERR err;
|
||
SECURITY_DESCRIPTOR * psd = NULL;
|
||
PRIVILEGE_SET * pps = NULL;
|
||
DWORD cbsd;
|
||
DWORD cbps;
|
||
GENERIC_MAPPING mapping = { 0, 0, 0, FILE_ALL_ACCESS };
|
||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
BOOL fStatus;
|
||
|
||
DBG_ASSERT( hUserToken != NULL );
|
||
DBG_ASSERT( pszFile != NULL );
|
||
DBG_ASSERT( pdwAccessGranted != NULL );
|
||
DBG_ASSERT( pcLinks != NULL );
|
||
|
||
//
|
||
// Setup.
|
||
//
|
||
|
||
*pdwAccessGranted = 0;
|
||
*pcLinks = 1;
|
||
|
||
//
|
||
// Open the target file/directory.
|
||
//
|
||
|
||
err = OpenPathForAccess( &hFile,
|
||
pszFile,
|
||
GENERIC_READ,
|
||
( FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||
FILE_SHARE_DELETE),
|
||
hUserToken
|
||
);
|
||
|
||
if( err != NO_ERROR )
|
||
{
|
||
return err;
|
||
}
|
||
|
||
//
|
||
// Determine the number of symbolic links.
|
||
//
|
||
|
||
if ( GetFileInformationByHandle( hFile,
|
||
&FileInfo)
|
||
) {
|
||
|
||
*pcLinks = FileInfo.nNumberOfLinks;
|
||
} else {
|
||
|
||
//
|
||
// We won't let this be serious enough to abort
|
||
// the entire operation.
|
||
//
|
||
|
||
*pcLinks = 1;
|
||
}
|
||
|
||
//
|
||
// Get the file's security descriptor.
|
||
//
|
||
|
||
cbsd = DEFAULT_SECURITY_DESC_SIZE;
|
||
psd = (SECURITY_DESCRIPTOR *)TCP_ALLOC( cbsd );
|
||
|
||
if( psd == NULL )
|
||
{
|
||
err = GetLastError();
|
||
goto Cleanup;
|
||
}
|
||
|
||
do
|
||
{
|
||
err = NO_ERROR;
|
||
|
||
//
|
||
// Replace NtQuerySecurityObject() by GetFileSecurity()
|
||
//
|
||
|
||
if (!GetFileSecurity( pszFile,
|
||
OWNER_SECURITY_INFORMATION
|
||
| GROUP_SECURITY_INFORMATION
|
||
| DACL_SECURITY_INFORMATION,
|
||
psd,
|
||
cbsd,
|
||
&cbsd )
|
||
) {
|
||
|
||
err = GetLastError();
|
||
}
|
||
|
||
if( err == ERROR_INSUFFICIENT_BUFFER )
|
||
{
|
||
TCP_FREE( psd );
|
||
psd = (SECURITY_DESCRIPTOR *)TCP_ALLOC( cbsd );
|
||
|
||
if( psd == NULL )
|
||
{
|
||
err = GetLastError();
|
||
break;
|
||
}
|
||
}
|
||
|
||
} while( err == ERROR_INSUFFICIENT_BUFFER );
|
||
|
||
if( err != NO_ERROR ) {
|
||
|
||
IF_DEBUG( DIR_LIST) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot get security for %s, error %lu\n",
|
||
pszFile,
|
||
err ));
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Check access.
|
||
//
|
||
|
||
cbps = DEFAULT_PRIV_SET_SIZE;
|
||
pps = (PRIVILEGE_SET *)TCP_ALLOC( cbps );
|
||
|
||
if( pps == NULL )
|
||
{
|
||
err = GetLastError();
|
||
goto Cleanup;
|
||
}
|
||
|
||
do
|
||
{
|
||
if( AccessCheck( psd,
|
||
hUserToken,
|
||
MAXIMUM_ALLOWED,
|
||
&mapping,
|
||
pps,
|
||
&cbps,
|
||
pdwAccessGranted,
|
||
&fStatus ) )
|
||
{
|
||
err = fStatus ? NO_ERROR : GetLastError();
|
||
|
||
if( err != NO_ERROR )
|
||
{
|
||
IF_DEBUG( DIR_LIST) {
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"AccessCheck() failure. Error=%d\n", err ));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
err = GetLastError();
|
||
|
||
if( err == ERROR_INSUFFICIENT_BUFFER )
|
||
{
|
||
TCP_FREE( pps );
|
||
pps = (PRIVILEGE_SET *)TCP_ALLOC( cbps );
|
||
|
||
if( pps == NULL )
|
||
{
|
||
err = GetLastError();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
} while( err == ERROR_INSUFFICIENT_BUFFER );
|
||
|
||
if( err != NO_ERROR )
|
||
{
|
||
IF_DEBUG(DIR_LIST) {
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot get check access for %s, error %lu\n",
|
||
pszFile,
|
||
err ));
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if( psd != NULL )
|
||
{
|
||
TCP_FREE( psd );
|
||
}
|
||
|
||
if( pps != NULL )
|
||
{
|
||
TCP_FREE( pps );
|
||
}
|
||
|
||
if( hFile != INVALID_HANDLE_VALUE )
|
||
{
|
||
CloseHandle( hFile );
|
||
}
|
||
|
||
return err;
|
||
|
||
} // ComputeFileInfo()
|
||
|
||
|
||
|
||
|
||
|
||
# define INVALID_FS_FLAGS ((DWORD ) -1L)
|
||
|
||
|
||
DWORD
|
||
GetFsFlags( IN CHAR chDrive)
|
||
/*++
|
||
|
||
This function uses GetVolumeInformation to retrieve the file system
|
||
flags for the given drive.
|
||
|
||
Arguments:
|
||
chDrive the drive letter to check for. Must be A-Z.
|
||
|
||
Returns:
|
||
DWORD containing the FS flags. 0 if unknown.
|
||
|
||
History:
|
||
MuraliK 25-Apr-1995
|
||
--*/
|
||
{
|
||
INT iDrive;
|
||
DWORD Flags = INVALID_FS_FLAGS;
|
||
|
||
static DWORD p_FsFlags[26] = {
|
||
// One per DOS drive (A - Z).
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS, INVALID_FS_FLAGS,
|
||
INVALID_FS_FLAGS, INVALID_FS_FLAGS
|
||
};
|
||
|
||
//
|
||
// Validate the parameter & map to uppercase.
|
||
//
|
||
|
||
chDrive = (INT)toupper( chDrive );
|
||
DBG_ASSERT( ( chDrive >= 'A' ) && ( chDrive <= 'Z' ) );
|
||
|
||
iDrive = (INT)( chDrive - 'A' );
|
||
|
||
//
|
||
// If we've already touched this drive, use the
|
||
// cached value.
|
||
//
|
||
|
||
Flags = p_FsFlags[iDrive];
|
||
|
||
if( Flags == INVALID_FS_FLAGS )
|
||
{
|
||
CHAR szRoot[] = "d:\\";
|
||
|
||
//
|
||
// Retrieve the flags.
|
||
//
|
||
|
||
szRoot[0] = chDrive;
|
||
|
||
GetVolumeInformation( szRoot, // lpRootPathName
|
||
NULL, // lpVolumeNameBuffer
|
||
0, // nVolumeNameSize
|
||
NULL, // lpVolumeSerialNumber
|
||
NULL, // lpMaximumComponentLength
|
||
&Flags, // lpFileSystemFlags
|
||
NULL, // lpFileSYstemNameBuffer,
|
||
0 ); // nFileSystemNameSize
|
||
|
||
p_FsFlags[iDrive] = Flags;
|
||
}
|
||
|
||
return ( Flags == INVALID_FS_FLAGS ) ? 0 : Flags;
|
||
|
||
} // GetFsFlags()
|
||
|
||
/************************ End of File ***********************/
|