579 lines
14 KiB
C
579 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
svcfile.c
|
||
|
||
Abstract:
|
||
|
||
This module contains routines for supporting the file APIs in the
|
||
server service, SrvNetFileClose, SrvNetFileEnum, and
|
||
SrvNetFileGetInfo,
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 31-Jan-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#include "svcfile.tmh"
|
||
#pragma hdrstop
|
||
|
||
#define BugCheckFileId SRV_FILE_SVCFILE
|
||
|
||
//
|
||
// Forward declarations.
|
||
//
|
||
|
||
VOID
|
||
FillFileInfoBuffer (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block,
|
||
IN OUT PVOID *FixedStructure,
|
||
IN LPWSTR *EndOfVariableData
|
||
);
|
||
|
||
BOOLEAN
|
||
FilterFiles (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block
|
||
);
|
||
|
||
ULONG
|
||
SizeFiles (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, SrvNetFileClose )
|
||
#pragma alloc_text( PAGE, SrvNetFileEnum )
|
||
#pragma alloc_text( PAGE, FillFileInfoBuffer )
|
||
#pragma alloc_text( PAGE, FilterFiles )
|
||
#pragma alloc_text( PAGE, SizeFiles )
|
||
#endif
|
||
|
||
//
|
||
// Macros to determine the size an RFCB would take up at one of the
|
||
// levels of file information.
|
||
//
|
||
// *** Note that the zero terminator on the path name is accounted for by
|
||
// the leading backslash, which is not returned.
|
||
//
|
||
|
||
#define TOTAL_SIZE_OF_FILE(lfcb,level, user) \
|
||
( (level) == 2 ? sizeof(FILE_INFO_2) : \
|
||
sizeof(FILE_INFO_3) + \
|
||
SrvLengthOfStringInApiBuffer( \
|
||
&(lfcb)->Mfcb->FileName) + \
|
||
SrvLengthOfStringInApiBuffer( user ) )
|
||
|
||
#define FIXED_SIZE_OF_FILE(level) \
|
||
( (level) == 2 ? sizeof(FILE_INFO_2) : \
|
||
sizeof(FILE_INFO_3) )
|
||
|
||
NTSTATUS
|
||
SrvNetFileClose (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes the NetFileClose API in the server.
|
||
|
||
Arguments:
|
||
|
||
Srp - a pointer to the server request packet that contains all
|
||
the information necessary to satisfy the request. This includes:
|
||
|
||
INPUT:
|
||
|
||
Parameters.Get.ResumeHandle - the file ID to close.
|
||
|
||
OUTPUT:
|
||
|
||
None.
|
||
|
||
Buffer - unused.
|
||
|
||
BufferLength - unused.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation to return to the server service.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRFCB rfcb;
|
||
|
||
PAGED_CODE( );
|
||
|
||
Buffer, BufferLength;
|
||
|
||
//
|
||
// Try to find a file that matches the file ID. Only an exact
|
||
// match will work.
|
||
//
|
||
|
||
rfcb = SrvFindEntryInOrderedList(
|
||
&SrvRfcbList,
|
||
NULL,
|
||
NULL,
|
||
Srp->Parameters.Get.ResumeHandle,
|
||
TRUE,
|
||
NULL
|
||
);
|
||
|
||
if ( rfcb == NULL ) {
|
||
Srp->ErrorCode = NERR_FileIdNotFound;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Close this RFCB.
|
||
//
|
||
|
||
SrvCloseRfcb( rfcb );
|
||
|
||
//
|
||
// SrvFindEntryInOrderedList referenced the RFCB; dereference it
|
||
// now.
|
||
//
|
||
|
||
SrvDereferenceRfcb( rfcb );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // SrvNetFileClose
|
||
|
||
|
||
NTSTATUS
|
||
SrvNetFileEnum (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes the NetFileEnum API in the server.
|
||
|
||
Arguments:
|
||
|
||
Srp - a pointer to the server request packet that contains all
|
||
the information necessary to satisfy the request. This includes:
|
||
|
||
INPUT:
|
||
|
||
Name1 - basename for limiting search--only files whose path name
|
||
begin with this string are returned.
|
||
|
||
Level - level of information to return, 2 or 3.
|
||
|
||
Flags - if SRP_RETURN_SINGLE_ENTRY is set, then this is a
|
||
NetFileGetInfo, so behave accordingly.
|
||
|
||
Parameters.Get.ResumeHandle - a handle to the last file that was
|
||
returned, or 0 if this is the first call.
|
||
|
||
OUTPUT:
|
||
|
||
Parameters.Get.EntriesRead - the number of entries that fit in
|
||
the output buffer.
|
||
|
||
Parameters.Get.TotalEntries - the total number of entries that
|
||
would be returned with a large enough buffer.
|
||
|
||
Parameters.Get.TotalBytesNeeded - the buffer size that would be
|
||
required to hold all the entries.
|
||
|
||
Parameters.Get.ResumeHandle - a handle to the last file
|
||
returned.
|
||
|
||
Buffer - a pointer to the buffer for results.
|
||
|
||
BufferLength - the length of this buffer.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation to return to the server service.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// If this is a GetInfo API, we really want to start with the file
|
||
// corresponding to the resume handle, not the one after it.
|
||
// Decrement the resume handle.
|
||
//
|
||
|
||
if ( (Srp->Flags & SRP_RETURN_SINGLE_ENTRY) != 0 ) {
|
||
Srp->Parameters.Get.ResumeHandle--;
|
||
}
|
||
|
||
return SrvEnumApiHandler(
|
||
Srp,
|
||
Buffer,
|
||
BufferLength,
|
||
&SrvRfcbList,
|
||
FilterFiles,
|
||
SizeFiles,
|
||
FillFileInfoBuffer
|
||
);
|
||
|
||
} // SrvNetFileEnum
|
||
|
||
|
||
VOID
|
||
FillFileInfoBuffer (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block,
|
||
IN OUT PVOID *FixedStructure,
|
||
IN LPWSTR *EndOfVariableData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine puts a single fixed file structure and associated
|
||
variable data, into a buffer. Fixed data goes at the beginning of
|
||
the buffer, variable data at the end.
|
||
|
||
*** This routine assumes that ALL the data, both fixed and variable,
|
||
will fit.
|
||
|
||
Arguments:
|
||
|
||
Srp - a pointer to the SRP for the operation. Only the Level
|
||
field is used.
|
||
|
||
Block - the RFCB from which to get information.
|
||
|
||
FixedStructure - where the ine buffer to place the fixed structure.
|
||
This pointer is updated to point to the next available
|
||
position for a fixed structure.
|
||
|
||
EndOfVariableData - the last position on the buffer that variable
|
||
data for this structure can occupy. The actual variable data
|
||
is written before this position as long as it won't overwrite
|
||
fixed structures. It is would overwrite fixed structures, it
|
||
is not written.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFILE_INFO_3 fi3 = *FixedStructure;
|
||
PRFCB rfcb;
|
||
PLFCB lfcb;
|
||
UNICODE_STRING userName;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Update FixedStructure to point to the next structure location.
|
||
//
|
||
|
||
*FixedStructure = (PCHAR)*FixedStructure + FIXED_SIZE_OF_FILE( Srp->Level );
|
||
ASSERT( (ULONG_PTR)*EndOfVariableData >= (ULONG_PTR)*FixedStructure );
|
||
|
||
rfcb = Block;
|
||
lfcb = rfcb->Lfcb;
|
||
|
||
//
|
||
// Case on the level to fill in the fixed structure appropriately.
|
||
// We fill in actual pointers in the output structure. This is
|
||
// possible because we are in the server FSD, hence the server
|
||
// service's process and address space.
|
||
//
|
||
// *** Using the switch statement in this fashion relies on the fact
|
||
// that the first fields on the different file structures are
|
||
// identical.
|
||
//
|
||
|
||
switch( Srp->Level ) {
|
||
|
||
case 3:
|
||
|
||
//
|
||
// Set level 3 specific fields in the buffer. Convert the
|
||
// permissions (granted access) stored in the LFCB to the format
|
||
// expected by the API.
|
||
//
|
||
|
||
fi3->fi3_permissions = 0;
|
||
|
||
if ( (lfcb->GrantedAccess & FILE_READ_DATA) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_READ;
|
||
}
|
||
|
||
if ( (lfcb->GrantedAccess & FILE_WRITE_DATA) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_WRITE;
|
||
}
|
||
|
||
if ( (lfcb->GrantedAccess & FILE_EXECUTE) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_EXEC;
|
||
}
|
||
|
||
if ( (lfcb->GrantedAccess & DELETE) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_DELETE;
|
||
}
|
||
|
||
if ( (lfcb->GrantedAccess & FILE_WRITE_ATTRIBUTES) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_ATRIB;
|
||
}
|
||
|
||
if ( (lfcb->GrantedAccess & WRITE_DAC) != 0 ) {
|
||
fi3->fi3_permissions |= ACCESS_PERM;
|
||
}
|
||
|
||
//
|
||
// Set count of locks on the RFCB.
|
||
//
|
||
|
||
fi3->fi3_num_locks = rfcb->NumberOfLocks;
|
||
|
||
//
|
||
// Set up the pathname and username of the RFCB. Note that we
|
||
// don't return the leading backslash on file names.
|
||
//
|
||
|
||
SrvCopyUnicodeStringToBuffer(
|
||
&lfcb->Mfcb->FileName,
|
||
*FixedStructure,
|
||
EndOfVariableData,
|
||
&fi3->fi3_pathname
|
||
);
|
||
|
||
ASSERT( fi3->fi3_pathname != NULL );
|
||
|
||
SrvGetUserAndDomainName( lfcb->Session, &userName, NULL );
|
||
|
||
SrvCopyUnicodeStringToBuffer(
|
||
&userName,
|
||
*FixedStructure,
|
||
EndOfVariableData,
|
||
&fi3->fi3_username
|
||
);
|
||
|
||
if( userName.Buffer ) {
|
||
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
||
}
|
||
|
||
//ASSERT( fi3->fi3_username != NULL );
|
||
|
||
// *** Lack of break is intentional!
|
||
|
||
case 2:
|
||
|
||
//
|
||
// Set up the file ID. Note that it is the same value as is
|
||
// used for the resume handle, so it is possible to use this
|
||
// value for rewindability.
|
||
//
|
||
|
||
fi3->fi3_id = rfcb->GlobalRfcbListEntry.ResumeHandle;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// This should never happen. The server service should have
|
||
// checked for an invalid level.
|
||
//
|
||
|
||
INTERNAL_ERROR(
|
||
ERROR_LEVEL_UNEXPECTED,
|
||
"FillFileInfoBuffer: invalid level number: %ld",
|
||
Srp->Level,
|
||
NULL
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
return;
|
||
|
||
} // FillFileInfoBuffer
|
||
|
||
|
||
BOOLEAN
|
||
FilterFiles (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is intended to be called by SrvEnumApiHandler to check
|
||
whether a particular RFCB should be returned.
|
||
|
||
Arguments:
|
||
|
||
Srp - a pointer to the SRP for the operation. ResumeHandle is
|
||
used if this is a NetFileGetInfo; Name1 is used as the path
|
||
name and Name2 is used as the user name if this is a
|
||
NetFileEnum.
|
||
|
||
Block - a pointer to the RFCB to check.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the block should be placed in the output buffer, FALSE
|
||
if it should be passed over.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRFCB rfcb = Block;
|
||
PLFCB lfcb = rfcb->Lfcb;
|
||
PMFCB mfcb = lfcb->Mfcb;
|
||
UNICODE_STRING pathName;
|
||
UNICODE_STRING userName;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Check if this is an Enum or GetInfo command. The SRP_RETURN_SINGLE_ENTRY
|
||
// flag is set if this is a get info.
|
||
//
|
||
|
||
if ( (Srp->Flags & SRP_RETURN_SINGLE_ENTRY) == 0 ) {
|
||
|
||
//
|
||
// If a user name was specified, the user name on the session
|
||
// must match the user name in the SRP exactly.
|
||
//
|
||
|
||
if ( Srp->Name2.Length != 0 ) {
|
||
|
||
//
|
||
// Get the user name for the owning session
|
||
//
|
||
SrvGetUserAndDomainName( lfcb->Session, &userName, NULL );
|
||
|
||
if( userName.Buffer == NULL ) {
|
||
//
|
||
// Since we don't know who owns the session, we can't match
|
||
// the username
|
||
//
|
||
return FALSE;
|
||
}
|
||
|
||
if ( !RtlEqualUnicodeString(
|
||
&Srp->Name2,
|
||
&userName,
|
||
TRUE ) ) {
|
||
|
||
//
|
||
// The names don't match. Don't put this RFCB in the
|
||
// output buffer.
|
||
//
|
||
|
||
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
||
return FALSE;
|
||
}
|
||
|
||
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
||
}
|
||
|
||
//
|
||
// See if the names match to as many digits of precision as are in
|
||
// the specified base name. Note that if no base name was
|
||
// specified, then the length = 0 and the file path will always
|
||
// match. Also note that the path name stored in the MFCB has a
|
||
// leading backslash, while the passed-in path name will never have
|
||
// this leading slash, hence the increment of the MFCB file name
|
||
// buffer.
|
||
//
|
||
|
||
pathName.Buffer = mfcb->FileName.Buffer;
|
||
pathName.Length =
|
||
MIN( Srp->Name1.Length, mfcb->FileName.Length );
|
||
pathName.MaximumLength = mfcb->FileName.MaximumLength;
|
||
|
||
return RtlEqualUnicodeString(
|
||
&Srp->Name1,
|
||
&pathName,
|
||
TRUE
|
||
);
|
||
}
|
||
|
||
//
|
||
// It's a GetInfo, so just see if the ResumeHandle in the SRP
|
||
// matches the ResumeHandle on the RFCB. We increment the value in
|
||
// the SRP because it was decremented before calling
|
||
// SrvEnumApiHandler.
|
||
//
|
||
|
||
return (BOOLEAN)( Srp->Parameters.Get.ResumeHandle + 1==
|
||
SrvGetResumeHandle( &SrvRfcbList, rfcb ) );
|
||
|
||
} // FilterFiles
|
||
|
||
|
||
ULONG
|
||
SizeFiles (
|
||
IN PSERVER_REQUEST_PACKET Srp,
|
||
IN PVOID Block
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the size the passed-in RFCB would take up
|
||
in an API output buffer.
|
||
|
||
Arguments:
|
||
|
||
Srp - a pointer to the SRP for the operation. Only the level
|
||
parameter is used.
|
||
|
||
Block - a pointer to the RFCB to size.
|
||
|
||
Return Value:
|
||
|
||
ULONG - The number of bytes the file would take up in the output
|
||
buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRFCB rfcb = Block;
|
||
UNICODE_STRING userName;
|
||
ULONG size;
|
||
|
||
PAGED_CODE( );
|
||
|
||
SrvGetUserAndDomainName( rfcb->Lfcb->Session, &userName, NULL );
|
||
|
||
size = TOTAL_SIZE_OF_FILE( rfcb->Lfcb, Srp->Level, &userName );
|
||
|
||
SrvReleaseUserAndDomainName( rfcb->Lfcb->Session, &userName, NULL );
|
||
|
||
return size;
|
||
|
||
} // SizeFiles
|