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.

506 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. grovel.cpp
  5. Abstract:
  6. SIS Groveler main function
  7. Authors:
  8. John Douceur, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "all.hxx"
  14. /*
  15. * The core of the groveler executable is an object of the EventTimer class.
  16. * All periodic operations are registered with the global event_timer object,
  17. * and they are called at appropriate times during the execution of the
  18. * event_timer.run() function.
  19. *
  20. * Errors are written to the system event log, which is accessed through
  21. * member functions of the EventLog class. The eventlog object is a global
  22. * so that any function or member function of any class can log an event if
  23. * necessary.
  24. *
  25. * The service control thread synchronizes with the main groveler thread via
  26. * a Windows event. This event is encapsulated in an object of the SyncEvent
  27. * class.
  28. *
  29. * The SISDrives class determines which drives have SIS installed.
  30. *
  31. * The SharedData class is used to write values that are read by the groveler
  32. * performance DLL, so that the groveler's operation can be monitored by
  33. * PerfMon. This object needs to be global so that any function or member
  34. * function of any class can record performance information.
  35. *
  36. * The CentralController class is instantiated into a global object, rather
  37. * than an object local to the main() function, so that the service controller
  38. * can invoke CentralController member functions in order to affect its
  39. * operation.
  40. *
  41. * Initially, the shared_data and controller pointers are set to null, so that
  42. * if an exception occurs, the code that deletes allocated objects can check
  43. * for a null to determine whether or not the object has been instantiated.
  44. *
  45. */
  46. EventTimer event_timer;
  47. EventLog eventlog;
  48. SyncEvent sync_event(false, false);
  49. SISDrives sis_drives;
  50. LogDrive *log_drive = 0;
  51. SharedData *shared_data = 0;
  52. CentralController *controller = 0;
  53. /*
  54. * Ordinarily, the groveler does not stop operation until it is told to by
  55. * a command from the service control manager. However, for testing, it can
  56. * sometimes be useful to specify a time limit for running. The groveler thus
  57. * accepts a first argument that indicates such a time limit. If an argument
  58. * is supplied, an invokation of the halt() function is scheduled in the
  59. * event_timer object for the specified time.
  60. *
  61. */
  62. void halt(
  63. void *context)
  64. {
  65. event_timer.halt();
  66. };
  67. /*
  68. * The function groveler_new_handler() is installed as a new handler by the
  69. * _set_new_handler() function. Whenever a memory allocation failure occurs,
  70. * it throws an exception_memory_allocation, which is caught by the catch
  71. * clause in the main() function.
  72. *
  73. */
  74. int __cdecl groveler_new_handler(
  75. size_t bytes)
  76. {
  77. throw exception_memory_allocation;
  78. return 0;
  79. }
  80. /*
  81. * This file contains the main() function and declarations for global objects
  82. * for the groveler.exe program, as well as a couple of simple ancillary
  83. * functions, halt() and groveler_new_handler().
  84. *
  85. * The main() function reads configuration information, instantiates a set of
  86. * primary objects -- the most significant of which are instances of the
  87. * classes Groveler and CentralController -- and enters the run() member
  88. * function of the event_timer object, which periodically invokes member
  89. * functions of other objects, most notably those of the clasess
  90. * CentralController and PartitionController.
  91. *
  92. * Configuration information comes from objects of three classes:
  93. * ReadParameters, ReadDiskInformation, and PathList. The ReadParameters
  94. * and PathList classes provide configuration information that applies to
  95. * grovelers on all partitions. The ReadDiskInformation class provides
  96. * configuration information that applies to a single disk partition. One
  97. * object of the ReadDiskInformation class is instantiated for each drive
  98. * that has SIS installed, as explained above.
  99. *
  100. * For each SIS drive, the main() function instantiates an object of the
  101. * ReadDiskInformation class to determine the configuration options (which
  102. * ReadDiskInformation obtains from the registry) for the given disk
  103. * partition. If the drive is configured to enable groveling, then an object
  104. * of the Groveler class is instantiated for that drive.
  105. *
  106. * The main() function then instantiates an object of class CentralController,
  107. * which in turn instantiates an object of class PartitionController for each
  108. * SIS-enabled disk partition. Each partition controller is assigned to one
  109. * object of the Groveler class, and it controls the groveler by calling its
  110. * member functions at appropriate times.
  111. *
  112. * Nearly all of of the processing done by the groveler executable is
  113. * performed within a try clause, the purpose of which is to catch errors of
  114. * terminal severity. There are two such errors (defined in all.hxx) that are
  115. * expected to throw such exceptions: a memory allocation failure and a
  116. * failure to create an Windows event. If either of these conditions occurs,
  117. * the program terminates.
  118. *
  119. */
  120. _main(int argc, _TCHAR **argv)
  121. {
  122. _set_new_handler(groveler_new_handler);
  123. SetErrorMode(SEM_FAILCRITICALERRORS);
  124. int exit_code = NO_ERROR;
  125. int num_partitions = 0;
  126. int index;
  127. //
  128. // Initially, these pointers are set to null, so that if an exception
  129. // occurs, the code that deletes allocated objects can check for a null
  130. // to determine whether or not the object has been instantiated.
  131. //
  132. Groveler *grovelers = 0;
  133. GrovelStatus *groveler_statuses = 0;
  134. ReadDiskInformation **read_disk_info = 0;
  135. WriteDiskInformation **write_disk_info = 0;
  136. //
  137. // If program tracing is being performed, and if the traces are being sent
  138. // to a file, the file is opened. This call is made through a macro
  139. // so that no code will be generated for released builds. Since this call
  140. // is made before the try clause, it is important that the function not
  141. // perform any operation that could throw an exception, such as a memory
  142. // allocation.
  143. //
  144. OPEN_TRACE_FILE();
  145. try
  146. {
  147. //
  148. // If a first argument is provided, it is the run period.
  149. //
  150. if (argc > 1)
  151. {
  152. int run_period = _ttoi(argv[1]);
  153. if (run_period <= 0)
  154. {
  155. PRINT_DEBUG_MSG((_T("GROVELER: run period must be greater than zero\n")));
  156. return ERROR_BAD_ARGUMENTS;
  157. }
  158. unsigned int start_time = GET_TICK_COUNT();
  159. event_timer.schedule(start_time + run_period, 0, halt);
  160. }
  161. #if DEBUG_WAIT
  162. // When debugging the groveler as a service, if the process is attached
  163. // to a debugger after it has started, then the initialization code
  164. // will usually be executed before the debugger has a chance to break.
  165. // However, by defining DEBUG_WAIT to a non-zero value, the code will
  166. // get stuck in the following infinite loop before doing the bulk of
  167. // its initialization. (The event_timer, eventlog, and sync_event
  168. // objects will have been constructed, because they are declared as
  169. // globals.) The debugger can then be used to set debug_wait to false,
  170. // and debugging can commence with the subsequent code.
  171. bool debug_wait = true;
  172. while (debug_wait)
  173. {
  174. SLEEP(100);
  175. };
  176. #endif // DEBUG_WAIT
  177. eventlog.report_event(GROVMSG_SERVICE_STARTED, 0);
  178. sis_drives.open();
  179. //
  180. // See if there were any partions to scan. If not, quit
  181. //
  182. num_partitions = sis_drives.partition_count();
  183. if (num_partitions == 0)
  184. {
  185. PRINT_DEBUG_MSG((_T("GROVELER: No local partitions have SIS installed.\n")));
  186. eventlog.report_event(GROVMSG_NO_PARTITIONS, 0);
  187. eventlog.report_event(GROVMSG_SERVICE_STOPPED, 0);
  188. return ERROR_SERVICE_NOT_ACTIVE;
  189. }
  190. //
  191. // Report the service is running
  192. //
  193. SERVICE_REPORT_START();
  194. //
  195. // Setup shared data are between all the worker threads
  196. //
  197. num_partitions = sis_drives.partition_count();
  198. _TCHAR **drive_names = new _TCHAR *[num_partitions];
  199. for (index = 0; index < num_partitions; index++)
  200. {
  201. drive_names[index] = sis_drives.partition_mount_name(index);
  202. }
  203. shared_data = new SharedData(num_partitions, drive_names);
  204. delete drive_names;
  205. //
  206. // Get READ parameters
  207. //
  208. ReadParameters read_parameters;
  209. ASSERT(read_parameters.parameter_backup_interval >= 0);
  210. //
  211. // Get WRITE parameters
  212. //
  213. WriteParameters write_parameters(read_parameters.parameter_backup_interval);
  214. //
  215. // Get excluded path list
  216. //
  217. PathList excluded_paths;
  218. //
  219. // Setup LogDrive
  220. //
  221. log_drive = new LogDrive;
  222. Groveler::set_log_drive(sis_drives.partition_mount_name(log_drive->drive_index()));
  223. //
  224. // Setup Groveler objects
  225. //
  226. grovelers = new Groveler[num_partitions];
  227. groveler_statuses = new GrovelStatus[num_partitions];
  228. //
  229. // Initially, the status of each partition is set to Grovel_disable so
  230. // that the close() member function of each Groveler object will not
  231. // be called unless the open() function is called first.
  232. //
  233. for (index = 0; index < num_partitions; index++)
  234. {
  235. groveler_statuses[index] = Grovel_disable;
  236. }
  237. //
  238. // Initially, the read_disk_info[] and write_disk_info[] arrays are set
  239. // to null, so that if an exception occurs, the code that deletes
  240. // allocated objects can check for a null to determine whether or not
  241. // the object has been instantiated.
  242. //
  243. read_disk_info = new ReadDiskInformation *[num_partitions];
  244. ZeroMemory(read_disk_info, sizeof(ReadDiskInformation *) * num_partitions);
  245. write_disk_info = new WriteDiskInformation *[num_partitions];
  246. ZeroMemory(read_disk_info, sizeof(WriteDiskInformation *) * num_partitions);
  247. //
  248. // Now initilaize each partition
  249. //
  250. for (index = 0; index < num_partitions; index++)
  251. {
  252. read_disk_info[index] = new ReadDiskInformation(sis_drives.partition_guid_name(index));
  253. write_disk_info[index] = new WriteDiskInformation(sis_drives.partition_guid_name(index),read_parameters.parameter_backup_interval);
  254. if (read_disk_info[index]->enable_groveling)
  255. {
  256. groveler_statuses[index] = grovelers[index].open(
  257. sis_drives.partition_guid_name(index),
  258. sis_drives.partition_mount_name(index),
  259. index == log_drive->drive_index(),
  260. read_parameters.read_report_discard_threshold,
  261. read_disk_info[index]->min_file_size,
  262. read_disk_info[index]->min_file_age,
  263. read_disk_info[index]->allow_compressed_files,
  264. read_disk_info[index]->allow_encrypted_files,
  265. read_disk_info[index]->allow_hidden_files,
  266. read_disk_info[index]->allow_offline_files,
  267. read_disk_info[index]->allow_temporary_files,
  268. excluded_paths.num_paths[index],
  269. excluded_paths.paths[index],
  270. read_parameters.base_regrovel_interval,
  271. read_parameters.max_regrovel_interval);
  272. ASSERT(groveler_statuses[index] != Grovel_disable);
  273. }
  274. if (groveler_statuses[index] == Grovel_ok)
  275. {
  276. log_drive->partition_initialized(index);
  277. eventlog.report_event(GROVMSG_GROVELER_STARTED, 1,
  278. sis_drives.partition_mount_name(index));
  279. }
  280. else if (groveler_statuses[index] == Grovel_disable)
  281. {
  282. eventlog.report_event(GROVMSG_GROVELER_DISABLED, 1,
  283. sis_drives.partition_mount_name(index));
  284. }
  285. else if (groveler_statuses[index] != Grovel_new)
  286. {
  287. ASSERT(groveler_statuses[index] == Grovel_error);
  288. eventlog.report_event(GROVMSG_GROVELER_NOSTART, 1,
  289. sis_drives.partition_mount_name(index));
  290. }
  291. }
  292. //
  293. // We have to pass a lot of information to the central controller that
  294. // it shouldn't really need. However, if a groveler fails, this
  295. // information is needed to restart it. It would be better if the
  296. // Groveler open() member function had a form that did not require
  297. // arguments, but rather re-used the arguments that had been passed in
  298. // previously. But this is not how it currently works.
  299. //
  300. controller = new CentralController(
  301. num_partitions,
  302. grovelers,
  303. groveler_statuses,
  304. &read_parameters,
  305. &write_parameters,
  306. read_disk_info,
  307. write_disk_info,
  308. excluded_paths.num_paths,
  309. excluded_paths.paths);
  310. SERVICE_RECORD_PARTITION_INDICES();
  311. ASSERT(read_parameters.grovel_duration > 0);
  312. SERVICE_SET_MAX_RESPONSE_TIME(read_parameters.grovel_duration);
  313. //
  314. // If any grovelers are alive, tell the service control manager that
  315. // we have concluded the initialization, then commence running.
  316. //
  317. if (controller->any_grovelers_alive())
  318. {
  319. event_timer.run();
  320. }
  321. //
  322. // If tracing is being performed in delayed mode, print the trace log
  323. // now that the run has completed.
  324. //
  325. PRINT_TRACE_LOG();
  326. } catch (Exception exception) {
  327. switch (exception)
  328. {
  329. case exception_memory_allocation:
  330. eventlog.report_event(GROVMSG_MEMALLOC_FAILURE, 0);
  331. break;
  332. case exception_create_event:
  333. eventlog.report_event(GROVMSG_CREATE_EVENT_FAILURE, 0);
  334. break;
  335. default:
  336. eventlog.report_event(GROVMSG_UNKNOWN_EXCEPTION, 0);
  337. break;
  338. }
  339. exit_code = ERROR_EXCEPTION_IN_SERVICE;
  340. }
  341. //
  342. // If program tracing is being performed, and if the traces are being sent
  343. // to a file, the file is closed. This call is made through a macro
  344. // so that no code will be generated for released builds. Since the trace
  345. // file is being closed before the objects are deleted, it is important
  346. // not to write trace information in the destructor of an object.
  347. //
  348. CLOSE_TRACE_FILE();
  349. //
  350. // Close each groveler object that was opened.
  351. //
  352. if (groveler_statuses != 0 && grovelers != 0)
  353. {
  354. for (int index = 0; index < num_partitions; index++)
  355. {
  356. if (groveler_statuses[index] != Grovel_disable)
  357. {
  358. grovelers[index].close();
  359. }
  360. }
  361. }
  362. //
  363. // Delete all objects that were allocated.
  364. //
  365. if (groveler_statuses != 0)
  366. {
  367. delete[] groveler_statuses;
  368. groveler_statuses = 0;
  369. }
  370. if (grovelers != 0)
  371. {
  372. delete[] grovelers;
  373. grovelers = 0;
  374. }
  375. if (read_disk_info != 0)
  376. {
  377. for (int index = 0; index < num_partitions; index++)
  378. {
  379. if (read_disk_info[index] != 0)
  380. {
  381. delete read_disk_info[index];
  382. read_disk_info[index] = 0;
  383. }
  384. }
  385. delete[] read_disk_info;
  386. read_disk_info = 0;
  387. }
  388. if (write_disk_info != 0)
  389. {
  390. for (int index = 0; index < num_partitions; index++)
  391. {
  392. if (write_disk_info[index] != 0)
  393. {
  394. delete write_disk_info[index];
  395. write_disk_info[index] = 0;
  396. }
  397. }
  398. delete[] write_disk_info;
  399. write_disk_info = 0;
  400. }
  401. if (controller != 0)
  402. {
  403. delete controller;
  404. controller = 0;
  405. }
  406. if (shared_data != 0)
  407. {
  408. delete shared_data;
  409. shared_data = 0;
  410. }
  411. if (log_drive != 0)
  412. {
  413. delete log_drive;
  414. log_drive = 0;
  415. }
  416. eventlog.report_event(GROVMSG_SERVICE_STOPPED, 0);
  417. return exit_code;
  418. }