Leaked source code of windows server 2003
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.
 
 
 
 
 
 

644 lines
18 KiB

//+----------------------------------------------------------------------------
//
// Job Scheduler service
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: sch_util.cxx
//
// Contents: scheduler object IUnknown methods, class factory,
// plus misc private class methods
//
// Classes: CSchedule, CScheduleCF
//
// Interfaces: IUnknown, IClassFactory
//
// History: 09-Sep-95 EricB created
//
//-----------------------------------------------------------------------------
#include "..\pch\headers.hxx"
#pragma hdrstop
#include "Sched.hxx"
//+----------------------------------------------------------------------------
//
// Member: CSchedule::ActivateJob, private
//
// Synopsis: Given a valid name, returns a pointer to the activated job
// object
//
// Arguments: [pwszName] - the folder-relative name of the job to activate
// [ppJob] - a pointer to the job class object; on entry,
// must either be NULL or point to a CJob object.
// [fAllData] - load all job data from disk.
//
// Returns: hresults
//
//-----------------------------------------------------------------------------
HRESULT
CSchedule::ActivateJob(LPCTSTR ptszName, CJob ** ppJob, BOOL fAllData)
{
TCHAR tszFullName[MAX_PATH + MAX_PATH];
HRESULT hr = StringCchCopy(tszFullName, MAX_PATH + MAX_PATH, g_TasksFolderInfo.ptszPath);
if (FAILED(hr))
{
schDebugOut((DEB_ERROR, "CSchedule::ActivateJob: StringCchCopy failed with error 0x%x\n", hr));
return hr;
}
hr = StringCchCat(tszFullName, MAX_PATH + MAX_PATH, TEXT("\\"));
if (FAILED(hr))
{
schDebugOut((DEB_ERROR, "CSchedule::ActivateJob: StringCchCat failed with error 0x%x\n", hr));
return hr;
}
hr = StringCchCat(tszFullName, MAX_PATH + MAX_PATH, ptszName);
if (FAILED(hr))
{
schDebugOut((DEB_ERROR, "CSchedule::ActivateJob: StringCchCat failed with error 0x%x\n", hr));
return hr;
}
//
// If *ppJob is NULL, allocate a new job object.
//
if (*ppJob == NULL)
{
//
// CJob is a single-use, in-proc handler, so no need to get OLE in the
// loop here. Use new (called by CJob::Create) instead of CoCreateInstance.
//
*ppJob = CJob::Create();
if (*ppJob == NULL)
{
return E_OUTOFMEMORY;
}
}
hr = (*ppJob)->LoadP(tszFullName, 0, TRUE, fAllData);
if (FAILED(hr))
{
schDebugOut((DEB_ERROR, "CSchedule::ActivateJob: pJob->Load failed with error 0x%x\n", hr));
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::CheckJobName
//
// Synopsis: Checks for a valid job object file name and returns the full
// path name. Takes an UNICODE input name and returns a TCHAR.
//
// Arguments: [pwszJobName] - the job name as specified by the client
// [pptszFullPathName] - the name including the job folder path
//
// Returns: HRESULTS
//
// Notes: The job name can be an absolute or UNC path. If not,it is
// assumed to be relative to the job schedule folder.
// If there is an extension on the last element (the actual file
// name), then it must be .job. If there is no extension, then
// the the correct one will be added.
//-----------------------------------------------------------------------------
HRESULT
CSchedule::CheckJobName(LPCWSTR pwszJobName, LPTSTR * pptszFullPathName)
{
//
// Make sure that the string doesn't end in a slash character.
//
ULONG cchJobName = wcslen(pwszJobName);
ULONG cchNameParam = cchJobName;
if (!cchNameParam)
{
schDebugOut((DEB_ERROR,
"CSchedule::CheckJobName: pwszJobName is a 0 length string\n"));
return E_INVALIDARG;
}
if (cchNameParam > 1 &&
(pwszJobName[cchNameParam - 1] == L'\\' ||
pwszJobName[cchNameParam - 1] == L'/'))
{
schDebugOut((DEB_ERROR,
"CSchedule::CheckJobName: pwszJobName ends in illegal char %c\n",
pwszJobName[cchNameParam - 1]));
return E_INVALIDARG;
}
BOOL fNeedsPath = TRUE;
//
// Is it a full or relative path?
//
if ((cchNameParam > 2 &&
(pwszJobName[1] == TEXT(':') ||
(pwszJobName[0] == TEXT('\\') && pwszJobName[1] == TEXT('\\')) ||
(pwszJobName[0] == TEXT('/') && pwszJobName[1] == TEXT('/')))))
{
fNeedsPath = FALSE;
}
//
// Check extension
//
WCHAR * pwszJobExt = TSZ_JOB;
ULONG cJobExt = ARRAY_LEN(TSZ_JOB); // add one for the period
BOOL fNeedExt = FALSE;
const WCHAR * pwszLastDot = wcsrchr(pwszJobName, L'.');
if (pwszLastDot != NULL)
{
// check if the period is within cJobExt chars of the end
//
if ((size_t)(cchNameParam - (pwszLastDot - pwszJobName)) <= (size_t)cJobExt)
{
if (_wcsicmp(pwszLastDot + 1, pwszJobExt) != 0)
{
// Its extension does not match TSZ_JOB, so it is invalid.
//
schDebugOut((DEB_ERROR,
"CSchedule::CheckJobName: expected '%S', got '%S'",
pwszJobExt,
pwszLastDot + 1));
return E_INVALIDARG;
}
}
else // append the extension.
{
fNeedExt = TRUE;
cchNameParam += cJobExt; // add the length of the extension
}
}
else // append the extension.
{
fNeedExt = TRUE;
cchNameParam += cJobExt; // add the length of the extension
}
//
// Allocate the string to return the result.
//
if (fNeedsPath)
{
// add one for the '\'
cchNameParam += lstrlen(m_ptszFolderPath) + 1;
}
// add 1 to the array length for the null
TCHAR * ptszPath = new TCHAR[cchNameParam + 1];
if (ptszPath == NULL)
{
return E_OUTOFMEMORY;
}
if (fNeedsPath)
{
StringCchCopy(ptszPath, cchNameParam + 1, m_ptszFolderPath);
StringCchCat(ptszPath, cchNameParam + 1, TEXT("\\"));
StringCchCat(ptszPath, cchNameParam + 1, pwszJobName);
}
else
{
StringCchCopy(ptszPath, cchNameParam + 1, pwszJobName);
}
if (fNeedExt)
{
StringCchCat(ptszPath, cchNameParam + 1, TEXT(".") TSZ_JOB);
}
*pptszFullPathName = ptszPath;
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::CSchedule
//
// Synopsis: constructor
//
//-----------------------------------------------------------------------------
CSchedule::CSchedule(void) :
m_ptszTargetMachine(NULL),
m_ptszFolderPath(NULL),
m_dwNextID(1),
m_uRefs(1)
{
InitializeCriticalSection(&m_CriticalSection);
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::~CSchedule
//
// Synopsis: destructor
//
//-----------------------------------------------------------------------------
CSchedule::~CSchedule(void)
{
DeleteCriticalSection(&m_CriticalSection);
if (m_ptszTargetMachine)
{
delete m_ptszTargetMachine;
}
if (m_ptszFolderPath)
{
delete m_ptszFolderPath;
}
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::Init
//
// Synopsis: Two phase construction - can't do operations that could fail
// in the ctor since there is no way to return errors without
// throwing exceptions.
//
//-----------------------------------------------------------------------------
HRESULT
CSchedule::Init(void)
{
if (g_TasksFolderInfo.ptszPath == NULL)
{
ERR_OUT("CSchedule::Init, folder path not set", E_FAIL);
return E_FAIL;
}
HRESULT hr;
//
// Get the jobs folder location. These values will be replaced when a
// call is made to SetTargetMachine
//
size_t cch = lstrlen(g_TasksFolderInfo.ptszPath) + 1;
m_ptszFolderPath = new TCHAR[cch];
if (!m_ptszFolderPath)
{
ERR_OUT("CSchedule::Init", E_OUTOFMEMORY);
return E_OUTOFMEMORY;
}
StringCchCopy(m_ptszFolderPath, cch, g_TasksFolderInfo.ptszPath);
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Function: GetNextAtID
//
// Synopsis: Examine the AT jobs to find the highest ID.
//
//-----------------------------------------------------------------------------
void
GetNextAtID(LPDWORD pdwAtID)
{
WCHAR wszAtJobSearchPath[MAX_PATH];
StringCchCopy(wszAtJobSearchPath, MAX_PATH, g_TasksFolderInfo.ptszPath);
StringCchCat(wszAtJobSearchPath, MAX_PATH, L"\\" TSZ_AT_JOB_PREFIX L"*." TSZ_JOB);
DWORD cchNamePrefixLen = ARRAY_LEN(TSZ_AT_JOB_PREFIX) - 1;
WIN32_FIND_DATA fd;
HANDLE hFileFind = FindFirstFile(wszAtJobSearchPath, &fd);
if (hFileFind == INVALID_HANDLE_VALUE)
{
//
// If no at jobs, set the initial job ID to be 1, since zero is
// reserved for an error flag.
//
*pdwAtID = 1;
return;
}
DWORD dwMaxID = 1;
do
{
WCHAR * pDot = wcschr(fd.cFileName, L'.');
if (pDot == NULL)
{
continue;
}
*pDot = L'\0';
DWORD dwCurID = (DWORD)wcstoul(fd.cFileName + cchNamePrefixLen, NULL, 10);
schDebugOut((DEB_ITRACE, "GetNextAtID: found %S, with ID %d\n",
fd.cFileName, dwCurID));
if (dwCurID > dwMaxID)
{
dwMaxID = dwCurID;
}
} while (FindNextFile(hFileFind, &fd));
FindClose(hFileFind);
if (ULONG_MAX != dwMaxID)
{
//
// The next available AT ID will be one greater than the current max.
//
*pdwAtID = dwMaxID + 1;
}
else
{
//
// find first hole instead
//
StringCchCopy(wszAtJobSearchPath, MAX_PATH, g_TasksFolderInfo.ptszPath);
StringCchCat(wszAtJobSearchPath, MAX_PATH, L"\\" TSZ_AT_JOB_PREFIX);
DWORD cchOffset = wcslen(wszAtJobSearchPath);
dwMaxID = 1;
StringCchPrintf(wszAtJobSearchPath + cchOffset, MAX_PATH - cchOffset, L"%d%s", dwMaxID, TSZ_DOTJOB);
while (0xffffffff != GetFileAttributes(wszAtJobSearchPath) && dwMaxID < ULONG_MAX)
{
dwMaxID++;
StringCchPrintf(wszAtJobSearchPath + cchOffset, MAX_PATH - cchOffset, L"%d%s", dwMaxID, TSZ_DOTJOB);
}
// it is safe to assume dwMaxID now equals the first ID that wasn't found
// as it is unfeasible that all IDs from 1 to 0xffffffff (4,294,967,295) would be in use
*pdwAtID = dwMaxID;
}
return;
}
//+----------------------------------------------------------------------------
//
// CSchedule IUnknown methods
//
//-----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
//
// Member: CSchedule::IUnknown::QueryInterface
//
// Synopsis: Returns requested interface pointer
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CSchedule::QueryInterface(REFIID riid, void ** ppvObject)
{
//schDebugOut((DEB_ITRACE, "CSchedule::QueryInterface"));
if (!ppvObject)
{
return E_INVALIDARG;
}
if (IID_IUnknown == riid)
{
*ppvObject = (IUnknown *)this;
}
else if (IID_ITaskScheduler == riid)
{
*ppvObject = (IUnknown *)(ITaskScheduler *)this;
}
//else if (IID_IDispatch == riid)
//{
// *ppvObject = (IUnknown *)(IDispatch *)this;
//}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::IUnknown::AddRef
//
// Synopsis: increments reference count
//
// Returns: the reference count
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CSchedule::AddRef(void)
{
//schDebugOut((DEB_ITRACE, "CSchedule::AddRef refcount going in %d\n", m_uRefs));
return InterlockedIncrement((long *)&m_uRefs);
}
//+----------------------------------------------------------------------------
//
// Member: CSchedule::IUnknown::Release
//
// Synopsis: Decrements the object's reference count and frees it when
// no longer referenced.
//
// Returns: zero if the reference count is zero or non-zero otherwise
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CSchedule::Release(void)
{
//schDebugOut((DEB_ITRACE, "CSchedule::Release ref count going in %d\n", m_uRefs));
unsigned long uTmp;
if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
{
delete this;
}
return uTmp;
}
//+----------------------------------------------------------------------------
//
// CScheduleCF - class factory for the Schedule Service object
//
//-----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::Create
//
// Synopsis: creates a new class factory object
//
//-----------------------------------------------------------------------------
IClassFactory *
CScheduleCF::Create(void)
{
return new CScheduleCF;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::CScheduleCF
//
// Synopsis: ctor
//
//-----------------------------------------------------------------------------
CScheduleCF::CScheduleCF(void)
{
m_uRefs = 1;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::~CScheduleCF
//
// Synopsis: dtor
//
//-----------------------------------------------------------------------------
CScheduleCF::~CScheduleCF(void)
{
;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::IUnknown::QueryInterface
//
// Synopsis: Returns requested interface pointer
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CScheduleCF::QueryInterface(REFIID riid, void ** ppvObject)
{
//schDebugOut((DEB_ITRACE, "CScheduleCF::QueryInterface"));
if (!ppvObject)
{
return E_INVALIDARG;
}
if (IID_IUnknown == riid)
{
*ppvObject = (IUnknown *)this;
}
else if (IsEqualIID(IID_IClassFactory, riid))
{
*ppvObject = (IClassFactory *)this;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::IUnknown::AddRef
//
// Synopsis: increments reference count
//
// Returns: the new reference count
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CScheduleCF::AddRef(void)
{
return InterlockedIncrement((long *)&m_uRefs);
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::IUnknown::Release
//
// Synopsis: noop, since this is a static object
//
// Returns: the new reference count
//
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CScheduleCF::Release(void)
{
unsigned long uTmp;
if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
{
delete this;
}
return uTmp;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::IClassFactory::CreateInstance
//
// Synopsis: create an incore instance of the job class object
//
// Arguments: [pUnkOuter] - aggregator
// [riid] - requested interface
// [ppvObject] - receptor for itf ptr
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CScheduleCF::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
{
//schDebugOut((DEB_ITRACE, "CScheduleCF::CreateInstance\n"));
if (!ppvObject)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
*ppvObject = NULL;
CSchedule * pSched = new CSchedule;
if (pSched == NULL)
{
return E_OUTOFMEMORY;
}
hr = pSched->Init();
if (FAILED(hr))
{
ERR_OUT("CScheduleCF::CreateInstance, pSched->Init", hr);
pSched->Release();
return hr;
}
hr = pSched->QueryInterface(riid, ppvObject);
if (FAILED(hr))
{
ERR_OUT("CScheduleCF::CreateInstance, pSched->QueryInterface", hr);
pSched->Release();
return hr;
}
//
// We got a refcount of one when launched, and the above QI increments it
// to 2, so call release to take it back to 1.
//
pSched->Release();
return hr;
}
//+----------------------------------------------------------------------------
//
// Member: CScheduleCF::IClassFactory::LockServer
//
// Synopsis: Called with fLock set to TRUE to indicate that the server
// should continue to run even if none of its objects are active
//
// Arguments: [fLock] - increment/decrement the instance count
//
// Returns: HRESULTS
//
// Notes: This is a no-op since the handler runs in-proc.
//
//-----------------------------------------------------------------------------
STDMETHODIMP
CScheduleCF::LockServer(BOOL fLock)
{
return S_OK;
}