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.

374 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. bootstatus.c
  5. Abstract:
  6. This module contains the code for manipulating the boot status file.
  7. The boot status file has some odd requirements and needs to be accessed/
  8. modified both by kernel and user-mode code.
  9. --*/
  10. #include "ntrtlp.h"
  11. // #include <nt.h>
  12. // #include <ntrtl.h>
  13. // #include <zwapi.h>
  14. #define BSD_UNICODE 1
  15. #include "bootstatus.h"
  16. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  17. #pragma alloc_text(PAGE,RtlLockBootStatusData)
  18. #pragma alloc_text(PAGE,RtlUnlockBootStatusData)
  19. #pragma alloc_text(PAGE,RtlGetSetBootStatusData)
  20. #pragma alloc_text(PAGE,RtlCreateBootStatusDataFile)
  21. #endif
  22. #define MYTAG 'fdsb' // bsdf
  23. NTSTATUS
  24. RtlLockBootStatusData(
  25. OUT PHANDLE BootStatusDataHandle
  26. )
  27. {
  28. OBJECT_ATTRIBUTES objectAttributes;
  29. WCHAR fileNameBuffer[MAXIMUM_FILENAME_LENGTH+1];
  30. UNICODE_STRING fileName;
  31. HANDLE dataFileHandle;
  32. IO_STATUS_BLOCK ioStatusBlock;
  33. NTSTATUS status;
  34. wcsncpy(fileNameBuffer, L"\\SystemRoot", MAXIMUM_FILENAME_LENGTH);
  35. wcsncat(fileNameBuffer,
  36. BSD_FILE_NAME,
  37. MAXIMUM_FILENAME_LENGTH - wcslen(fileNameBuffer));
  38. RtlInitUnicodeString(&fileName, fileNameBuffer);
  39. InitializeObjectAttributes(&objectAttributes,
  40. &fileName,
  41. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  42. NULL,
  43. NULL);
  44. status = ZwOpenFile(&dataFileHandle,
  45. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  46. &objectAttributes,
  47. &ioStatusBlock,
  48. 0,
  49. FILE_SYNCHRONOUS_IO_NONALERT);
  50. ASSERT(status != STATUS_PENDING);
  51. if(NT_SUCCESS(status)) {
  52. *BootStatusDataHandle = dataFileHandle;
  53. } else {
  54. *BootStatusDataHandle = NULL;
  55. }
  56. return status;
  57. }
  58. VOID
  59. RtlUnlockBootStatusData(
  60. IN HANDLE BootStatusDataHandle
  61. )
  62. {
  63. IO_STATUS_BLOCK ioStatusBlock;
  64. USHORT i = COMPRESSION_FORMAT_NONE;
  65. NTSTATUS status;
  66. //
  67. // Decompress the data file. If the file is not already compressed then
  68. // this should be a very lightweight operation (so say the FS guys).
  69. //
  70. // On the other hand if the file is compressed then the boot loader will
  71. // be unable to write to it and auto-recovery is effectively disabled.
  72. //
  73. status = ZwFsControlFile(
  74. BootStatusDataHandle,
  75. NULL,
  76. NULL,
  77. NULL,
  78. &ioStatusBlock,
  79. FSCTL_SET_COMPRESSION,
  80. &i,
  81. sizeof(USHORT),
  82. NULL,
  83. 0
  84. );
  85. ASSERT(status != STATUS_PENDING);
  86. status = ZwFlushBuffersFile(BootStatusDataHandle, &ioStatusBlock);
  87. ASSERT(status != STATUS_PENDING);
  88. ZwClose(BootStatusDataHandle);
  89. return;
  90. }
  91. #define FIELD_SIZE(type, field) sizeof(((type *)0)->field)
  92. #define FIELD_OFFSET_AND_SIZE(n) {FIELD_OFFSET(BSD_BOOT_STATUS_DATA, n), FIELD_SIZE(BSD_BOOT_STATUS_DATA, n)}
  93. NTSTATUS
  94. RtlGetSetBootStatusData(
  95. IN HANDLE Handle,
  96. IN BOOLEAN Get,
  97. IN RTL_BSD_ITEM_TYPE DataItem,
  98. IN PVOID DataBuffer,
  99. IN ULONG DataBufferLength,
  100. OUT PULONG BytesReturned OPTIONAL
  101. )
  102. {
  103. struct {
  104. ULONG FieldOffset;
  105. ULONG FieldLength;
  106. } bootStatusFields[] = {
  107. FIELD_OFFSET_AND_SIZE(Version),
  108. FIELD_OFFSET_AND_SIZE(ProductType),
  109. FIELD_OFFSET_AND_SIZE(AutoAdvancedBoot),
  110. FIELD_OFFSET_AND_SIZE(AdvancedBootMenuTimeout),
  111. FIELD_OFFSET_AND_SIZE(LastBootSucceeded),
  112. FIELD_OFFSET_AND_SIZE(LastBootShutdown)
  113. };
  114. LARGE_INTEGER fileOffset;
  115. ULONG dataFileVersion;
  116. ULONG itemLength;
  117. ULONG bytesRead;
  118. IO_STATUS_BLOCK ioStatusBlock;
  119. NTSTATUS status;
  120. ASSERT(RtlBsdItemMax == (sizeof(bootStatusFields) / sizeof(bootStatusFields[0])));
  121. //
  122. // Read the version number out of the data file.
  123. //
  124. fileOffset.QuadPart = 0;
  125. status = ZwReadFile(Handle,
  126. NULL,
  127. NULL,
  128. NULL,
  129. &ioStatusBlock,
  130. &dataFileVersion,
  131. sizeof(ULONG),
  132. &fileOffset,
  133. NULL);
  134. ASSERT(status != STATUS_PENDING);
  135. if(!NT_SUCCESS(status)) {
  136. return status;
  137. }
  138. //
  139. // If the data item requsted isn't one we have code to handle then
  140. // return invalid parameter.
  141. //
  142. if(DataItem >= (sizeof(bootStatusFields) / sizeof(bootStatusFields[0]))) {
  143. return STATUS_INVALID_PARAMETER;
  144. }
  145. fileOffset.QuadPart = bootStatusFields[DataItem].FieldOffset;
  146. itemLength = bootStatusFields[DataItem].FieldLength;
  147. //
  148. // If the data item offset is beyond the end of the file then return a
  149. // versioning error.
  150. //
  151. if((fileOffset.QuadPart + itemLength) > dataFileVersion) {
  152. return STATUS_REVISION_MISMATCH;
  153. }
  154. if(DataBufferLength < itemLength) {
  155. DataBufferLength = itemLength;
  156. return STATUS_BUFFER_TOO_SMALL;
  157. }
  158. if(Get) {
  159. status = ZwReadFile(Handle,
  160. NULL,
  161. NULL,
  162. NULL,
  163. &ioStatusBlock,
  164. DataBuffer,
  165. itemLength,
  166. &fileOffset,
  167. NULL);
  168. } else {
  169. status = ZwWriteFile(Handle,
  170. NULL,
  171. NULL,
  172. NULL,
  173. &ioStatusBlock,
  174. DataBuffer,
  175. itemLength,
  176. &fileOffset,
  177. NULL);
  178. }
  179. ASSERT(status != STATUS_PENDING);
  180. if(NT_SUCCESS(status) && ARGUMENT_PRESENT(BytesReturned)) {
  181. *BytesReturned = (ULONG) ioStatusBlock.Information;
  182. }
  183. return status;
  184. }
  185. NTSTATUS
  186. RtlCreateBootStatusDataFile(
  187. VOID
  188. )
  189. {
  190. OBJECT_ATTRIBUTES objectAttributes;
  191. WCHAR fileNameBuffer[MAXIMUM_FILENAME_LENGTH+1];
  192. UNICODE_STRING fileName;
  193. HANDLE dataFileHandle;
  194. IO_STATUS_BLOCK ioStatusBlock;
  195. LARGE_INTEGER t;
  196. UCHAR zero = 0;
  197. BSD_BOOT_STATUS_DATA defaultValues;
  198. NTSTATUS status;
  199. wcsncpy(fileNameBuffer, L"\\SystemRoot", MAXIMUM_FILENAME_LENGTH);
  200. wcsncat(fileNameBuffer,
  201. BSD_FILE_NAME,
  202. MAXIMUM_FILENAME_LENGTH - wcslen(fileNameBuffer));
  203. RtlInitUnicodeString(&fileName, fileNameBuffer);
  204. InitializeObjectAttributes(&objectAttributes,
  205. &fileName,
  206. OBJ_CASE_INSENSITIVE,
  207. NULL,
  208. NULL);
  209. //
  210. // The file must be large enough that it doesn't reside in the MFT entry
  211. // or the loader won't be able to write to it.
  212. //
  213. t.QuadPart = 2048;
  214. //
  215. // Create the file.
  216. //
  217. status = ZwCreateFile(&dataFileHandle,
  218. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  219. &objectAttributes,
  220. &(ioStatusBlock),
  221. &t,
  222. FILE_ATTRIBUTE_SYSTEM,
  223. 0,
  224. FILE_CREATE,
  225. FILE_SYNCHRONOUS_IO_NONALERT,
  226. NULL,
  227. 0);
  228. ASSERT(status != STATUS_PENDING);
  229. if(!NT_SUCCESS(status)) {
  230. return status;
  231. }
  232. //
  233. // Write a single zero byte to the 0x7ffth byte in the file to make
  234. // sure that 2k are actually allocated. This is to ensure that the
  235. // file will not become attribute resident even after a conversion
  236. // from FAT to NTFS.
  237. //
  238. t.QuadPart = t.QuadPart - 1;
  239. status = ZwWriteFile(dataFileHandle,
  240. NULL,
  241. NULL,
  242. NULL,
  243. &ioStatusBlock,
  244. &zero,
  245. 1,
  246. &t,
  247. NULL);
  248. ASSERT(status != STATUS_PENDING);
  249. if(!NT_SUCCESS(status)) {
  250. goto CreateDone;
  251. }
  252. //
  253. // Now write out the default values to the beginning of the file.
  254. //
  255. defaultValues.Version = sizeof(BSD_BOOT_STATUS_DATA);
  256. RtlGetNtProductType(&(defaultValues.ProductType));
  257. defaultValues.AutoAdvancedBoot = FALSE;
  258. defaultValues.AdvancedBootMenuTimeout = 30;
  259. defaultValues.LastBootSucceeded = TRUE;
  260. defaultValues.LastBootShutdown = FALSE;
  261. t.QuadPart = 0;
  262. status = ZwWriteFile(dataFileHandle,
  263. NULL,
  264. NULL,
  265. NULL,
  266. &ioStatusBlock,
  267. &defaultValues,
  268. sizeof(BSD_BOOT_STATUS_DATA),
  269. &t,
  270. NULL);
  271. ASSERT(status != STATUS_PENDING);
  272. if(!NT_SUCCESS(status)) {
  273. //
  274. // The data file was created and we can assume the contents were zeroed
  275. // even if we couldn't write out the defaults. Since this wouldn't
  276. // enable auto-advanced boot we'll leave the data file in place with
  277. // its zeroed contents.
  278. //
  279. }
  280. CreateDone:
  281. ZwClose(dataFileHandle);
  282. return status;
  283. }