mirror of https://github.com/lianthony/NT4.0
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.
636 lines
17 KiB
636 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atapi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the worker routines for all APIs implemented
|
|
in the Schedule service.
|
|
|
|
Author:
|
|
|
|
Vladimir Z. Vulovic (vladimv) 06 - November - 1992
|
|
|
|
Revision History:
|
|
|
|
06-Nov-1992 vladimv
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include "at.h"
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrJobAdd(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN LPAT_INFO pAtInfo,
|
|
OUT LPDWORD pJobId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the NetJobAdd entry point in the Schedule service.
|
|
Given the info about a new job, its creates a new job and returns the
|
|
id of the new job.
|
|
|
|
Arguments:
|
|
|
|
ServerName - IGNORED
|
|
pAtInfo - pointer to information about the job to be added
|
|
pJobId - pointer to id of the newly added job
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
PAT_RECORD pRecord;
|
|
DWORD CommandLength;
|
|
DWORD CommandSize;
|
|
AT_TIME time;
|
|
|
|
|
|
UNREFERENCED_PARAMETER( ServerName);
|
|
|
|
status = AtCheckSecurity( AT_JOB_ADD);
|
|
if ( status != NERR_Success) {
|
|
return( ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
//
|
|
// Is it safe to calculate string length below?
|
|
// Should RPC supply string length parameter?
|
|
// Note that wcslen() returns length of UNICODE string in WCHAR-s.
|
|
// Thus storage needed for Command is (CommandLength+1)*sizeof(WCHAR)
|
|
//
|
|
CommandLength = wcslen( pAtInfo->Command);
|
|
|
|
if ( ( CommandLength > MAXIMUM_COMMAND_LENGTH) ||
|
|
( pAtInfo->JobTime > MAXIMUM_JOB_TIME) ||
|
|
( pAtInfo->DaysOfWeek & ~DAYS_OF_WEEK) != 0 ||
|
|
( pAtInfo->DaysOfMonth & ~DAYS_OF_MONTH) != 0 ||
|
|
( pAtInfo->Flags & ~JOB_INPUT_FLAGS) != 0 ) {
|
|
return( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
CommandSize = ( CommandLength + 1) * sizeof( WCHAR);
|
|
|
|
pRecord = (PAT_RECORD)LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof( AT_RECORD) + AT_KEY_NAME_SIZE + CommandSize
|
|
);
|
|
if ( pRecord == NULL) {
|
|
return( ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
pRecord->CommandSize = (WORD)CommandSize;
|
|
pRecord->NameSize = AT_KEY_NAME_SIZE; // max possible
|
|
|
|
pRecord->JobTime = pAtInfo->JobTime;
|
|
pRecord->JobDay = JOB_INVALID_DAY; // the default
|
|
#ifdef AT_DEBUG
|
|
pRecord->Debug = 0;
|
|
#endif // AT_DEBUG
|
|
|
|
pRecord->Name = (PWCHAR)( (PBYTE)pRecord + sizeof( AT_RECORD));
|
|
memset( pRecord->Name, 0, AT_KEY_NAME_SIZE);
|
|
|
|
pRecord->Command = (PWCHAR)( (PBYTE)&pRecord->Name[0] + AT_KEY_NAME_SIZE);
|
|
memcpy( pRecord->Command, pAtInfo->Command, CommandSize);
|
|
|
|
EnterCriticalSection( &AtGlobalCriticalSection);
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "++JobAdd: Command=%ws\n", pRecord->Command));
|
|
|
|
AtTimeGet( &time); // needed in what follows
|
|
|
|
if ( pAtInfo->Flags & JOB_ADD_CURRENT_DATE) {
|
|
pAtInfo->Flags &= ~JOB_ADD_CURRENT_DATE;
|
|
pAtInfo->DaysOfMonth |= 1 << ( time.CurrentDay - 1);
|
|
}
|
|
|
|
pRecord->Flags = pAtInfo->Flags;
|
|
pRecord->DaysOfMonth = pAtInfo->DaysOfMonth;
|
|
pRecord->DaysOfWeek = pAtInfo->DaysOfWeek;
|
|
|
|
//
|
|
// BUGBUG Should we have a more stringent test that makes sure
|
|
// BUGBUG that service state is SERVICE_RUNNING ?
|
|
//
|
|
if ( AtGlobalServiceStatus.dwCurrentState == SERVICE_PAUSED) {
|
|
//
|
|
// BUGBUG Error ERROR_SERVICE_PAUSED is not defined properly for now.
|
|
//
|
|
status = ERROR_SERVICE_PAUSED;
|
|
goto error_exit;
|
|
}
|
|
ASSERT( AtGlobalServiceStatus.dwCurrentState == SERVICE_RUNNING);
|
|
|
|
|
|
*pJobId = pRecord->JobId = AtGlobalJobId++;
|
|
|
|
status = AtCreateKey( pRecord);
|
|
if ( status != NERR_Success) {
|
|
LocalFree( pRecord);
|
|
goto error_exit;
|
|
}
|
|
|
|
AtCalculateRuntime( pRecord, &time);
|
|
AtInsertRecord( pRecord, BOTH_QUEUES);
|
|
|
|
error_exit:
|
|
AtLog(( AT_DEBUG_MAIN, "--JobAdd: Command=%ws status=%d JobId=%d\n",
|
|
pRecord->Command, status, pRecord->JobId));
|
|
LeaveCriticalSection( &AtGlobalCriticalSection);
|
|
SetEvent( AtGlobalEvent); // to calculate new timeout
|
|
return( status);
|
|
|
|
} // NetrJobAdd
|
|
|
|
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrJobDel(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN DWORD MinJobId,
|
|
IN DWORD MaxJobId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the NetJobDel entry point in the Schedule service.
|
|
Given the minimum and maximum job id, this routines deletes all jobs
|
|
whose job id is greater than or equal to the minimum job id and
|
|
less than or equal to the maximum job id.
|
|
|
|
Arguments:
|
|
|
|
ServerName - IGNORED
|
|
MinJobId - minimum job id
|
|
MaxJobId - maximum job id
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
PLIST_ENTRY pListEntry;
|
|
PAT_RECORD pRecord;
|
|
BOOL JobDeleted;
|
|
|
|
UNREFERENCED_PARAMETER(ServerName);
|
|
|
|
status = AtCheckSecurity( AT_JOB_DEL);
|
|
if ( status != NERR_Success) {
|
|
return( status);
|
|
}
|
|
|
|
if ( MinJobId > MaxJobId) {
|
|
return( ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
EnterCriticalSection( &AtGlobalCriticalSection);
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "++JobDel: MinJobId=%d MaxJobId=%d\n",
|
|
MinJobId, MaxJobId));
|
|
|
|
for ( JobDeleted = FALSE, pListEntry = AtGlobalJobIdListHead.Flink;
|
|
pListEntry != &AtGlobalJobIdListHead;
|
|
NOTHING) {
|
|
|
|
pRecord = CONTAINING_RECORD(
|
|
pListEntry,
|
|
AT_RECORD,
|
|
JobIdList
|
|
);
|
|
|
|
if ( pRecord->JobId > MaxJobId) {
|
|
break; // JobId is too larger, we are done
|
|
}
|
|
|
|
pListEntry = pListEntry->Flink; // actual iteration statement
|
|
|
|
if ( pRecord->JobId < MinJobId) {
|
|
continue; // JobId is too small, look further
|
|
}
|
|
|
|
JobDeleted = TRUE;
|
|
|
|
AtDeleteKey( pRecord);
|
|
AtRemoveRecord( pRecord, BOTH_QUEUES);
|
|
(VOID)LocalFree( pRecord);
|
|
}
|
|
|
|
status = JobDeleted == TRUE ? NERR_Success : APE_AT_ID_NOT_FOUND;
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "--JobDel: MinJobId=%d MaxJobId=%d status=%d\n",
|
|
MinJobId, MaxJobId, status));
|
|
|
|
LeaveCriticalSection( &AtGlobalCriticalSection);
|
|
SetEvent( AtGlobalEvent); // to calculate new timeout
|
|
return( status);
|
|
|
|
} // NetrJobDelete
|
|
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrJobEnum(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN OUT LPAT_ENUM_CONTAINER pEnumContainer,
|
|
IN DWORD PreferredMaximumLength,
|
|
OUT LPDWORD TotalEntries,
|
|
IN OUT LPDWORD ResumeHandle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the NetJobEnum entry point in the Schedule service.
|
|
It returns information about jobs starting with a job id given by
|
|
resume handle, or if resume handle is absent, starting with a job
|
|
with the lowest job id.
|
|
|
|
Arguments:
|
|
|
|
ServerName - IGNORED
|
|
|
|
pEnumContainer - pointer to enumeration container which contains the
|
|
array of job information structures and size of that array.
|
|
|
|
PreferedMaximumLength - Supplies the number of bytes of information
|
|
to return in the buffer. If this value is MAXULONG, all available
|
|
information will be returned.
|
|
|
|
TotalEntries - Returns the total number of entries available. This value
|
|
is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
|
|
|
|
ResumeHandle - Supplies a handle to resume the enumeration from where it
|
|
left off the last time through. Returns the resume handle if return
|
|
code is ERROR_MORE_DATA.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
DWORD JobId; // resume job id
|
|
DWORD JobCount;
|
|
DWORD BufferSize;
|
|
PLIST_ENTRY pListEntry;
|
|
PAT_RECORD pRecord;
|
|
LPBYTE Buffer;
|
|
LPAT_ENUM pAtEnum;
|
|
LPBYTE StringBuffer;
|
|
DWORD EntriesRead;
|
|
BOOL success;
|
|
AT_TIME time;
|
|
|
|
UNREFERENCED_PARAMETER(ServerName);
|
|
|
|
status = AtCheckSecurity( AT_JOB_ENUM);
|
|
if ( status != NERR_Success) {
|
|
return( ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
JobId = (ARGUMENT_PRESENT( ResumeHandle)) ? *ResumeHandle : 0;
|
|
Buffer = NULL;
|
|
EntriesRead = 0;
|
|
|
|
|
|
EnterCriticalSection( &AtGlobalCriticalSection);
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "++JobEnum: JobId=%d\n", JobId));
|
|
|
|
AtTimeGet( &time); // needed in what follows
|
|
|
|
for ( JobCount = 0, BufferSize = 0,
|
|
pListEntry = AtGlobalJobIdListHead.Blink;
|
|
pListEntry != &AtGlobalJobIdListHead;
|
|
JobCount++, BufferSize += pRecord->CommandSize,
|
|
pListEntry = pListEntry->Blink) {
|
|
|
|
pRecord = CONTAINING_RECORD(
|
|
pListEntry,
|
|
AT_RECORD,
|
|
JobIdList
|
|
);
|
|
|
|
if ( pRecord->JobId < JobId) {
|
|
break; // reached first stale record
|
|
}
|
|
}
|
|
|
|
|
|
*TotalEntries = JobCount;
|
|
|
|
if ( JobCount == 0) {
|
|
goto error_exit;
|
|
}
|
|
|
|
if ( PreferredMaximumLength == -1) {
|
|
//
|
|
// If the caller has not specified a size, calculate a size
|
|
// that will hold the entire enumeration.
|
|
//
|
|
BufferSize += JobCount * sizeof( AT_ENUM);
|
|
|
|
} else {
|
|
BufferSize = PreferredMaximumLength;
|
|
}
|
|
|
|
Buffer = (LPBYTE)MIDL_user_allocate( BufferSize);
|
|
if ( Buffer == NULL) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// When we arrive here "pListEntry" points either to the head of the
|
|
// list (if we enumerate from the beginning) or to the first stale
|
|
// record.
|
|
//
|
|
for ( pListEntry = pListEntry->Flink, pAtEnum = (PAT_ENUM)Buffer,
|
|
StringBuffer = Buffer + BufferSize;
|
|
pListEntry != &AtGlobalJobIdListHead;
|
|
pListEntry = pListEntry->Flink, pAtEnum++,
|
|
EntriesRead++) {
|
|
|
|
pRecord = CONTAINING_RECORD(
|
|
pListEntry,
|
|
AT_RECORD,
|
|
JobIdList
|
|
);
|
|
|
|
if ( StringBuffer <= (LPBYTE)pAtEnum + sizeof( AT_ENUM)) {
|
|
status = ERROR_MORE_DATA;
|
|
break; // the buffer is full
|
|
}
|
|
|
|
pAtEnum->JobId = pRecord->JobId;
|
|
pAtEnum->JobTime = pRecord->JobTime;
|
|
pAtEnum->DaysOfMonth = pRecord->DaysOfMonth;
|
|
pAtEnum->DaysOfWeek = pRecord->DaysOfWeek;
|
|
pAtEnum->Flags = pRecord->Flags;
|
|
|
|
if ( time.CurrentTime < pRecord->JobTime) {
|
|
pAtEnum->Flags |= JOB_RUNS_TODAY;
|
|
}
|
|
|
|
success = NetpCopyStringToBuffer(
|
|
pRecord->Command,
|
|
pRecord->CommandSize / sizeof( WCHAR) - 1,
|
|
(LPBYTE)(pAtEnum+1),
|
|
(LPWSTR *)&StringBuffer,
|
|
&pAtEnum->Command
|
|
);
|
|
|
|
if ( success == FALSE) {
|
|
status = ERROR_MORE_DATA;
|
|
KdPrint(( "[Job] NetrJobEnum: Not enough room\n"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( status == ERROR_MORE_DATA) {
|
|
JobId = pRecord->JobId; // JobId of first one we have not read
|
|
} else {
|
|
JobId = 0; // we have read everything, reset resume handle
|
|
}
|
|
|
|
error_exit:
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "--JobEnum: JobId=%d\n", JobId));
|
|
LeaveCriticalSection( &AtGlobalCriticalSection);
|
|
SetEvent( AtGlobalEvent); // to calculate new timeout
|
|
|
|
pEnumContainer->EntriesRead = EntriesRead;
|
|
|
|
if ( EntriesRead == 0 && Buffer != NULL) {
|
|
|
|
MIDL_user_free( Buffer);
|
|
Buffer = NULL;
|
|
|
|
}
|
|
|
|
pEnumContainer->Buffer = (LPAT_ENUM)Buffer;
|
|
|
|
if ( ARGUMENT_PRESENT( ResumeHandle)) {
|
|
*ResumeHandle = JobId;
|
|
}
|
|
|
|
return( status);
|
|
|
|
} // NetrJobEnum
|
|
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrJobGetInfo(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN DWORD JobId,
|
|
OUT LPAT_INFO * ppAtInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the NetJobGetInfo entry point in the Schedule service.
|
|
It returns information about a job corresponding to the supplied job id.
|
|
|
|
Arguments:
|
|
|
|
ServerName - IGNORED
|
|
JobId - job id of a job we are interested in
|
|
ppAtInfo - pointer to pointer to data about the job in question
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
PAT_RECORD pRecord;
|
|
PLIST_ENTRY pListEntry;
|
|
LPAT_INFO pAtInfo;
|
|
AT_TIME time;
|
|
|
|
UNREFERENCED_PARAMETER(ServerName);
|
|
|
|
#ifdef AT_DEBUG
|
|
if ( JobId == 70503010) {
|
|
DbgUserBreakPoint();
|
|
}
|
|
#endif // AT_DEBUG
|
|
|
|
status = AtCheckSecurity( AT_JOB_GET_INFO);
|
|
if ( status != NERR_Success) {
|
|
return( ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
pAtInfo = NULL;
|
|
|
|
EnterCriticalSection( &AtGlobalCriticalSection);
|
|
AtLog(( AT_DEBUG_MAIN, "++JobGetInfo: JobId=%d\n", JobId));
|
|
|
|
AtTimeGet( &time); // needed in what follows
|
|
|
|
for ( pListEntry = AtGlobalJobIdListHead.Flink;
|
|
pListEntry != &AtGlobalJobIdListHead;
|
|
pListEntry = pListEntry->Flink) {
|
|
|
|
pRecord = CONTAINING_RECORD(
|
|
pListEntry,
|
|
AT_RECORD,
|
|
JobIdList
|
|
);
|
|
|
|
if ( pRecord->JobId == JobId) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pListEntry == &AtGlobalJobIdListHead) {
|
|
status = APE_AT_ID_NOT_FOUND;
|
|
goto error_exit;
|
|
}
|
|
|
|
pAtInfo = (PAT_INFO)MIDL_user_allocate(
|
|
sizeof( AT_INFO) + pRecord->CommandSize
|
|
);
|
|
if ( pAtInfo == NULL) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error_exit;
|
|
}
|
|
|
|
pAtInfo->JobTime = pRecord->JobTime;
|
|
pAtInfo->DaysOfMonth = pRecord->DaysOfMonth;
|
|
pAtInfo->DaysOfWeek = pRecord->DaysOfWeek;
|
|
pAtInfo->Flags = pRecord->Flags;
|
|
|
|
if ( time.CurrentTime < pRecord->JobTime) {
|
|
pAtInfo->Flags |= JOB_RUNS_TODAY;
|
|
}
|
|
|
|
pAtInfo->Command = (LPWSTR)( pAtInfo + 1);
|
|
|
|
memcpy( pAtInfo->Command, pRecord->Command, pRecord->CommandSize);
|
|
|
|
error_exit:
|
|
|
|
AtLog(( AT_DEBUG_MAIN, "--JobGetInfo: JobId=%d\n", JobId));
|
|
LeaveCriticalSection( &AtGlobalCriticalSection);
|
|
SetEvent( AtGlobalEvent); // to calculate new timeout
|
|
|
|
*ppAtInfo = pAtInfo;
|
|
|
|
return( status);
|
|
|
|
} // NetrJobGetInfo
|
|
|
|
|
|
#ifdef NOT_YET
|
|
|
|
|
|
NET_API_STATUS NET_API_FUNCTION
|
|
NetrJobControl(
|
|
IN LPCWSTR ServerName OPTIONAL,
|
|
IN OUT LPJOB_CONTROL_INFO ControlInfo,
|
|
IN DWORD Opcode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the NetJobControl entry point in the Schedule service.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
Comments:
|
|
|
|
BUGBUG JobControl contains old stuff - need to clean it up & make it work.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS status;
|
|
|
|
UNREFERENCED_PARAMETER(ServerName);
|
|
|
|
status = AtCheckSecurity( AT_JOB_CONTROL);
|
|
if ( status != NERR_Success) {
|
|
return( ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
EnterCriticalSection( &AtGlobalCriticalSection);
|
|
|
|
switch ( opcode) {
|
|
case ENABLE:
|
|
case DISABLE:
|
|
break;
|
|
default:
|
|
status = ERROR_INVALID_REQUEST;
|
|
goto error_exit;
|
|
}
|
|
|
|
pJob = FindExactJob( pDelRequest);
|
|
if ( pJob == NULL) {
|
|
status = ERROR_JOB_NOT_FOUND;
|
|
goto error_exit;
|
|
}
|
|
|
|
if ( opcode == pJob->State) { // case of stupid request
|
|
status = STATUS_SUCCESS;
|
|
goto error_exit;
|
|
}
|
|
|
|
pJob->State = opcode;
|
|
DeleteJob( pJob);
|
|
|
|
switch( opcode) {
|
|
case ENABLED:
|
|
// Evaluate the next run time and queue the job near the front
|
|
// of the list where all enabled jobs reside.
|
|
break;
|
|
case DISABLED:
|
|
// Optionally set next run time to infinity, then queue the job
|
|
// near the back of the list where all the disabled jobs reside.
|
|
break;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
// Queue a job delete request to a registry queue.
|
|
|
|
|
|
error_exit:
|
|
|
|
LeaveCriticalSection( &AtGlobalCriticalSection);
|
|
SetEvent( AtGlobalEvent); // to calculate new timeout
|
|
return( status);
|
|
|
|
} // NetrJobControl
|
|
|
|
#endif // NOT_YET
|
|
|
|
|