disk.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. disk.c
  9. Abstract:
  10. This module implements support for working with the disk directly in
  11. the setup app.
  12. Author:
  13. Evan Green 11-Apr-2014
  14. Environment:
  15. User
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <getopt.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include "setup.h"
  29. #include "sconf.h"
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // Define the boot partition size in blocks.
  35. //
  36. #define SETUP_BOOT_PARTITION_SIZE ((_1MB * 10) / SETUP_BLOCK_SIZE)
  37. //
  38. // Define the amount to clear of the beginning of each partition.
  39. //
  40. #define SETUP_PARTITION_CLEAR_SIZE (1024 * 16)
  41. //
  42. // ------------------------------------------------------ Data Type Definitions
  43. //
  44. //
  45. // ----------------------------------------------- Internal Function Prototypes
  46. //
  47. PVOID
  48. SetupPartitionLibraryAllocate (
  49. UINTN Size
  50. );
  51. VOID
  52. SetupPartitionLibraryFree (
  53. PVOID Memory
  54. );
  55. KSTATUS
  56. SetupPartitionLibraryRead (
  57. PPARTITION_CONTEXT Context,
  58. ULONGLONG BlockAddress,
  59. PVOID Buffer
  60. );
  61. KSTATUS
  62. SetupPartitionLibraryWrite (
  63. PPARTITION_CONTEXT Context,
  64. ULONGLONG BlockAddress,
  65. PVOID Buffer
  66. );
  67. VOID
  68. SetupPartitionLibraryFillRandom (
  69. PPARTITION_CONTEXT Context,
  70. PUCHAR Buffer,
  71. ULONG BufferSize
  72. );
  73. //
  74. // -------------------------------------------------------------------- Globals
  75. //
  76. //
  77. // ------------------------------------------------------------------ Functions
  78. //
  79. INT
  80. SetupFormatDisk (
  81. PSETUP_CONTEXT Context
  82. )
  83. /*++
  84. Routine Description:
  85. This routine partitions a disk.
  86. Arguments:
  87. Context - Supplies a pointer to the application context.
  88. Return Value:
  89. 0 on success.
  90. Non-zero on failure.
  91. --*/
  92. {
  93. UINTN AllocationSize;
  94. ULONGLONG BlockCount;
  95. ULONG BlockIndex;
  96. ULONGLONG BlockOffset;
  97. PSETUP_DISK_CONFIGURATION DiskConfiguration;
  98. ULONGLONG FreeSize;
  99. PSETUP_PARTITION_CONFIGURATION PartitionConfig;
  100. PPARTITION_CONTEXT PartitionContext;
  101. ULONG PartitionCount;
  102. ULONG PartitionDataStart;
  103. ULONG PartitionIndex;
  104. PPARTITION_INFORMATION PartitionInfo;
  105. PPARTITION_INFORMATION Partitions;
  106. INT Result;
  107. ULONGLONG Size;
  108. ULONG SplitCount;
  109. ULONGLONG Start;
  110. KSTATUS Status;
  111. ULONG SystemIndex;
  112. PVOID ZeroBuffer;
  113. assert((Context->Disk == NULL) && (Context->DiskPath != NULL));
  114. DiskConfiguration = &(Context->Configuration->Disk);
  115. Partitions = NULL;
  116. ZeroBuffer = NULL;
  117. //
  118. // Open up the disk.
  119. //
  120. Context->Disk = SetupOpenDestination(Context->DiskPath,
  121. O_CREAT | O_RDWR,
  122. 0664);
  123. if (Context->Disk == NULL) {
  124. printf("Error: Failed to open ");
  125. SetupPrintDestination(Context->DiskPath);
  126. Result = errno;
  127. if (errno == 0) {
  128. Result = -1;
  129. }
  130. printf(": %s\n", strerror(Result));
  131. return Result;
  132. }
  133. //
  134. // Set up the partition context.
  135. //
  136. PartitionContext = &(Context->PartitionContext);
  137. PartitionContext->AllocateFunction = SetupPartitionLibraryAllocate;
  138. PartitionContext->FreeFunction = SetupPartitionLibraryFree;
  139. PartitionContext->ReadFunction = SetupPartitionLibraryRead;
  140. PartitionContext->WriteFunction = SetupPartitionLibraryWrite;
  141. PartitionContext->FillRandomFunction = SetupPartitionLibraryFillRandom;
  142. PartitionContext->BlockSize = SETUP_BLOCK_SIZE;
  143. Result = SetupFstat(Context->Disk,
  144. &(PartitionContext->BlockCount),
  145. NULL,
  146. NULL);
  147. if (Result != 0) {
  148. goto FormatDiskEnd;
  149. }
  150. //
  151. // Use the override if one was specified.
  152. //
  153. if (Context->DiskSize != 0) {
  154. PartitionContext->BlockCount = Context->DiskSize;
  155. }
  156. PartitionContext->BlockCount /= SETUP_BLOCK_SIZE;
  157. if (PartitionContext->BlockCount == 0) {
  158. fprintf(stderr, "Error: Disk has zero size.\n");
  159. Result = ERANGE;
  160. goto FormatDiskEnd;
  161. }
  162. PartitionContext->Format = DiskConfiguration->PartitionFormat;
  163. Status = PartInitialize(PartitionContext);
  164. if (!KSUCCESS(Status)) {
  165. fprintf(stderr,
  166. "Error: Failed to initialize partition library: %d\n",
  167. Status);
  168. Result = -1;
  169. goto FormatDiskEnd;
  170. }
  171. //
  172. // Initialize the partition layout.
  173. //
  174. switch (PartitionContext->Format) {
  175. case PartitionFormatNone:
  176. PartitionDataStart = 0;
  177. break;
  178. case PartitionFormatMbr:
  179. PartitionDataStart = 1;
  180. break;
  181. case PartitionFormatGpt:
  182. PartitionDataStart = 41;
  183. break;
  184. default:
  185. assert(FALSE);
  186. Result = EINVAL;
  187. goto FormatDiskEnd;
  188. }
  189. AllocationSize = sizeof(PARTITION_INFORMATION) *
  190. DiskConfiguration->PartitionCount;
  191. Partitions = malloc(AllocationSize);
  192. if (Partitions == NULL) {
  193. Result = ENOMEM;
  194. goto FormatDiskEnd;
  195. }
  196. memset(Partitions, 0, AllocationSize);
  197. //
  198. // Go through once to calculate the main partition size and how many
  199. // partitions to split it between.
  200. //
  201. BlockOffset = PartitionDataStart;
  202. SplitCount = 0;
  203. for (PartitionIndex = 0;
  204. PartitionIndex < DiskConfiguration->PartitionCount;
  205. PartitionIndex += 1) {
  206. PartitionConfig = &(DiskConfiguration->Partitions[PartitionIndex]);
  207. Start = BlockOffset;
  208. if (PartitionConfig->Alignment > SETUP_BLOCK_SIZE) {
  209. Start =
  210. ALIGN_RANGE_UP(BlockOffset,
  211. PartitionConfig->Alignment / SETUP_BLOCK_SIZE);
  212. }
  213. BlockOffset = Start;
  214. if (PartitionConfig->Size == -1ULL) {
  215. SplitCount += 1;
  216. continue;
  217. }
  218. Size = ALIGN_RANGE_UP(PartitionConfig->Size, SETUP_BLOCK_SIZE) /
  219. SETUP_BLOCK_SIZE;
  220. BlockOffset += Size;
  221. }
  222. if (BlockOffset > PartitionContext->BlockCount) {
  223. fprintf(stderr,
  224. "Error: Partition specification goes out to block 0x%llx, "
  225. "but disk size is only 0x%llx.\n",
  226. BlockOffset,
  227. PartitionContext->BlockCount);
  228. Result = ERANGE;
  229. goto FormatDiskEnd;
  230. }
  231. assert(BlockOffset <= PartitionContext->BlockCount);
  232. FreeSize = PartitionContext->BlockCount - BlockOffset;
  233. if (PartitionContext->Format == PartitionFormatGpt) {
  234. if (FreeSize < 40) {
  235. fprintf(stderr, "Error: Disk too small for GPT footer.\n");
  236. Result = ERANGE;
  237. goto FormatDiskEnd;
  238. }
  239. FreeSize -= 40;
  240. }
  241. if (SplitCount > 1) {
  242. FreeSize /= SplitCount;
  243. }
  244. //
  245. // Initialize the partition structures.
  246. //
  247. PartitionCount = DiskConfiguration->PartitionCount;
  248. SystemIndex = PartitionCount;
  249. BlockOffset = PartitionDataStart;
  250. for (PartitionIndex = 0;
  251. PartitionIndex < DiskConfiguration->PartitionCount;
  252. PartitionIndex += 1) {
  253. PartitionInfo = &(Partitions[PartitionIndex]);
  254. PartitionConfig = &(DiskConfiguration->Partitions[PartitionIndex]);
  255. Start = BlockOffset;
  256. if (PartitionConfig->Alignment > SETUP_BLOCK_SIZE) {
  257. Start =
  258. ALIGN_RANGE_UP(BlockOffset,
  259. PartitionConfig->Alignment / SETUP_BLOCK_SIZE);
  260. }
  261. PartitionInfo->StartOffset = Start;
  262. PartitionConfig->Offset = Start * SETUP_BLOCK_SIZE;
  263. //
  264. // If the partition size is -1, use as much space as is available.
  265. // Watch out for differences due to alignment requirements between
  266. // this loop and the earlier one.
  267. //
  268. if (PartitionConfig->Size == -1ULL) {
  269. if (FreeSize > PartitionContext->BlockCount) {
  270. Size = PartitionContext->BlockCount - Start;
  271. } else {
  272. Size = FreeSize;
  273. }
  274. } else {
  275. Size = ALIGN_RANGE_UP(PartitionConfig->Size, SETUP_BLOCK_SIZE) /
  276. SETUP_BLOCK_SIZE;
  277. }
  278. PartitionConfig->Size = Size * SETUP_BLOCK_SIZE;
  279. PartitionInfo->EndOffset = Start + Size;
  280. BlockOffset = PartitionInfo->EndOffset;
  281. if ((PartitionInfo->EndOffset > PartitionContext->BlockCount) ||
  282. (Start + Size < Start)) {
  283. fprintf(stderr,
  284. "Error: Partition blocks 0x%llx + 0x%llx bigger than "
  285. "disk size 0x%llx (%lldMB).\n",
  286. Start,
  287. Size,
  288. PartitionContext->BlockCount,
  289. PartitionContext->BlockCount * SETUP_BLOCK_SIZE / _1MB);
  290. Result = EINVAL;
  291. goto FormatDiskEnd;
  292. }
  293. PartitionInfo->Number = PartitionIndex + 1;
  294. PartitionInfo->Flags = PARTITION_FLAG_PRIMARY;
  295. if ((PartitionConfig->Flags & SETUP_PARTITION_FLAG_BOOT) != 0) {
  296. PartitionInfo->Flags |= PARTITION_FLAG_BOOT;
  297. }
  298. if ((PartitionConfig->Flags & SETUP_PARTITION_FLAG_SYSTEM) != 0) {
  299. SystemIndex = PartitionIndex;
  300. }
  301. if (DiskConfiguration->PartitionFormat == PartitionFormatGpt) {
  302. memcpy(PartitionInfo->TypeIdentifier,
  303. PartitionConfig->PartitionType,
  304. PARTITION_TYPE_SIZE);
  305. } else if (DiskConfiguration->PartitionFormat == PartitionFormatMbr) {
  306. PartitionInfo->TypeIdentifier[0] = PartitionConfig->MbrType;
  307. }
  308. PartitionInfo->Attributes = PartitionConfig->Attributes;
  309. }
  310. //
  311. // If the disk is actually not partitioned, end now.
  312. //
  313. if (DiskConfiguration->PartitionFormat == PartitionFormatNone) {
  314. Status = 0;
  315. goto FormatDiskEnd;
  316. }
  317. if (SystemIndex == PartitionCount) {
  318. fprintf(stderr,
  319. "Error: One partition must be designated the system "
  320. "partition.\n");
  321. Status = EINVAL;
  322. goto FormatDiskEnd;
  323. }
  324. Status = PartWritePartitionLayout(PartitionContext,
  325. DiskConfiguration->PartitionFormat,
  326. Partitions,
  327. PartitionCount,
  328. TRUE);
  329. if (!KSUCCESS(Status)) {
  330. Result = -1;
  331. fprintf(stderr,
  332. "Error: Failed to write partition layout: %d\n",
  333. Status);
  334. goto FormatDiskEnd;
  335. }
  336. //
  337. // Re-read the partition information to get the randomly assigned partition
  338. // and disk IDs.
  339. //
  340. Status = PartEnumeratePartitions(PartitionContext);
  341. if (!KSUCCESS(Status)) {
  342. fprintf(stderr,
  343. "Error: Failed to reenumerate partitions: %d\n",
  344. Status);
  345. Result = -1;
  346. goto FormatDiskEnd;
  347. }
  348. assert(PartitionContext->PartitionCount == PartitionCount);
  349. Partitions = PartitionContext->Partitions;
  350. ZeroBuffer = malloc(PartitionContext->BlockSize);
  351. if (ZeroBuffer == NULL) {
  352. Result = ENOMEM;
  353. goto FormatDiskEnd;
  354. }
  355. memset(ZeroBuffer, 0, PartitionContext->BlockSize);
  356. //
  357. // Clear out the space before the first partition.
  358. //
  359. BlockCount = Partitions[0].StartOffset;
  360. for (BlockIndex = PartitionDataStart;
  361. BlockIndex < BlockCount;
  362. BlockIndex += 1) {
  363. Status = SetupPartitionLibraryWrite(PartitionContext,
  364. BlockIndex,
  365. ZeroBuffer);
  366. if (!KSUCCESS(Status)) {
  367. fprintf(stderr,
  368. "Error: Failed to clear %llx: %d\n",
  369. Partitions[PartitionIndex].StartOffset + BlockIndex,
  370. Status);
  371. Result = -1;
  372. goto FormatDiskEnd;
  373. }
  374. }
  375. //
  376. // Clear out the first 16kB of each partition to remove any file systems
  377. // that may have happened to exist there.
  378. //
  379. for (PartitionIndex = 0;
  380. PartitionIndex < PartitionCount;
  381. PartitionIndex += 1) {
  382. BlockCount = SETUP_PARTITION_CLEAR_SIZE / PartitionContext->BlockSize;
  383. if (BlockCount >
  384. (Partitions[PartitionIndex].EndOffset -
  385. Partitions[PartitionIndex].StartOffset)) {
  386. BlockCount = Partitions[PartitionIndex].EndOffset -
  387. Partitions[PartitionIndex].StartOffset;
  388. }
  389. for (BlockIndex = 0; BlockIndex < BlockCount; BlockIndex += 1) {
  390. Status = SetupPartitionLibraryWrite(
  391. PartitionContext,
  392. Partitions[PartitionIndex].StartOffset + BlockIndex,
  393. ZeroBuffer);
  394. if (!KSUCCESS(Status)) {
  395. fprintf(stderr,
  396. "Error: Failed to clear %llx: %d\n",
  397. Partitions[PartitionIndex].StartOffset + BlockIndex,
  398. Status);
  399. Result = -1;
  400. goto FormatDiskEnd;
  401. }
  402. }
  403. }
  404. //
  405. // Read and write the last sector on the disk, to ensure that for disks
  406. // that are actually files that the file size is correct.
  407. //
  408. Status = SetupPartitionLibraryRead(PartitionContext,
  409. PartitionContext->BlockCount - 1,
  410. ZeroBuffer);
  411. if (Status != 0) {
  412. fprintf(stderr, "Error: Failed to read the last sector.\n");
  413. Result = -1;
  414. goto FormatDiskEnd;
  415. }
  416. Status = SetupPartitionLibraryWrite(PartitionContext,
  417. PartitionContext->BlockCount - 1,
  418. ZeroBuffer);
  419. if (Status != 0) {
  420. fprintf(stderr, "Error: Failed to write the last sector.\n");
  421. Result = -1;
  422. goto FormatDiskEnd;
  423. }
  424. //
  425. // Convert the actual partition data back into the configuration
  426. // structures.
  427. //
  428. for (PartitionIndex = 0;
  429. PartitionIndex < DiskConfiguration->PartitionCount;
  430. PartitionIndex += 1) {
  431. PartitionInfo = &(Partitions[PartitionIndex]);
  432. PartitionConfig = &(DiskConfiguration->Partitions[PartitionIndex]);
  433. PartitionConfig->Index = PartitionInfo->Number - 1;
  434. PartitionConfig->Offset = PartitionInfo->StartOffset * SETUP_BLOCK_SIZE;
  435. Size = (PartitionInfo->EndOffset - PartitionInfo->StartOffset) *
  436. SETUP_BLOCK_SIZE;
  437. assert(Size == PartitionConfig->Size);
  438. PartitionConfig->Size = Size;
  439. RtlCopyMemory(&(PartitionConfig->PartitionId),
  440. &(PartitionInfo->Identifier),
  441. PARTITION_IDENTIFIER_SIZE);
  442. RtlCopyMemory(&(PartitionConfig->PartitionType),
  443. &(PartitionInfo->TypeIdentifier),
  444. PARTITION_TYPE_SIZE);
  445. if (DiskConfiguration->PartitionFormat == PartitionFormatMbr) {
  446. assert(PartitionConfig->MbrType ==
  447. PartitionInfo->TypeIdentifier[0]);
  448. }
  449. }
  450. FormatDiskEnd:
  451. if (ZeroBuffer != NULL) {
  452. free(ZeroBuffer);
  453. }
  454. return Result;
  455. }
  456. //
  457. // --------------------------------------------------------- Internal Functions
  458. //
  459. PVOID
  460. SetupPartitionLibraryAllocate (
  461. UINTN Size
  462. )
  463. /*++
  464. Routine Description:
  465. This routine is called when the partition library needs to allocate memory.
  466. Arguments:
  467. Size - Supplies the size of the allocation request, in bytes.
  468. Return Value:
  469. Returns a pointer to the allocation if successful, or NULL if the
  470. allocation failed.
  471. --*/
  472. {
  473. return malloc(Size);
  474. }
  475. VOID
  476. SetupPartitionLibraryFree (
  477. PVOID Memory
  478. )
  479. /*++
  480. Routine Description:
  481. This routine is called when the partition library needs to free allocated
  482. memory.
  483. Arguments:
  484. Memory - Supplies the allocation returned by the allocation routine.
  485. Return Value:
  486. None.
  487. --*/
  488. {
  489. free(Memory);
  490. return;
  491. }
  492. KSTATUS
  493. SetupPartitionLibraryRead (
  494. PPARTITION_CONTEXT Context,
  495. ULONGLONG BlockAddress,
  496. PVOID Buffer
  497. )
  498. /*++
  499. Routine Description:
  500. This routine is called when the partition library needs to read a sector
  501. from the disk.
  502. Arguments:
  503. Context - Supplies the partition context identifying the disk.
  504. BlockAddress - Supplies the block address to read.
  505. Buffer - Supplies a pointer where the data will be returned on success.
  506. This buffer is expected to be one block in size (as specified in the
  507. partition context).
  508. Return Value:
  509. Status code.
  510. --*/
  511. {
  512. PSETUP_CONTEXT ApplicationContext;
  513. LONGLONG BytesRead;
  514. LONGLONG Result;
  515. ApplicationContext = PARENT_STRUCTURE(Context,
  516. SETUP_CONTEXT,
  517. PartitionContext);
  518. Result = SetupSeek(ApplicationContext->Disk,
  519. BlockAddress * SETUP_BLOCK_SIZE);
  520. if (Result != BlockAddress * SETUP_BLOCK_SIZE) {
  521. return STATUS_UNSUCCESSFUL;
  522. }
  523. BytesRead = SetupRead(ApplicationContext->Disk, Buffer, SETUP_BLOCK_SIZE);
  524. if (BytesRead != SETUP_BLOCK_SIZE) {
  525. return STATUS_UNSUCCESSFUL;
  526. }
  527. return STATUS_SUCCESS;
  528. }
  529. KSTATUS
  530. SetupPartitionLibraryWrite (
  531. PPARTITION_CONTEXT Context,
  532. ULONGLONG BlockAddress,
  533. PVOID Buffer
  534. )
  535. /*++
  536. Routine Description:
  537. This routine is called when the partition library needs to write a sector
  538. to the disk.
  539. Arguments:
  540. Context - Supplies the partition context identifying the disk.
  541. BlockAddress - Supplies the block address to read.
  542. Buffer - Supplies a pointer where the data will be returned on success.
  543. This buffer is expected to be one block in size (as specified in the
  544. partition context).
  545. Return Value:
  546. Status code.
  547. --*/
  548. {
  549. PSETUP_CONTEXT ApplicationContext;
  550. LONGLONG BytesWritten;
  551. LONGLONG Result;
  552. ApplicationContext = PARENT_STRUCTURE(Context,
  553. SETUP_CONTEXT,
  554. PartitionContext);
  555. Result = SetupSeek(ApplicationContext->Disk,
  556. BlockAddress * SETUP_BLOCK_SIZE);
  557. if (Result != BlockAddress * SETUP_BLOCK_SIZE) {
  558. return STATUS_UNSUCCESSFUL;
  559. }
  560. BytesWritten = SetupWrite(ApplicationContext->Disk,
  561. Buffer,
  562. SETUP_BLOCK_SIZE);
  563. if (BytesWritten != SETUP_BLOCK_SIZE) {
  564. return STATUS_UNSUCCESSFUL;
  565. }
  566. return STATUS_SUCCESS;
  567. }
  568. VOID
  569. SetupPartitionLibraryFillRandom (
  570. PPARTITION_CONTEXT Context,
  571. PUCHAR Buffer,
  572. ULONG BufferSize
  573. )
  574. /*++
  575. Routine Description:
  576. This routine is called when the partition library needs to fill a buffer
  577. with random bytes.
  578. Arguments:
  579. Context - Supplies the partition context identifying the disk.
  580. Buffer - Supplies a pointer to the buffer to fill with random bytes.
  581. BufferSize - Supplies the size of the buffer in bytes.
  582. Return Value:
  583. None.
  584. --*/
  585. {
  586. INT Value;
  587. while (BufferSize != 0) {
  588. Value = rand();
  589. if (BufferSize >= sizeof(USHORT)) {
  590. RtlCopyMemory(Buffer, &Value, sizeof(USHORT));
  591. Buffer += sizeof(USHORT);
  592. BufferSize -= sizeof(USHORT);
  593. } else {
  594. RtlCopyMemory(Buffer, &Value, BufferSize);
  595. break;
  596. }
  597. }
  598. return;
  599. }