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.

624 lines
18 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. sbentry.c
  5. Abstract:
  6. Contains the OS boot entry and boot options
  7. abstraction implementation.
  8. Author:
  9. Vijay Jayaseelan (vijayj@microsoft.com) 14 Feb 2001
  10. Revision History:
  11. None.
  12. --*/
  13. #include <sbentry.h>
  14. #include <stdio.h>
  15. SBEMemAllocateRoutine AllocRoutine = NULL;
  16. SBEMemFreeRoutine FreeRoutine = NULL;
  17. //
  18. // OS_BOOT_ENTRY Methods
  19. //
  20. PCWSTR
  21. OSBEAddOsLoadOption(
  22. IN POS_BOOT_ENTRY This,
  23. IN PCWSTR BootOption
  24. )
  25. {
  26. PWSTR Option = NULL;
  27. WCHAR Buffer[MAX_PATH];
  28. if (This && BootOption) {
  29. ULONG Length;
  30. wcscpy(Buffer, BootOption);
  31. _wcsupr(Buffer);
  32. Length = wcslen(Buffer);
  33. if (Length) {
  34. //
  35. // Add a space at the end if required
  36. //
  37. if ((Length < ARRAY_SIZE(Buffer)) && (Buffer[Length - 1] != L' ')) {
  38. Buffer[Length] = L' ';
  39. Buffer[Length + 1] = UNICODE_NULL;
  40. Length++;
  41. }
  42. if ((!wcsstr(This->OsLoadOptions, Buffer)) &&
  43. ((wcslen(This->OsLoadOptions) + Length) < MAX_PATH)) {
  44. wcscat(This->OsLoadOptions, Buffer);
  45. Option = This->OsLoadOptions;
  46. }
  47. OSBE_SET_DIRTY(This);
  48. OSBO_SET_DIRTY(This->BootOptions);
  49. }
  50. }
  51. return Option;
  52. }
  53. PCWSTR
  54. OSBERemoveOsLoadOption(
  55. IN POS_BOOT_ENTRY This,
  56. IN PCWSTR BootOption
  57. )
  58. {
  59. PWSTR Option = NULL;
  60. WCHAR Buffer[MAX_PATH];
  61. if (This && BootOption) {
  62. ULONG Length;
  63. wcscpy(Buffer, BootOption);
  64. _wcsupr(Buffer);
  65. Length = wcslen(Buffer);
  66. if (Length) {
  67. PWSTR OldOption;
  68. if ((Length < ARRAY_SIZE(Buffer)) && (Buffer[Length - 1] != L' ')) {
  69. Buffer[Length] = L' ';
  70. Buffer[Length + 1] = UNICODE_NULL;
  71. Length++;
  72. }
  73. OldOption = wcsstr(This->OsLoadOptions, Buffer);
  74. if (OldOption) {
  75. PWSTR NextToken = wcschr(OldOption + 1, L'/');
  76. if (NextToken) {
  77. wcscpy(OldOption, NextToken);
  78. } else {
  79. *OldOption = UNICODE_NULL;
  80. }
  81. Option = This->OsLoadOptions;
  82. OSBE_SET_DIRTY(This);
  83. OSBO_SET_DIRTY(This->BootOptions);
  84. }
  85. }
  86. }
  87. return Option;
  88. }
  89. BOOLEAN
  90. OSBEIsOsLoadOptionPresent(
  91. IN POS_BOOT_ENTRY This,
  92. IN PCWSTR BootOption
  93. )
  94. {
  95. BOOLEAN Result = FALSE;
  96. WCHAR Buffer[MAX_PATH];
  97. if (This && BootOption) {
  98. ULONG Length;
  99. wcscpy(Buffer, BootOption);
  100. _wcsupr(Buffer);
  101. Length = wcslen(Buffer);
  102. if (Length) {
  103. if ((Length < ARRAY_SIZE(Buffer)) && (Buffer[Length - 1] != L' ')) {
  104. Buffer[Length] = L' ';
  105. Buffer[Length + 1] = UNICODE_NULL;
  106. Length++;
  107. }
  108. Result = wcsstr(This->OsLoadOptions, Buffer) ? TRUE : FALSE;
  109. }
  110. }
  111. return Result;
  112. }
  113. //
  114. // OS_BOOT_OPTIONS Methods
  115. //
  116. POS_BOOT_ENTRY
  117. OSBOFindBootEntry(
  118. IN POS_BOOT_OPTIONS This,
  119. IN ULONG Id
  120. )
  121. {
  122. POS_BOOT_ENTRY Entry = NULL;
  123. if (This) {
  124. for (Entry = This->BootEntries; Entry; Entry = Entry->NextEntry) {
  125. if (Entry->Id == Id) {
  126. break; // found the required entry
  127. }
  128. }
  129. }
  130. return Entry;
  131. }
  132. ULONG
  133. OSBOFindBootEntryOrder(
  134. IN POS_BOOT_OPTIONS This,
  135. IN ULONG Id
  136. )
  137. {
  138. ULONG Index = -1;
  139. if (This) {
  140. ULONG EntryIndex;
  141. for (EntryIndex = 0;
  142. EntryIndex < OSBOGetOrderedBootEntryCount(This);
  143. EntryIndex++) {
  144. if (This->BootOrder[EntryIndex] == Id) {
  145. Index = EntryIndex;
  146. break; // found the required entry
  147. }
  148. }
  149. }
  150. return Index;
  151. }
  152. BOOLEAN
  153. OSBODeleteBootEntry(
  154. IN POS_BOOT_OPTIONS This,
  155. IN POS_BOOT_ENTRY BootEntry
  156. )
  157. {
  158. BOOLEAN Result = FALSE;
  159. if (This && BootEntry) {
  160. POS_BOOT_ENTRY CurrEntry = NULL;
  161. POS_BOOT_ENTRY PrevEntry = NULL;
  162. for (CurrEntry = This->BootEntries;
  163. CurrEntry != BootEntry;
  164. PrevEntry = CurrEntry, CurrEntry = CurrEntry->NextEntry) {
  165. // do nothing
  166. }
  167. if (CurrEntry) {
  168. ULONG Order;
  169. POS_BOOT_ENTRY OrderedEntry;
  170. //
  171. // Set the required attributes
  172. //
  173. OSBE_SET_DELETED(BootEntry);
  174. OSBE_SET_DIRTY(BootEntry);
  175. OSBO_SET_DIRTY(This);
  176. //
  177. // Flush the changes
  178. //
  179. Result = OSBEFlush(BootEntry);
  180. if (Result) {
  181. //
  182. // Remove references to the entries
  183. //
  184. if (PrevEntry) {
  185. PrevEntry->NextEntry = BootEntry->NextEntry;
  186. } else {
  187. This->BootEntries = BootEntry->NextEntry;
  188. }
  189. if (This->EntryCount) {
  190. This->EntryCount--;
  191. }
  192. //
  193. // if this entry was ordered then remove
  194. // reference from the order too
  195. //
  196. Order = OSBOFindBootEntryOrder(This, OSBEGetId(BootEntry));
  197. if (Order != (-1)) {
  198. ULONG OrderCount = OSBOGetOrderedBootEntryCount(This);
  199. OrderCount--;
  200. if (OrderCount) {
  201. PULONG NewOrder = SBE_MALLOC(OrderCount * sizeof(ULONG));
  202. if (NewOrder) {
  203. //
  204. // copy entries before the current entry
  205. //
  206. memcpy(NewOrder, This->BootOrder, Order * sizeof(ULONG));
  207. //
  208. // copy entries after the current entry
  209. //
  210. memcpy(NewOrder + Order, This->BootOrder + Order + 1,
  211. (OrderCount - Order) * sizeof(ULONG));
  212. SBE_FREE(This->BootOrder);
  213. This->BootOrder = NewOrder;
  214. This->BootOrderCount = OrderCount;
  215. Result = TRUE;
  216. } else {
  217. Result = FALSE;
  218. }
  219. } else {
  220. SBE_FREE(This->BootOrder);
  221. This->BootOrder = NULL;
  222. This->BootOrderCount = 0;
  223. }
  224. }
  225. if (BootEntry == OSBOGetActiveBootEntry(This)) {
  226. ULONG Index;
  227. //
  228. // Update the active boot entry and the next boot entry
  229. //
  230. This->CurrentEntry = NULL;
  231. Index = OSBOGetBootEntryIdByOrder(This, 0);
  232. if (Index != (-1)) {
  233. This->CurrentEntry = OSBOFindBootEntry(This, Index);
  234. }
  235. }
  236. //
  237. // Since we updated some state mark it dirty
  238. //
  239. OSBO_SET_DIRTY(This);
  240. OSBEDelete(BootEntry);
  241. }
  242. }
  243. }
  244. return Result;
  245. }
  246. POS_BOOT_ENTRY
  247. OSBOSetActiveBootEntry(
  248. IN POS_BOOT_OPTIONS This,
  249. IN POS_BOOT_ENTRY BootEntry
  250. )
  251. {
  252. POS_BOOT_ENTRY OldActiveEntry = NULL;
  253. if (This && BootEntry) {
  254. ULONG OrderCount = OSBOGetOrderedBootEntryCount(This);
  255. OldActiveEntry = OSBOGetActiveBootEntry(This);
  256. if ((OrderCount > 0) && (OldActiveEntry != BootEntry)) {
  257. ULONG Index;
  258. ULONG ActiveIndex = OSBOFindBootEntryOrder(This,
  259. OSBEGetId(BootEntry));
  260. //
  261. // If the entry is already present in the boot order
  262. // and move it to the start of the list
  263. //
  264. if (ActiveIndex != (-1)) {
  265. for (Index = ActiveIndex; Index; Index--) {
  266. This->BootOrder[Index] = This->BootOrder[Index - 1];
  267. }
  268. This->BootOrder[0] = BootEntry->Id;
  269. } else {
  270. //
  271. // This is a new entry in ordered list. Grow the ordered boot
  272. // entry list with this new entry at the start
  273. //
  274. PULONG NewBootOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
  275. memcpy(NewBootOrder + 1, This->BootOrder, sizeof(ULONG) * OrderCount);
  276. NewBootOrder[0] = BootEntry->Id;
  277. SBE_FREE(This->BootOrder);
  278. This->BootOrder = NewBootOrder;
  279. }
  280. //
  281. // Update the active boot entry and the next boot entry
  282. //
  283. This->CurrentEntry = NULL;
  284. Index = OSBOGetBootEntryIdByOrder(This, 0);
  285. if (Index != (-1)) {
  286. This->CurrentEntry = OSBOFindBootEntry(This, Index);
  287. }
  288. //
  289. // Since we updated some state mark it dirty
  290. //
  291. OSBO_SET_DIRTY(This);
  292. }
  293. }
  294. return OldActiveEntry;
  295. }
  296. POS_BOOT_ENTRY
  297. OSBOGetFirstBootEntry(
  298. IN POS_BOOT_OPTIONS This,
  299. IN OUT PULONG Index
  300. )
  301. {
  302. POS_BOOT_ENTRY Entry = NULL;
  303. if (This && Index) {
  304. *Index = 0;
  305. Entry = OSBOGetNextBootEntry(This, Index);
  306. }
  307. return Entry;
  308. }
  309. POS_BOOT_ENTRY
  310. OSBOGetNextBootEntry(
  311. IN POS_BOOT_OPTIONS This,
  312. IN PULONG Index
  313. )
  314. {
  315. POS_BOOT_ENTRY Entry = NULL;
  316. //
  317. // TBD : Might want to optimize this, since
  318. // each boot entry now has a pointer to the next
  319. // boot entry
  320. //
  321. if (This && Index) {
  322. ULONG Count = *Index;
  323. POS_BOOT_ENTRY CurrEntry;
  324. for (CurrEntry = This->BootEntries;
  325. CurrEntry;
  326. CurrEntry = CurrEntry->NextEntry, Count--) {
  327. if (!Count) {
  328. Entry = CurrEntry;
  329. (*Index)++;
  330. break;
  331. }
  332. }
  333. }
  334. return Entry;
  335. }
  336. ULONG
  337. OSBOFindDriverEntryOrder(
  338. IN POS_BOOT_OPTIONS This,
  339. IN ULONG Id
  340. )
  341. {
  342. ULONG Index = -1;
  343. if (This) {
  344. ULONG EntryIndex;
  345. for (EntryIndex = 0;
  346. EntryIndex < OSBOGetOrderedDriverEntryCount(This);
  347. EntryIndex++) {
  348. if (This->DriverEntryOrder[EntryIndex] == Id) {
  349. Index = EntryIndex;
  350. break; // found the required entry
  351. }
  352. }
  353. }
  354. return Index;
  355. }
  356. PDRIVER_ENTRY
  357. OSBOFindDriverEntryById(
  358. IN POS_BOOT_OPTIONS This,
  359. IN ULONG Id
  360. )
  361. {
  362. PDRIVER_ENTRY Entry = NULL;
  363. if (This) {
  364. for (Entry = This->DriverEntries;
  365. Entry;
  366. Entry = OSBOGetNextDriverEntry(This, Entry)) {
  367. if (Entry->Id == Id) {
  368. break; // found the required entry
  369. }
  370. }
  371. }
  372. return Entry;
  373. }
  374. PDRIVER_ENTRY
  375. OSBOFindDriverEntryByName(
  376. IN POS_BOOT_OPTIONS This,
  377. IN PCWSTR DriverName
  378. )
  379. /*++
  380. Finds matching driver entry by driver file name.
  381. --*/
  382. {
  383. PDRIVER_ENTRY CurrentDriverEntry = NULL;
  384. if (This && DriverName && DriverName[0] != UNICODE_NULL){
  385. CurrentDriverEntry = This->DriverEntries;
  386. while (CurrentDriverEntry){
  387. if (!_wcsicmp(CurrentDriverEntry->FileName ,DriverName)){
  388. break;
  389. }
  390. CurrentDriverEntry = OSBOGetNextDriverEntry(This, CurrentDriverEntry);
  391. }
  392. }
  393. return (CurrentDriverEntry);
  394. }
  395. BOOLEAN
  396. OSBODeleteDriverEntry(
  397. IN POS_BOOT_OPTIONS This,
  398. IN ULONG Id
  399. )
  400. /*++
  401. Description:
  402. Used to delete a driver entry. Calls Flush to flush the entry out.
  403. Parameters:
  404. This - Pointer to OS boot options structure.
  405. Id - Id for the drivr entry to be deleted.
  406. Return Value:
  407. TRUE if successful else FALSE.
  408. --*/
  409. {
  410. BOOLEAN Result = FALSE;
  411. if (This){
  412. //
  413. // Look up for the driver entry that has this ID set and mark it to
  414. // be deleted. Then Flush it.
  415. //
  416. PDRIVER_ENTRY CurrentEntry = This->DriverEntries;
  417. PDRIVER_ENTRY PreviousEntry = NULL;
  418. while (CurrentEntry){
  419. if (Id == CurrentEntry->Id){
  420. DRIVERENT_SET_DIRTY(CurrentEntry);
  421. DRIVERENT_SET_DELETED(CurrentEntry);
  422. OSBO_SET_DIRTY(This);
  423. //
  424. // Flush The data.
  425. //
  426. Result = OSDriverEntryFlush(CurrentEntry);
  427. if (Result){
  428. ULONG Order;
  429. //
  430. //Remove it out of the Driver List.
  431. //
  432. if (NULL == PreviousEntry){
  433. This->DriverEntries = OSBOGetNextDriverEntry(This,CurrentEntry);
  434. } else {
  435. PreviousEntry->NextEntry = OSBOGetNextDriverEntry(This, CurrentEntry);
  436. }
  437. if (This->DriverEntryCount) {
  438. This->DriverEntryCount--;
  439. }
  440. //
  441. // if this entry was ordered then remove
  442. // reference from the order too
  443. //
  444. Order = OSBOFindDriverEntryOrder(This, OSDriverGetId(CurrentEntry));
  445. if (Order != (-1)) {
  446. ULONG OrderCount = OSBOGetOrderedDriverEntryCount(This);
  447. OrderCount--;
  448. if (OrderCount) {
  449. PULONG NewOrder = SBE_MALLOC(OrderCount * sizeof(ULONG));
  450. if (NewOrder) {
  451. //
  452. // copy entries before the current entry
  453. //
  454. memcpy(NewOrder, This->DriverEntryOrder, Order * sizeof(ULONG));
  455. //
  456. // copy entries after the current entry
  457. //
  458. memcpy(NewOrder + Order, This->DriverEntryOrder + Order + 1,
  459. (OrderCount - Order) * sizeof(ULONG));
  460. SBE_FREE(This->DriverEntryOrder);
  461. This->DriverEntryOrder = NewOrder;
  462. This->DriverEntryOrderCount = OrderCount;
  463. Result = TRUE;
  464. } else {
  465. Result = FALSE;
  466. }
  467. } else {
  468. SBE_FREE(This->DriverEntryOrder);
  469. This->DriverEntryOrder = NULL;
  470. This->DriverEntryOrderCount = 0;
  471. }
  472. }
  473. SBE_FREE(CurrentEntry);
  474. //
  475. // Since we updated some state mark it dirty
  476. //
  477. OSBO_SET_DIRTY(This);
  478. }
  479. //
  480. // As we make sure that ID's are unique we can break and not process any more.
  481. //
  482. break;
  483. }
  484. PreviousEntry = CurrentEntry;
  485. CurrentEntry = OSBOGetNextDriverEntry(This, CurrentEntry);
  486. }
  487. }
  488. return Result;
  489. }