Source code of Windows XP (NT5)
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.

530 lines
15 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: globals.cxx
  7. //
  8. // Contents: Service global data.
  9. //
  10. // Classes: None.
  11. //
  12. // Functions: None.
  13. //
  14. // History: 09-Sep-95 EricB Created.
  15. // 01-Dec-95 MarkBl Split from util.cxx.
  16. //
  17. //----------------------------------------------------------------------------
  18. #include "..\pch\headers.hxx"
  19. #pragma hdrstop
  20. #include "..\inc\resource.h"
  21. #include "..\inc\common.hxx"
  22. #include "..\inc\debug.hxx"
  23. #include "..\inc\misc.hxx"
  24. #if !defined(_CHICAGO_)
  25. void
  26. GetRootPath(
  27. LPCWSTR pwszPath,
  28. WCHAR wszRootPath[]);
  29. #endif // !defined(_CHICAGO_)
  30. TasksFolderInfo g_TasksFolderInfo = { NULL, FILESYSTEM_FAT };
  31. TCHAR g_tszSrvcName[] = SCHED_SERVICE_NAME;
  32. BOOL g_fNotifyMiss; // = 0 by loader
  33. HINSTANCE g_hInstance; // = NULL by loader
  34. ULONG CDll::s_cObjs; // = 0 by loader
  35. ULONG CDll::s_cLocks; // = 0 by loader
  36. #if !defined(_CHICAGO_)
  37. WCHAR g_wszAtJobSearchPath[MAX_PATH];
  38. #endif // !defined(_CHICAGO_)
  39. #define DEFAULT_FOLDER_PATH TEXT("%WinDir%\\Tasks")
  40. #define TASKS_FOLDER TEXT("\\Tasks")
  41. //
  42. // BUGBUG: global __int64 initialization is not working without the CRT.
  43. // BUG # 37752.
  44. //
  45. __int64 FILETIMES_PER_DAY;
  46. //+----------------------------------------------------------------------------
  47. //
  48. // Function: InitGlobals
  49. //
  50. // Synopsis: constructs global strings including the folder path strings and,
  51. // if needed, creates the folders
  52. //
  53. // Returns: HRESULTS
  54. //
  55. // Notes: This function is called in exactly two places, once for each
  56. // binary: in dllmisc.cxx for the DLL and in svc_core.cxx for the
  57. // service.
  58. //-----------------------------------------------------------------------------
  59. HRESULT
  60. InitGlobals(void)
  61. {
  62. HRESULT hr = S_OK;
  63. //
  64. // Open the schedule agent key
  65. //
  66. long lErr;
  67. HKEY hSchedKey = NULL;
  68. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ,
  69. &hSchedKey);
  70. if (lErr != ERROR_SUCCESS)
  71. {
  72. ERR_OUT("RegOpenKeyEx of Scheduler key", lErr);
  73. //
  74. // The scheduler key is missing, create it.
  75. //
  76. DWORD disp = 0;
  77. lErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, NULL, 0,
  78. KEY_SET_VALUE, NULL, &hSchedKey, &disp);
  79. if (lErr != ERROR_SUCCESS)
  80. {
  81. ERR_OUT("RegCreateKeyEx of Scheduler key", lErr);
  82. hSchedKey = NULL;
  83. }
  84. }
  85. TCHAR tszFolder[MAX_PATH + 1] = TEXT("");
  86. // Ensure null termination (registry doesn't guarantee this if not string data)
  87. tszFolder[MAX_PATH] = TEXT('\0');
  88. if (hSchedKey != NULL)
  89. {
  90. //
  91. // Get the jobs folder location
  92. //
  93. DWORD cb = MAX_PATH * sizeof(TCHAR);
  94. lErr = RegQueryValueEx(hSchedKey, SCH_FOLDER_VALUE, NULL, NULL,
  95. (LPBYTE)tszFolder, &cb);
  96. if (lErr != ERROR_SUCCESS)
  97. {
  98. ERR_OUT("RegQueryValueEx of Scheduler TasksFolder value", lErr);
  99. //
  100. // The task folder value is missing, create it.
  101. //
  102. // Reopen the key with write access.
  103. //
  104. RegCloseKey(hSchedKey);
  105. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0,
  106. KEY_SET_VALUE, &hSchedKey);
  107. if (lErr != ERROR_SUCCESS)
  108. {
  109. ERR_OUT("RegOpenKeyEx of Scheduler key", lErr);
  110. hSchedKey = NULL;
  111. }
  112. else
  113. {
  114. //
  115. // Default to the windows root.
  116. //
  117. lErr = RegSetValueEx(hSchedKey,
  118. SCH_FOLDER_VALUE,
  119. 0,
  120. REG_EXPAND_SZ,
  121. (const BYTE *) DEFAULT_FOLDER_PATH,
  122. sizeof(DEFAULT_FOLDER_PATH));
  123. if (lErr != ERROR_SUCCESS)
  124. {
  125. ERR_OUT("RegSetValueEx of Scheduler TasksFolder value",
  126. lErr);
  127. }
  128. }
  129. }
  130. //
  131. // Read the "NotifyOnTaskMiss" value. Default value is 0.
  132. //
  133. cb = sizeof g_fNotifyMiss;
  134. lErr = RegQueryValueEx(hSchedKey, SCH_NOTIFYMISS_VALUE, NULL, NULL,
  135. (LPBYTE) &g_fNotifyMiss, &cb);
  136. if (lErr != ERROR_SUCCESS)
  137. {
  138. if (lErr != ERROR_FILE_NOT_FOUND)
  139. {
  140. ERR_OUT("RegQueryValueEx of NotifyOnTaskMiss value", lErr);
  141. }
  142. g_fNotifyMiss = 0;
  143. }
  144. schDebugOut((DEB_TRACE, "Notification of missed runs is %s\n",
  145. g_fNotifyMiss ? "enabled" : "disabled"));
  146. if (hSchedKey != NULL)
  147. {
  148. RegCloseKey(hSchedKey);
  149. }
  150. }
  151. if (lstrlen(tszFolder) == 0)
  152. {
  153. //
  154. // Use a default if the value is missing.
  155. //
  156. lstrcpy(tszFolder, DEFAULT_FOLDER_PATH);
  157. }
  158. //
  159. // The ExpandEnvironmentStrings character counts include the terminating
  160. // null.
  161. //
  162. TCHAR tszDummy[1];
  163. DWORD cch = ExpandEnvironmentStrings(tszFolder, tszDummy, 1);
  164. if (!cch)
  165. {
  166. hr = HRESULT_FROM_WIN32(GetLastError());
  167. ERR_OUT("ExpandEnvironmentStrings", hr);
  168. return hr;
  169. }
  170. g_TasksFolderInfo.ptszPath = new TCHAR[cch];
  171. if (g_TasksFolderInfo.ptszPath == NULL)
  172. {
  173. ERR_OUT("Tasks Folder name buffer allocation", E_OUTOFMEMORY);
  174. return E_OUTOFMEMORY;
  175. }
  176. cch = ExpandEnvironmentStrings(tszFolder, g_TasksFolderInfo.ptszPath,
  177. cch);
  178. if (!cch)
  179. {
  180. hr = HRESULT_FROM_WIN32(GetLastError());
  181. ERR_OUT("ExpandEnvironmentStrings", hr);
  182. return hr;
  183. }
  184. //
  185. // if the Jobs folder doesn't exist, create it
  186. //
  187. hr = CreateFolders(g_TasksFolderInfo.ptszPath, FALSE);
  188. if (FAILED(hr))
  189. {
  190. ERR_OUT("InitGlobals, CreateFolders", hr);
  191. return hr;
  192. }
  193. //
  194. // Initialize the file system type global task folder info field.
  195. // Always FAT on Win95.
  196. //
  197. #if defined(_CHICAGO_)
  198. g_TasksFolderInfo.FileSystemType = FILESYSTEM_FAT;
  199. #else
  200. hr = GetFileSystemTypeFromPath(g_TasksFolderInfo.ptszPath,
  201. &g_TasksFolderInfo.FileSystemType);
  202. if (FAILED(hr))
  203. {
  204. return hr;
  205. }
  206. #endif // defined(_CHICAGO_)
  207. schDebugOut((DEB_ITRACE,
  208. "Path to local sched folder: \"" FMT_TSTR "\"\n",
  209. g_TasksFolderInfo.ptszPath));
  210. #if !defined(_CHICAGO_)
  211. //
  212. // Create the AT task FindFirstFile filespec
  213. //
  214. ULONG cchAtJobSearchPath;
  215. cchAtJobSearchPath = lstrlen(g_TasksFolderInfo.ptszPath) +
  216. ARRAY_LEN(TSZ_AT_JOB_PREFIX) - 1 +
  217. ARRAY_LEN(TSZ_DOTJOB) - 1 +
  218. 3; // backslash, start, and nul terminator
  219. if (cchAtJobSearchPath > ARRAY_LEN(g_wszAtJobSearchPath))
  220. {
  221. schDebugOut((DEB_ERROR,
  222. "InitGlobals: At job search path is %u chars but dest buffer is %u\n",
  223. cchAtJobSearchPath,
  224. ARRAY_LEN(g_wszAtJobSearchPath)));
  225. return E_FAIL;
  226. }
  227. lstrcpy(g_wszAtJobSearchPath, g_TasksFolderInfo.ptszPath);
  228. lstrcat(g_wszAtJobSearchPath, L"\\" TSZ_AT_JOB_PREFIX L"*" TSZ_DOTJOB);
  229. #endif // !defined(_CHICAGO_)
  230. //
  231. // BUGBUG: This is temporary until global __int64 initialization is working
  232. // without the CRT:
  233. //
  234. FILETIMES_PER_DAY = (__int64)FILETIMES_PER_MINUTE *
  235. (__int64)JOB_MINS_PER_HOUR *
  236. (__int64)JOB_HOURS_PER_DAY;
  237. return S_OK;
  238. }
  239. //+----------------------------------------------------------------------------
  240. //
  241. // Function: FreeGlobals
  242. //
  243. // Synopsis: frees dynamically allocated globals
  244. //
  245. // Notes: This function is called in exactly two places, once for each
  246. // binary: in dllmisc.cxx for the DLL and in svc_core.cxx for the
  247. // service.
  248. //-----------------------------------------------------------------------------
  249. void
  250. FreeGlobals(void)
  251. {
  252. if (g_TasksFolderInfo.ptszPath != NULL)
  253. {
  254. delete g_TasksFolderInfo.ptszPath;
  255. g_TasksFolderInfo.ptszPath = NULL;
  256. }
  257. }
  258. //+----------------------------------------------------------------------------
  259. //
  260. // Function: ReadLastTaskRun
  261. //
  262. // Synopsis: Reads the last task run time from the registry.
  263. //
  264. // Returns: TRUE if successful, FALSE if unsuccessful
  265. //
  266. // Notes:
  267. //
  268. //-----------------------------------------------------------------------------
  269. BOOL
  270. ReadLastTaskRun(SYSTEMTIME * pstLastRun)
  271. {
  272. HKEY hSchedKey;
  273. LONG lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_READ,
  274. &hSchedKey);
  275. if (lErr != ERROR_SUCCESS)
  276. {
  277. ERR_OUT("RegOpenKeyEx of Sched key", lErr);
  278. return FALSE;
  279. }
  280. DWORD cb = sizeof SYSTEMTIME;
  281. DWORD dwType;
  282. lErr = RegQueryValueEx(hSchedKey, SCH_LASTRUN_VALUE, NULL, &dwType,
  283. (LPBYTE)pstLastRun, &cb);
  284. RegCloseKey(hSchedKey);
  285. if (lErr != ERROR_SUCCESS || dwType != REG_BINARY || cb != sizeof SYSTEMTIME)
  286. {
  287. schDebugOut((DEB_ERROR, "RegQueryValueEx of LastRunTime value failed, "
  288. "error %ld, dwType = %lu, cb = %lu\n",
  289. lErr, dwType, cb));
  290. return FALSE;
  291. }
  292. return TRUE;
  293. }
  294. //+----------------------------------------------------------------------------
  295. //
  296. // Function: WriteLastTaskRun
  297. //
  298. // Synopsis: Writes the last task run time to the registry.
  299. //
  300. // Returns: TRUE if successful, FALSE if unsuccessful
  301. //
  302. // Notes:
  303. //
  304. //-----------------------------------------------------------------------------
  305. void WriteLastTaskRun(const SYSTEMTIME * pstLastRun)
  306. {
  307. HKEY hSchedKey;
  308. LONG lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SCH_AGENT_KEY, 0, KEY_WRITE,
  309. &hSchedKey);
  310. if (lErr != ERROR_SUCCESS)
  311. {
  312. ERR_OUT("RegOpenKeyEx of Sched key for write", lErr);
  313. return;
  314. }
  315. lErr = RegSetValueEx(hSchedKey, SCH_LASTRUN_VALUE, 0, REG_BINARY,
  316. (const BYTE *) pstLastRun, sizeof SYSTEMTIME);
  317. if (lErr != ERROR_SUCCESS)
  318. {
  319. schDebugOut((DEB_ERROR, "RegSetValueEx of LastRunTime value failed %ld\n",
  320. lErr));
  321. }
  322. RegCloseKey(hSchedKey);
  323. }
  324. #if !defined(_CHICAGO_)
  325. //+---------------------------------------------------------------------------
  326. //
  327. // Function: GetFileSystemTypeFromPath
  328. //
  329. // Synopsis: Determine the file system type, either FAT or NTFS, from
  330. // the path passed.
  331. //
  332. // Arguments: [pwszPath] -- Input path.
  333. // [wszRootPath] -- Returned root path.
  334. //
  335. // Returns: S_OK
  336. // GetVolumeInformation HRESULT error code.
  337. //
  338. // Notes: None.
  339. //
  340. //----------------------------------------------------------------------------
  341. HRESULT
  342. GetFileSystemTypeFromPath(LPCWSTR pwszPath, FILESYSTEMTYPE * pFileSystemType)
  343. {
  344. #define FS_NTFS L"NTFS"
  345. #define FS_NAME_BUFFER_SIZE (sizeof(FS_NTFS) * 2)
  346. //
  347. // Obtain the root path (eg: "r:\", "\\fido\scratch\", etc.) from the
  348. // path.
  349. //
  350. LPWSTR pwszRootPath = new WCHAR[wcslen(pwszPath) + 2];
  351. if (pwszRootPath == NULL)
  352. {
  353. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  354. return E_OUTOFMEMORY;
  355. }
  356. GetRootPath(pwszPath, pwszRootPath);
  357. //
  358. // Retrieve the file system name.
  359. //
  360. WCHAR wszFileSystemName[FS_NAME_BUFFER_SIZE + 1];
  361. DWORD dwMaxCompLength, dwFileSystemFlags;
  362. if (!GetVolumeInformation(pwszRootPath, // Root path name.
  363. NULL, // Ignore name.
  364. 0,
  365. NULL, // Ignore serial no.
  366. &dwMaxCompLength, // Unused.
  367. &dwFileSystemFlags, // Unused.
  368. wszFileSystemName, // "FAT"/"NTFS".
  369. FS_NAME_BUFFER_SIZE)) // name buffer size.
  370. {
  371. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  372. CHECK_HRESULT(hr);
  373. delete [] pwszRootPath;
  374. return hr;
  375. }
  376. delete [] pwszRootPath;
  377. //
  378. // Check if the volume is NTFS.
  379. // If not NTFS, assume FAT.
  380. //
  381. if (_wcsicmp(wszFileSystemName, FS_NTFS) == 0)
  382. {
  383. *pFileSystemType = FILESYSTEM_NTFS;
  384. }
  385. else
  386. {
  387. *pFileSystemType = FILESYSTEM_FAT;
  388. }
  389. return(S_OK);
  390. }
  391. #endif // !defined(_CHICAGO_)
  392. #if !defined(_CHICAGO_)
  393. //+---------------------------------------------------------------------------
  394. //
  395. // Function: GetRootPath
  396. //
  397. // Synopsis: Return the root portion of the path indicated. eg: return
  398. // "r:\" from "r:\foo\bar"
  399. // "\\fido\scratch\", from "\\fido\scratch\bar\foo"
  400. //
  401. // Arguments: [pwszPath] -- Input path.
  402. // [wszRootPath] -- Returned root path.
  403. //
  404. // Returns: None.
  405. //
  406. // Notes: None.
  407. //
  408. //----------------------------------------------------------------------------
  409. void
  410. GetRootPath(LPCWSTR pwszPath, WCHAR wszRootPath[])
  411. {
  412. LPCWSTR pwsz = pwszPath;
  413. if (*pwsz == L'\\')
  414. {
  415. if (*(++pwsz) == L'\\')
  416. {
  417. //
  418. // UNC path. GetVolumeInformation requires the trailing '\'
  419. // on the UNC path. eg: \\server\share\.
  420. //
  421. DWORD i;
  422. for (i = 0, pwsz++; *pwsz && i < 2; i++, pwsz++)
  423. {
  424. for ( ; *pwsz && *pwsz != L'\\'; pwsz++) ;
  425. }
  426. if (i == 2)
  427. {
  428. pwsz--;
  429. }
  430. else
  431. {
  432. goto ErrorExit;
  433. }
  434. }
  435. else
  436. {
  437. //
  438. // Path is "\". Not an error, but handled the same way
  439. //
  440. goto ErrorExit;
  441. }
  442. }
  443. else
  444. {
  445. for ( ; *pwsz && *pwsz != L'\\'; pwsz++) ;
  446. }
  447. if (*pwsz == L'\\')
  448. {
  449. DWORD cbLen = (DWORD)((BYTE *)pwsz - (BYTE *)pwszPath) + sizeof(L'\\');
  450. CopyMemory((LPWSTR)wszRootPath, (LPWSTR)pwszPath, cbLen);
  451. wszRootPath[cbLen / sizeof(WCHAR)] = L'\0';
  452. return;
  453. }
  454. else
  455. {
  456. //
  457. // Fall through.
  458. //
  459. }
  460. ErrorExit:
  461. //
  462. // Return '\' in error cases.
  463. //
  464. wszRootPath[0] = L'\\';
  465. wszRootPath[1] = L'\0';
  466. }
  467. #endif // !defined(_CHICAGO_)