351 lines
7.8 KiB
C
351 lines
7.8 KiB
C
|
/********************************************************************/
|
||
|
/** Copyright(c) 1989 Microsoft Corporation. **/
|
||
|
/********************************************************************/
|
||
|
|
||
|
//***
|
||
|
//
|
||
|
// Filename: finder.c
|
||
|
//
|
||
|
// Description: This module contains support routines for the finder
|
||
|
// category API's for the AFP server service
|
||
|
//
|
||
|
// History:
|
||
|
// Sept 30,1993. NarenG Created original version.
|
||
|
//
|
||
|
#include "afpsvcp.h"
|
||
|
|
||
|
BOOL
|
||
|
IsTargetNTFS(
|
||
|
IN LPWSTR lpwsPath
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
CopyStream(
|
||
|
IN HANDLE hSrc,
|
||
|
IN HANDLE hDst
|
||
|
);
|
||
|
|
||
|
#define AFP_RESC_STREAM TEXT(":AFP_Resource")
|
||
|
|
||
|
//**
|
||
|
//
|
||
|
// Call: AfpAdminrFinderSetInfo
|
||
|
//
|
||
|
// Returns: NO_ERROR
|
||
|
// ERROR_ACCESS_DENIED
|
||
|
// non-zero returns from AfpServerIOCtrl
|
||
|
//
|
||
|
// Description: This routine communicates with the AFP FSD to implement
|
||
|
// the AfpAdminFinderSetInfo function.
|
||
|
//
|
||
|
DWORD
|
||
|
AfpAdminrFinderSetInfo(
|
||
|
IN AFP_SERVER_HANDLE hServer,
|
||
|
IN LPWSTR pType,
|
||
|
IN LPWSTR pCreator,
|
||
|
IN LPWSTR pData,
|
||
|
IN LPWSTR pResource,
|
||
|
IN LPWSTR pTarget,
|
||
|
IN DWORD dwParmNum
|
||
|
)
|
||
|
{
|
||
|
AFP_REQUEST_PACKET AfpSrp;
|
||
|
DWORD dwRetCode = NO_ERROR, dwRetryCount = 0;
|
||
|
AFP_FINDER_INFO AfpFinderInfo;
|
||
|
LPBYTE pAfpFinderInfoSR = NULL;
|
||
|
DWORD cbAfpFinderInfoSRSize;
|
||
|
DWORD dwAccessStatus=0;
|
||
|
HANDLE hTarget = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hDataSrc = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hResourceSrc = INVALID_HANDLE_VALUE;
|
||
|
LPWSTR lpwsResourceFork;
|
||
|
BOOLEAN fCreatedFile = FALSE;
|
||
|
|
||
|
|
||
|
// Check if caller has access
|
||
|
//
|
||
|
if ( dwRetCode = AfpSecObjAccessCheck( AFPSVC_ALL_ACCESS, &dwAccessStatus))
|
||
|
{
|
||
|
AFP_PRINT(( "SFMSVC: AfpAdminrFinderSetInfo, AfpSecObjAccessCheck failed %ld\n",dwRetCode));
|
||
|
AfpLogEvent( AFPLOG_CANT_CHECK_ACCESS, 0, NULL,
|
||
|
dwRetCode, EVENTLOG_ERROR_TYPE );
|
||
|
return( ERROR_ACCESS_DENIED );
|
||
|
}
|
||
|
|
||
|
if ( dwAccessStatus )
|
||
|
{
|
||
|
AFP_PRINT(( "SFMSVC: AfpAdminrFinderSetInfo, AfpSecObjAccessCheck returned %ld\n",dwAccessStatus));
|
||
|
return( ERROR_ACCESS_DENIED );
|
||
|
}
|
||
|
|
||
|
if ( wcsstr( pTarget, (LPWSTR)TEXT(":\\") ) == NULL )
|
||
|
return( ERROR_INVALID_NAME );
|
||
|
|
||
|
if ( !IsTargetNTFS( pTarget ) )
|
||
|
return( (DWORD)AFPERR_UnsupportedFS );
|
||
|
|
||
|
|
||
|
//
|
||
|
// Impersonate the client while we read/write the fork data
|
||
|
//
|
||
|
dwRetCode = RpcImpersonateClient( NULL );
|
||
|
if ( dwRetCode != RPC_S_OK )
|
||
|
{
|
||
|
return(I_RpcMapWin32Status( dwRetCode ));
|
||
|
}
|
||
|
|
||
|
// open the data source file if one was specified
|
||
|
//
|
||
|
if ( STRLEN( pData ) > 0 ){
|
||
|
hDataSrc = CreateFile(pData, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
|
||
|
if (hDataSrc == INVALID_HANDLE_VALUE) {
|
||
|
RpcRevertToSelf();
|
||
|
return( GetLastError() );
|
||
|
}
|
||
|
|
||
|
|
||
|
// open the target file's data stream if the file exists,
|
||
|
// otherwise create the file
|
||
|
//
|
||
|
hTarget = CreateFile(pTarget, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||
|
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
|
||
|
if (hTarget == INVALID_HANDLE_VALUE) {
|
||
|
dwRetCode = GetLastError();
|
||
|
CloseHandle(hDataSrc);
|
||
|
RpcRevertToSelf();
|
||
|
return( dwRetCode );
|
||
|
}
|
||
|
|
||
|
// Figure out if we just created a new file
|
||
|
if (GetLastError() == 0)
|
||
|
{
|
||
|
fCreatedFile = TRUE;
|
||
|
}
|
||
|
|
||
|
SetFilePointer(hTarget,0,NULL,FILE_BEGIN);
|
||
|
SetEndOfFile(hTarget);
|
||
|
|
||
|
// Read the source data and write it to target data stream
|
||
|
//
|
||
|
SetLastError(NO_ERROR);
|
||
|
dwRetCode = CopyStream(hDataSrc, hTarget);
|
||
|
|
||
|
CloseHandle(hDataSrc);
|
||
|
CloseHandle(hTarget);
|
||
|
|
||
|
if (dwRetCode != NO_ERROR) {
|
||
|
RpcRevertToSelf();
|
||
|
return( dwRetCode );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// open the resource source file if one was specified
|
||
|
//
|
||
|
if ( STRLEN( pResource ) > 0 ) {
|
||
|
|
||
|
hResourceSrc = CreateFile( pResource, GENERIC_READ, FILE_SHARE_READ,
|
||
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL);
|
||
|
|
||
|
if (hResourceSrc == INVALID_HANDLE_VALUE) {
|
||
|
RpcRevertToSelf();
|
||
|
return( GetLastError() );
|
||
|
}
|
||
|
|
||
|
lpwsResourceFork = LocalAlloc( LPTR,
|
||
|
(STRLEN(pTarget)+
|
||
|
STRLEN(AFP_RESC_STREAM)+1)
|
||
|
* sizeof( WCHAR ) );
|
||
|
|
||
|
if ( lpwsResourceFork == NULL ) {
|
||
|
CloseHandle(hResourceSrc);
|
||
|
RpcRevertToSelf();
|
||
|
return( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
}
|
||
|
|
||
|
// Open the target resource fork
|
||
|
//
|
||
|
STRCPY(lpwsResourceFork, pTarget );
|
||
|
STRCAT(lpwsResourceFork, AFP_RESC_STREAM);
|
||
|
|
||
|
hTarget = CreateFile(lpwsResourceFork, GENERIC_WRITE, FILE_SHARE_READ,
|
||
|
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
|
||
|
if (hTarget == INVALID_HANDLE_VALUE) {
|
||
|
dwRetCode = GetLastError();
|
||
|
LocalFree( lpwsResourceFork );
|
||
|
CloseHandle(hResourceSrc);
|
||
|
RpcRevertToSelf();
|
||
|
return( dwRetCode );
|
||
|
}
|
||
|
|
||
|
LocalFree( lpwsResourceFork );
|
||
|
|
||
|
// Assume we created a new file (datafork) in the process, there is
|
||
|
// no way to tell for sure since creating a new resource fork will
|
||
|
// not tell us whether or not the datafork already existed or not
|
||
|
fCreatedFile = TRUE;
|
||
|
|
||
|
// Read the source resource and write it to target resource stream
|
||
|
//
|
||
|
SetLastError(NO_ERROR);
|
||
|
dwRetCode = CopyStream(hResourceSrc, hTarget);
|
||
|
|
||
|
CloseHandle(hResourceSrc);
|
||
|
CloseHandle(hTarget);
|
||
|
|
||
|
if (dwRetCode != NO_ERROR) {
|
||
|
RpcRevertToSelf();
|
||
|
return( dwRetCode );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Revert back to LocalSystem context
|
||
|
//
|
||
|
RpcRevertToSelf();
|
||
|
|
||
|
if ( dwParmNum & ( AFP_FD_PARMNUM_TYPE | AFP_FD_PARMNUM_CREATOR ) ){
|
||
|
|
||
|
dwRetCode = NO_ERROR;
|
||
|
|
||
|
AfpFinderInfo.afpfd_path = pTarget;
|
||
|
|
||
|
if ( dwParmNum & AFP_FD_PARMNUM_TYPE )
|
||
|
STRCPY( AfpFinderInfo.afpfd_type, pType );
|
||
|
else
|
||
|
AfpFinderInfo.afpfd_type[0] = TEXT( '\0' );
|
||
|
|
||
|
if ( dwParmNum & AFP_FD_PARMNUM_CREATOR )
|
||
|
STRCPY( AfpFinderInfo.afpfd_creator, pCreator );
|
||
|
else
|
||
|
AfpFinderInfo.afpfd_creator[0] = TEXT( '\0' );
|
||
|
|
||
|
// Make this buffer self-relative.
|
||
|
//
|
||
|
if ( dwRetCode = AfpBufMakeFSDRequest((LPBYTE)&AfpFinderInfo,
|
||
|
sizeof(SETINFOREQPKT),
|
||
|
AFP_FINDER_STRUCT,
|
||
|
&pAfpFinderInfoSR,
|
||
|
&cbAfpFinderInfoSRSize ))
|
||
|
return( dwRetCode );
|
||
|
|
||
|
// Make IOCTL to set info
|
||
|
//
|
||
|
AfpSrp.dwRequestCode = OP_FINDER_SET;
|
||
|
AfpSrp.dwApiType = AFP_API_TYPE_SETINFO;
|
||
|
AfpSrp.Type.SetInfo.pInputBuf = pAfpFinderInfoSR;
|
||
|
AfpSrp.Type.SetInfo.cbInputBufSize = cbAfpFinderInfoSRSize;
|
||
|
AfpSrp.Type.SetInfo.dwParmNum = dwParmNum;
|
||
|
|
||
|
|
||
|
// Since there will be a delay between the time the change
|
||
|
// notify comes into the server for the new file, and the
|
||
|
// time it is actually processed by the server, we need to
|
||
|
// put in a delay and retry to give the server a chance to
|
||
|
// cache the new file
|
||
|
if (fCreatedFile)
|
||
|
{
|
||
|
Sleep( 2000 );
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
|
||
|
dwRetCode = AfpServerIOCtrl( &AfpSrp );
|
||
|
|
||
|
if (dwRetCode != ERROR_PATH_NOT_FOUND)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Sleep( 2000);
|
||
|
|
||
|
} while ( ++dwRetryCount < 4 );
|
||
|
|
||
|
LocalFree( pAfpFinderInfoSR );
|
||
|
|
||
|
}
|
||
|
|
||
|
return( dwRetCode );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
CopyStream(
|
||
|
IN HANDLE hSrc,
|
||
|
IN HANDLE hDst
|
||
|
)
|
||
|
{
|
||
|
DWORD bytesread, byteswritten, Status = NO_ERROR;
|
||
|
BYTE Buffer[1024 * 16];
|
||
|
|
||
|
do
|
||
|
{
|
||
|
bytesread = byteswritten = 0;
|
||
|
|
||
|
// read from src, write to dst
|
||
|
//
|
||
|
if (ReadFile(hSrc, Buffer, sizeof(Buffer), &bytesread, NULL))
|
||
|
{
|
||
|
if (bytesread == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = GetLastError();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!WriteFile(hDst, Buffer, bytesread, &byteswritten, NULL))
|
||
|
{
|
||
|
Status = GetLastError();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} while (TRUE);
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsTargetNTFS(
|
||
|
IN LPWSTR lpwsPath
|
||
|
)
|
||
|
{
|
||
|
WCHAR wchDrive[5];
|
||
|
DWORD dwMaxCompSize;
|
||
|
DWORD dwFlags;
|
||
|
WCHAR wchFileSystem[10];
|
||
|
|
||
|
// Get the drive letter, : and backslash
|
||
|
//
|
||
|
ZeroMemory( wchDrive, sizeof( wchDrive ) );
|
||
|
|
||
|
STRNCPY( wchDrive, lpwsPath, 3 );
|
||
|
|
||
|
if ( !( GetVolumeInformation( (LPWSTR)wchDrive,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
&dwMaxCompSize,
|
||
|
&dwFlags,
|
||
|
(LPWSTR)wchFileSystem,
|
||
|
sizeof( wchFileSystem ) ) ) ){
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
if ( STRICMP( wchFileSystem, TEXT("NTFS") ) == 0 )
|
||
|
return( TRUE );
|
||
|
else
|
||
|
return( FALSE );
|
||
|
|
||
|
}
|