1
0

steps.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783
  1. /*++
  2. Copyright (c) 2015 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. steps.c
  9. Abstract:
  10. This module implements the major steps in installing the OS.
  11. Author:
  12. Evan Green 20-Oct-2015
  13. Environment:
  14. Setup
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <assert.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <time.h>
  27. #include <unistd.h>
  28. #include "setup.h"
  29. #include "sconf.h"
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // Define the default factor to multiply system memory by to get the page file
  35. // size.
  36. //
  37. #define SETUP_DEFAULT_PAGE_FILE_NUMERATOR 2
  38. #define SETUP_DEFAULT_PAGE_FILE_DENOMINATOR 1
  39. #define SETUP_MAX_PAGE_FILE_DISK_DIVISOR 10
  40. //
  41. // ------------------------------------------------------ Data Type Definitions
  42. //
  43. //
  44. // ----------------------------------------------- Internal Function Prototypes
  45. //
  46. INT
  47. SetupDeterminePageFileSize (
  48. PSETUP_CONTEXT Context
  49. );
  50. INT
  51. SetupWriteBootDriversFile (
  52. PSETUP_CONTEXT Context,
  53. PVOID DestinationVolume
  54. );
  55. INT
  56. SetupExecuteCopy (
  57. PSETUP_CONTEXT Context,
  58. PVOID DestinationVolume,
  59. PSETUP_COPY Command
  60. );
  61. INT
  62. SetupWriteBootSectorFile (
  63. PSETUP_CONTEXT Context,
  64. PSETUP_COPY Command,
  65. BOOL WriteLbaOffset,
  66. BOOL Clobber
  67. );
  68. INT
  69. SetupReadEntireFile (
  70. PSETUP_CONTEXT Context,
  71. PVOID Source,
  72. PCSTR SourcePath,
  73. PVOID *FileContents,
  74. PULONG FileContentsSize
  75. );
  76. PSETUP_PARTITION_CONFIGURATION
  77. SetupGetPartition (
  78. PSETUP_CONTEXT Context,
  79. ULONG Flag
  80. );
  81. PVOID
  82. SetupGetSourceVolume (
  83. PSETUP_CONTEXT Context,
  84. ULONG SourceVolume
  85. );
  86. //
  87. // -------------------------------------------------------------------- Globals
  88. //
  89. UCHAR SetupZeroDiskIdentifier[DISK_IDENTIFIER_SIZE] = {0};
  90. UCHAR SetupZeroPartitionIdentifier[PARTITION_IDENTIFIER_SIZE] = {0};
  91. //
  92. // ------------------------------------------------------------------ Functions
  93. //
  94. INT
  95. SetupInstallToDisk (
  96. PSETUP_CONTEXT Context
  97. )
  98. /*++
  99. Routine Description:
  100. This routine installs the OS onto an open disk.
  101. Arguments:
  102. Context - Supplies a pointer to the application context.
  103. Return Value:
  104. 0 on success.
  105. Non-zero on failure.
  106. --*/
  107. {
  108. PVOID BootVolume;
  109. BOOL CompatibilityMode;
  110. ULONG Index;
  111. PSETUP_PARTITION_CONFIGURATION Partition;
  112. ULONG PartitionCount;
  113. LONGLONG PreviousOffset;
  114. ULONGLONG PreviousSize;
  115. INT Result;
  116. BootVolume = NULL;
  117. PreviousOffset = Context->CurrentPartitionOffset;
  118. PreviousSize = Context->CurrentPartitionSize;
  119. //
  120. // Write the partition structures.
  121. //
  122. Result = SetupFormatDisk(Context);
  123. if (Result != 0) {
  124. fprintf(stderr, "Failed to format disk.\n");
  125. goto InstallToDiskEnd;
  126. }
  127. //
  128. // Loop installing all files to all partitions.
  129. //
  130. Partition = Context->Configuration->Disk.Partitions;
  131. PartitionCount = Context->Configuration->Disk.PartitionCount;
  132. for (Index = 0; Index < PartitionCount; Index += 1) {
  133. Result = SetupInstallToPartition(Context, Partition);
  134. if (Result != 0) {
  135. goto InstallToDiskEnd;
  136. }
  137. Partition += 1;
  138. }
  139. //
  140. // Write the MBR if there is one.
  141. //
  142. if (Context->Configuration->Disk.Mbr.Source != NULL) {
  143. Context->CurrentPartitionOffset = 0;
  144. Context->CurrentPartitionSize =
  145. Context->Configuration->Disk.Partitions[0].Offset;
  146. Result = SetupWriteBootSectorFile(Context,
  147. &(Context->Configuration->Disk.Mbr),
  148. FALSE,
  149. FALSE);
  150. if (Result != 0) {
  151. fprintf(stderr, "Failed to write MBR.\n");
  152. goto InstallToDiskEnd;
  153. }
  154. }
  155. //
  156. // Open up the boot volume and write out the new boot entries.
  157. //
  158. Partition = SetupGetPartition(Context, SETUP_PARTITION_FLAG_BOOT);
  159. if (Partition != NULL) {
  160. CompatibilityMode = FALSE;
  161. if ((Partition->Flags & SETUP_PARTITION_FLAG_COMPATIBILITY_MODE) != 0) {
  162. CompatibilityMode = TRUE;
  163. }
  164. Context->CurrentPartitionOffset = Partition->Offset / SETUP_BLOCK_SIZE;
  165. Context->CurrentPartitionSize = Partition->Size / SETUP_BLOCK_SIZE;
  166. BootVolume = SetupVolumeOpen(Context,
  167. Context->DiskPath,
  168. SetupVolumeFormatIfIncompatible,
  169. CompatibilityMode);
  170. if (BootVolume == NULL) {
  171. fprintf(stderr, "Error: Failed to open boot volume.\n");
  172. Result = -1;
  173. goto InstallToDiskEnd;
  174. }
  175. Result = SetupUpdateBootEntries(Context, BootVolume);
  176. if (Result != 0) {
  177. fprintf(stderr, "Error: Failed to update boot entries.\n");
  178. goto InstallToDiskEnd;
  179. }
  180. }
  181. InstallToDiskEnd:
  182. if (BootVolume != NULL) {
  183. SetupVolumeClose(Context, BootVolume);
  184. BootVolume = NULL;
  185. }
  186. Context->CurrentPartitionOffset = PreviousOffset;
  187. Context->CurrentPartitionSize = PreviousSize;
  188. return Result;
  189. }
  190. INT
  191. SetupInstallToPartition (
  192. PSETUP_CONTEXT Context,
  193. PSETUP_PARTITION_CONFIGURATION PartitionConfiguration
  194. )
  195. /*++
  196. Routine Description:
  197. This routine perform the required installation steps for a particular
  198. partition.
  199. Arguments:
  200. Context - Supplies a pointer to the application context.
  201. PartitionConfiguration - Supplies a pointer to the partition data to
  202. install.
  203. Return Value:
  204. 0 on success.
  205. Non-zero on failure.
  206. --*/
  207. {
  208. BOOL Clobber;
  209. BOOL CompatibilityMode;
  210. PSETUP_DESTINATION Destination;
  211. PARTITION_DEVICE_INFORMATION PartitionInformation;
  212. INT Result;
  213. LONGLONG SeekResult;
  214. PVOID Volume;
  215. BOOL WriteLbaOffset;
  216. Volume = NULL;
  217. //
  218. // If no partition was specified, get the system partition. If that fails,
  219. // just get the first partition.
  220. //
  221. if (PartitionConfiguration == NULL) {
  222. PartitionConfiguration = SetupGetPartition(Context,
  223. SETUP_PARTITION_FLAG_SYSTEM);
  224. if (PartitionConfiguration == NULL) {
  225. if (Context->Configuration->Disk.PartitionCount == 0) {
  226. fprintf(stderr, "Error: no partitions.\n");
  227. return ENOENT;
  228. }
  229. PartitionConfiguration =
  230. &(Context->Configuration->Disk.Partitions[0]);
  231. }
  232. }
  233. //
  234. // Open up the partition. If there's already a disk, then set the offset
  235. // to the partition offset.
  236. //
  237. if (Context->Disk != NULL) {
  238. Destination = Context->DiskPath;
  239. Context->CurrentPartitionOffset =
  240. PartitionConfiguration->Offset / SETUP_BLOCK_SIZE;
  241. Context->CurrentPartitionSize =
  242. PartitionConfiguration->Size / SETUP_BLOCK_SIZE;
  243. SeekResult = SetupPartitionSeek(Context, Context->Disk, 0);
  244. if (SeekResult != 0) {
  245. fprintf(stderr, "Failed to seek to install partition.\n");
  246. Result = -1;
  247. goto InstallToPartitionEnd;
  248. }
  249. //
  250. // No device has been opened, so open up the partition directly.
  251. //
  252. } else {
  253. Destination = Context->PartitionPath;
  254. memset(&PartitionInformation, 0, sizeof(PartitionInformation));
  255. Context->Disk = SetupPartitionOpen(Context,
  256. Destination,
  257. &PartitionInformation);
  258. if (Context->Disk == NULL) {
  259. Result = errno;
  260. fprintf(stderr, "Failed to open partition: %s.\n", strerror(errno));
  261. goto InstallToPartitionEnd;
  262. }
  263. Context->CurrentPartitionOffset = 0;
  264. Context->CurrentPartitionSize = PartitionInformation.LastBlock -
  265. PartitionInformation.FirstBlock + 1;
  266. PartitionConfiguration->Offset = PartitionInformation.FirstBlock *
  267. PartitionInformation.BlockSize;
  268. PartitionConfiguration->Size = Context->CurrentPartitionSize *
  269. SETUP_BLOCK_SIZE;
  270. memcpy(&(PartitionConfiguration->PartitionId),
  271. PartitionInformation.PartitionId,
  272. PARTITION_IDENTIFIER_SIZE);
  273. memcpy(&(Context->PartitionContext.DiskIdentifier),
  274. PartitionInformation.DiskId,
  275. DISK_IDENTIFIER_SIZE);
  276. }
  277. assert(Destination != NULL);
  278. if (PartitionConfiguration->CopyCommandCount != 0) {
  279. CompatibilityMode = FALSE;
  280. if ((PartitionConfiguration->Flags &
  281. SETUP_PARTITION_FLAG_COMPATIBILITY_MODE) != 0) {
  282. CompatibilityMode = TRUE;
  283. }
  284. Volume = SetupVolumeOpen(Context,
  285. Destination,
  286. SetupVolumeFormatAlways,
  287. CompatibilityMode);
  288. if (Volume == NULL) {
  289. Result = -1;
  290. goto InstallToPartitionEnd;
  291. }
  292. Result = SetupInstallFiles(Context, Volume, PartitionConfiguration);
  293. if (Result != 0) {
  294. goto InstallToPartitionEnd;
  295. }
  296. }
  297. //
  298. // Write the VBR if there is one.
  299. //
  300. Clobber = TRUE;
  301. if ((PartitionConfiguration->Flags & SETUP_PARTITION_FLAG_MERGE_VBR) != 0) {
  302. Clobber = FALSE;
  303. }
  304. if (PartitionConfiguration->Vbr.Source != NULL) {
  305. WriteLbaOffset = FALSE;
  306. if ((PartitionConfiguration->Flags &
  307. SETUP_PARTITION_FLAG_WRITE_VBR_LBA) != 0) {
  308. WriteLbaOffset = TRUE;
  309. }
  310. Result = SetupWriteBootSectorFile(Context,
  311. &(PartitionConfiguration->Vbr),
  312. WriteLbaOffset,
  313. Clobber);
  314. if (Result != 0) {
  315. fprintf(stderr, "Failed to write VBR.\n");
  316. goto InstallToPartitionEnd;
  317. }
  318. }
  319. Result = 0;
  320. InstallToPartitionEnd:
  321. if (Volume != NULL) {
  322. SetupVolumeClose(Context, Volume);
  323. }
  324. //
  325. // Only close the partition if this routine opened it.
  326. //
  327. if ((Context->Disk != NULL) && (Destination != Context->DiskPath)) {
  328. SetupPartitionClose(Context, Context->Disk);
  329. Context->Disk = NULL;
  330. }
  331. return Result;
  332. }
  333. INT
  334. SetupInstallToDirectory (
  335. PSETUP_CONTEXT Context
  336. )
  337. /*++
  338. Routine Description:
  339. This routine installs the OS onto a directory, copying only system
  340. partition files.
  341. Arguments:
  342. Context - Supplies a pointer to the application context.
  343. Return Value:
  344. 0 on success.
  345. Non-zero on failure.
  346. --*/
  347. {
  348. INT Result;
  349. PSETUP_PARTITION_CONFIGURATION SystemPartition;
  350. PVOID Volume;
  351. SystemPartition = SetupGetPartition(Context, SETUP_PARTITION_FLAG_SYSTEM);
  352. assert(SystemPartition != NULL);
  353. Volume = SetupVolumeOpen(Context,
  354. Context->DirectoryPath,
  355. SetupVolumeFormatNever,
  356. FALSE);
  357. if (Volume == NULL) {
  358. return -1;
  359. }
  360. Result = SetupInstallFiles(Context, Volume, SystemPartition);
  361. SetupVolumeClose(Context, Volume);
  362. return Result;
  363. }
  364. INT
  365. SetupInstallFiles (
  366. PSETUP_CONTEXT Context,
  367. PVOID DestinationVolume,
  368. PSETUP_PARTITION_CONFIGURATION Partition
  369. )
  370. /*++
  371. Routine Description:
  372. This routine installs to the given volume.
  373. Arguments:
  374. Context - Supplies a pointer to the applicaton context.
  375. DestinationVolume - Supplies a pointer to the open destination volume
  376. handle.
  377. Partition - Supplies a pointer to the partition configuration, which
  378. contains the files to copy.
  379. Return Value:
  380. 0 on success.
  381. Non-zero on failure.
  382. --*/
  383. {
  384. PSETUP_COPY CopyCommand;
  385. ULONG CopyCommandCount;
  386. ULONG Index;
  387. PVOID PageFile;
  388. ULONGLONG PageFileSize;
  389. INT Result;
  390. PageFile = NULL;
  391. CopyCommand = Partition->CopyCommands;
  392. CopyCommandCount = Partition->CopyCommandCount;
  393. for (Index = 0; Index < CopyCommandCount; Index += 1) {
  394. Result = SetupExecuteCopy(Context, DestinationVolume, CopyCommand);
  395. if (Result != 0) {
  396. goto InstallFilesEnd;
  397. }
  398. CopyCommand += 1;
  399. }
  400. if ((Partition->Flags & SETUP_PARTITION_FLAG_SYSTEM) != 0) {
  401. Result = SetupWriteBootDriversFile(Context, DestinationVolume);
  402. if (Result != 0) {
  403. fprintf(stderr, "Failed to write boot drivers file.\n");
  404. goto InstallFilesEnd;
  405. }
  406. //
  407. // Compute the page file size if it has not already been specified.
  408. //
  409. if (Context->PageFileSize == -1ULL) {
  410. SetupDeterminePageFileSize(Context);
  411. }
  412. //
  413. // Create a page file if needed.
  414. //
  415. if (Context->PageFileSize != 0) {
  416. PageFileSize = Context->PageFileSize * _1MB;
  417. //
  418. // Watch out for file system limitations on max file size.
  419. // TODO: Max file size is file system specific, not hardcoded.
  420. //
  421. if (PageFileSize > MAX_ULONG) {
  422. PageFileSize = MAX_ULONG;
  423. }
  424. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  425. printf("Creating %lldMB page file...", PageFileSize / _1MB);
  426. fflush(stdout);
  427. }
  428. PageFile = SetupFileOpen(DestinationVolume,
  429. SETUP_PAGE_FILE_PATH,
  430. O_RDWR | O_CREAT,
  431. 0);
  432. if (PageFile == NULL) {
  433. fprintf(stderr, "Warning: Failed to create page file.\n");
  434. goto InstallFilesEnd;
  435. }
  436. Result = SetupFileFileTruncate(PageFile, PageFileSize);
  437. SetupFileClose(PageFile);
  438. PageFile = NULL;
  439. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  440. printf("Done.\n");
  441. }
  442. if (Result != 0) {
  443. fprintf(stderr, "Warning: Failed to set page file size.\n");
  444. Result = 0;
  445. }
  446. }
  447. }
  448. InstallFilesEnd:
  449. if (PageFile != NULL) {
  450. SetupFileClose(PageFile);
  451. }
  452. return Result;
  453. }
  454. INT
  455. SetupUpdateBootVolume (
  456. PSETUP_CONTEXT Context,
  457. PVOID BootVolume
  458. )
  459. /*++
  460. Routine Description:
  461. This routine updates the boot volume, copying the boot files and updating
  462. the boot entries.
  463. Arguments:
  464. Context - Supplies a pointer to the applicaton context.
  465. BootVolume - Supplies a pointer to the open boot volume handle.
  466. Return Value:
  467. 0 on success.
  468. Non-zero on failure.
  469. --*/
  470. {
  471. PSETUP_PARTITION_CONFIGURATION BootPartition;
  472. INT Status;
  473. BootPartition = SetupGetPartition(Context, SETUP_PARTITION_FLAG_BOOT);
  474. if ((BootPartition != NULL) &&
  475. ((BootPartition->Flags & SETUP_PARTITION_FLAG_SYSTEM) == 0)) {
  476. Status = SetupInstallFiles(Context, BootVolume, BootPartition);
  477. if (Status != 0) {
  478. fprintf(stderr, "Error: Failed to install boot volume files.\n");
  479. return Status;
  480. }
  481. }
  482. Status = SetupUpdateBootEntries(Context, BootVolume);
  483. if (Status != 0) {
  484. return Status;
  485. }
  486. return 0;
  487. }
  488. INT
  489. SetupUpdateBootEntries (
  490. PSETUP_CONTEXT Context,
  491. PVOID BootVolume
  492. )
  493. /*++
  494. Routine Description:
  495. This routine writes out the new boot entries for the installed image.
  496. Arguments:
  497. Context - Supplies a pointer to the applicaton context.
  498. BootVolume - Supplies a pointer to the open boot volume handle.
  499. Return Value:
  500. 0 on success.
  501. Non-zero on failure.
  502. --*/
  503. {
  504. BOOT_CONFIGURATION_CONTEXT BootConfiguration;
  505. BOOL BootConfigurationInitialized;
  506. PCSTR BootDataPath;
  507. PBOOT_ENTRY BootEntries;
  508. PBOOT_ENTRY BootEntry;
  509. ULONG BootEntryCount;
  510. PVOID Buffer;
  511. ssize_t BytesComplete;
  512. int CompareResult;
  513. PVOID Destination;
  514. ULONG EntryIndex;
  515. ULONGLONG FileSize;
  516. UINTN Index;
  517. PBOOT_ENTRY NewBootEntry;
  518. PVOID NewBuffer;
  519. size_t NewSize;
  520. mode_t Permissions;
  521. INT Result;
  522. KSTATUS Status;
  523. PSETUP_PARTITION_CONFIGURATION SystemPartition;
  524. memset(&BootConfiguration, 0, sizeof(BOOT_CONFIGURATION_CONTEXT));
  525. BootConfigurationInitialized = FALSE;
  526. Destination = NULL;
  527. NewBootEntry = NULL;
  528. //
  529. // Make sure the appropriate directories exist.
  530. //
  531. Permissions = S_IRUSR | S_IWUSR | S_IXUSR;
  532. //
  533. // The install partition information had better be valid.
  534. //
  535. SystemPartition = SetupGetPartition(Context, SETUP_PARTITION_FLAG_SYSTEM);
  536. if (SystemPartition == NULL) {
  537. Result = EINVAL;
  538. goto UpdateBootVolumeEnd;
  539. }
  540. //
  541. // Initialize the boot configuration library support.
  542. //
  543. BootConfiguration.AllocateFunction = (PBOOT_CONFIGURATION_ALLOCATE)malloc;
  544. BootConfiguration.FreeFunction = (PBOOT_CONFIGURATION_FREE)free;
  545. Status = BcInitializeContext(&BootConfiguration);
  546. if (!KSUCCESS(Status)) {
  547. fprintf(stderr, "BcInitializeContext Error: %d\n", Status);
  548. Result = -1;
  549. goto UpdateBootVolumeEnd;
  550. }
  551. BootConfigurationInitialized = TRUE;
  552. //
  553. // Attempt to open up the boot configuration data.
  554. //
  555. BootDataPath = Context->Configuration->BootDataPath;
  556. if (BootDataPath == NULL) {
  557. BootDataPath = BOOT_CONFIGURATION_ABSOLUTE_PATH;
  558. }
  559. Destination = SetupFileOpen(BootVolume,
  560. BootDataPath,
  561. O_RDONLY,
  562. 0);
  563. if (Destination != NULL) {
  564. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  565. printf("Reading existing boot configuration.\n");
  566. }
  567. //
  568. // The file exists. Read it in.
  569. //
  570. Result = SetupFileFileStat(Destination, &FileSize, NULL, NULL);
  571. if (Result != 0) {
  572. goto UpdateBootVolumeEnd;
  573. }
  574. Status = STATUS_NOT_FOUND;
  575. if (FileSize != 0) {
  576. Buffer = malloc(FileSize);
  577. if (Buffer == NULL) {
  578. goto UpdateBootVolumeEnd;
  579. }
  580. BytesComplete = SetupFileRead(Destination, Buffer, FileSize);
  581. if (BytesComplete != FileSize) {
  582. fprintf(stderr, "Failed to read boot configuration file.\n");
  583. goto UpdateBootVolumeEnd;
  584. }
  585. BootConfiguration.FileData = Buffer;
  586. BootConfiguration.FileDataSize = FileSize;
  587. Buffer = NULL;
  588. //
  589. // Read in and parse the boot configuration data. If it is
  590. // invalid, create a brand new default configuration.
  591. //
  592. Status = BcReadBootConfigurationFile(&BootConfiguration);
  593. if (!KSUCCESS(Status)) {
  594. fprintf(stderr,
  595. "Failed to read boot configuration data: %d.\n",
  596. Status);
  597. }
  598. }
  599. //
  600. // If the file size is zero or could not be read, create a default
  601. // configuration.
  602. //
  603. if (!KSUCCESS(Status)) {
  604. Status = BcCreateDefaultBootConfiguration(
  605. &BootConfiguration,
  606. Context->PartitionContext.DiskIdentifier,
  607. SystemPartition->PartitionId);
  608. if (!KSUCCESS(Status)) {
  609. fprintf(stderr,
  610. "Failed to create default boot configuration: %d\n",
  611. Status);
  612. Result = -1;
  613. goto UpdateBootVolumeEnd;
  614. }
  615. }
  616. SetupFileClose(Destination);
  617. Destination = NULL;
  618. //
  619. // There is no boot configuration data. Create a new one.
  620. //
  621. } else {
  622. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  623. printf("Creating initial boot configuration.\n");
  624. }
  625. Status = BcCreateDefaultBootConfiguration(
  626. &BootConfiguration,
  627. Context->PartitionContext.DiskIdentifier,
  628. SystemPartition->PartitionId);
  629. if (!KSUCCESS(Status)) {
  630. fprintf(stderr,
  631. "BcCreateDefaultBootConfiguration Error: %x\n",
  632. Status);
  633. Result = -1;
  634. goto UpdateBootVolumeEnd;
  635. }
  636. }
  637. BootEntries = Context->Configuration->BootEntries;
  638. BootEntryCount = Context->Configuration->BootEntryCount;
  639. for (EntryIndex = 0; EntryIndex < BootEntryCount; EntryIndex += 1) {
  640. NewBootEntry = BcCopyBootEntry(&BootConfiguration,
  641. &(BootEntries[EntryIndex]));
  642. if (NewBootEntry == NULL) {
  643. Result = ENOMEM;
  644. goto UpdateBootVolumeEnd;
  645. }
  646. //
  647. // Mark new boot entries so that the loop below doesn't replace them,
  648. // even if several of them point to the same partition ID.
  649. //
  650. NewBootEntry->Id = -1;
  651. if ((Context->Flags & SETUP_FLAG_INSTALL_DEBUG) != 0) {
  652. NewBootEntry->Flags |= BOOT_ENTRY_FLAG_DEBUG;
  653. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  654. printf("Enabled debug mode.\n");
  655. }
  656. }
  657. if ((Context->Flags & SETUP_FLAG_INSTALL_BOOT_DEBUG) != 0) {
  658. NewBootEntry->Flags |= BOOT_ENTRY_FLAG_BOOT_DEBUG;
  659. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  660. printf("Enabled boot debug mode.\n");
  661. }
  662. }
  663. //
  664. // If the disk ID or partition ID are blank, fill them in with the
  665. // system disk and partition IDs.
  666. //
  667. assert(BOOT_DISK_ID_SIZE == DISK_IDENTIFIER_SIZE);
  668. CompareResult = memcmp(NewBootEntry->DiskId,
  669. SetupZeroDiskIdentifier,
  670. DISK_IDENTIFIER_SIZE);
  671. if (CompareResult == 0) {
  672. memcpy(NewBootEntry->DiskId,
  673. Context->PartitionContext.DiskIdentifier,
  674. DISK_IDENTIFIER_SIZE);
  675. }
  676. assert(BOOT_PARTITION_ID_SIZE == PARTITION_IDENTIFIER_SIZE);
  677. CompareResult = memcmp(NewBootEntry->PartitionId,
  678. SetupZeroPartitionIdentifier,
  679. PARTITION_IDENTIFIER_SIZE);
  680. if (CompareResult == 0) {
  681. memcpy(NewBootEntry->PartitionId,
  682. SystemPartition->PartitionId,
  683. PARTITION_IDENTIFIER_SIZE);
  684. }
  685. //
  686. // Look for a boot entry with this partition ID to replace. Skip ones
  687. // that are already new.
  688. //
  689. for (Index = 0;
  690. Index < BootConfiguration.BootEntryCount;
  691. Index += 1) {
  692. BootEntry = BootConfiguration.BootEntries[Index];
  693. if (BootEntry->Id == (ULONG)-1) {
  694. continue;
  695. }
  696. CompareResult = memcmp(BootEntry->PartitionId,
  697. NewBootEntry->PartitionId,
  698. BOOT_PARTITION_ID_SIZE);
  699. if (CompareResult == 0) {
  700. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  701. printf("Replacing boot entry %d: %s.\n",
  702. BootEntry->Id,
  703. BootEntry->Name);
  704. }
  705. BootConfiguration.BootEntries[Index] = NewBootEntry;
  706. BcDestroyBootEntry(&BootConfiguration, BootEntry);
  707. break;
  708. }
  709. }
  710. //
  711. // If there was no previous entry pointing at this partition,
  712. // add it to the end of the list.
  713. //
  714. if (Index == BootConfiguration.BootEntryCount) {
  715. NewSize = (BootConfiguration.BootEntryCount + 1) *
  716. sizeof(PBOOT_ENTRY);
  717. NewBuffer = realloc(BootConfiguration.BootEntries, NewSize);
  718. if (NewBuffer == NULL) {
  719. Result = ENOMEM;
  720. goto UpdateBootVolumeEnd;
  721. }
  722. BootConfiguration.BootEntries = NewBuffer;
  723. BootConfiguration.BootEntries[BootConfiguration.BootEntryCount] =
  724. NewBootEntry;
  725. BootConfiguration.BootEntryCount += 1;
  726. }
  727. if (EntryIndex == 0) {
  728. BootConfiguration.GlobalConfiguration.DefaultBootEntry =
  729. NewBootEntry;
  730. }
  731. NewBootEntry = NULL;
  732. }
  733. //
  734. // Serialize the boot configuration data.
  735. //
  736. Status = BcWriteBootConfigurationFile(&BootConfiguration);
  737. if (!KSUCCESS(Status)) {
  738. fprintf(stderr,
  739. "Error: Failed to serialize boot configuration data: %d.\n",
  740. Status);
  741. Result = -1;
  742. goto UpdateBootVolumeEnd;
  743. }
  744. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  745. printf("Writing boot configuration data.\n");
  746. }
  747. //
  748. // Open and write the data.
  749. //
  750. SetupCreateDirectories(Context, BootVolume, BootDataPath);
  751. Destination = SetupFileOpen(BootVolume,
  752. BootDataPath,
  753. O_RDWR | O_CREAT | O_TRUNC,
  754. Permissions);
  755. if (Destination == NULL) {
  756. fprintf(stderr,
  757. "Error: Failed to open %s for writing.\n",
  758. BOOT_CONFIGURATION_ABSOLUTE_PATH);
  759. Result = errno;
  760. if (Result == 0) {
  761. Result = -1;
  762. }
  763. goto UpdateBootVolumeEnd;
  764. }
  765. BytesComplete = SetupFileWrite(Destination,
  766. BootConfiguration.FileData,
  767. BootConfiguration.FileDataSize);
  768. if (BytesComplete != BootConfiguration.FileDataSize) {
  769. fprintf(stderr,
  770. "Error: Failed to write boot configuration data.\n");
  771. Result = -1;
  772. goto UpdateBootVolumeEnd;
  773. }
  774. SetupFileClose(Destination);
  775. Destination = NULL;
  776. Result = 0;
  777. UpdateBootVolumeEnd:
  778. if (BootConfigurationInitialized != FALSE) {
  779. if (NewBootEntry != NULL) {
  780. BcDestroyBootEntry(&BootConfiguration, NewBootEntry);
  781. }
  782. BcDestroyContext(&BootConfiguration);
  783. }
  784. if (Destination != NULL) {
  785. SetupFileClose(Destination);
  786. }
  787. return Result;
  788. }
  789. //
  790. // --------------------------------------------------------- Internal Functions
  791. //
  792. INT
  793. SetupDeterminePageFileSize (
  794. PSETUP_CONTEXT Context
  795. )
  796. /*++
  797. Routine Description:
  798. This routine determines the size of the page file to create.
  799. Arguments:
  800. Context - Supplies a pointer to the applicaton context.
  801. Return Value:
  802. 0 on success.
  803. Non-zero on failure.
  804. --*/
  805. {
  806. ULONGLONG InstallPartitionSize;
  807. ULONGLONG PageFileSize;
  808. INT Result;
  809. ULONGLONG SystemMemory;
  810. PSETUP_PARTITION_CONFIGURATION SystemPartition;
  811. assert(Context->PageFileSize == -1ULL);
  812. //
  813. // On failure, don't make a page file.
  814. //
  815. Context->PageFileSize = 0;
  816. Result = SetupOsGetSystemMemorySize(&SystemMemory);
  817. if (Result != 0) {
  818. return Result;
  819. }
  820. PageFileSize = (SystemMemory * SETUP_DEFAULT_PAGE_FILE_NUMERATOR) /
  821. SETUP_DEFAULT_PAGE_FILE_DENOMINATOR;
  822. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  823. printf("System memory %lldMB, Page File size %lldMB.\n",
  824. SystemMemory,
  825. PageFileSize);
  826. }
  827. SystemPartition = SetupGetPartition(Context, SETUP_PARTITION_FLAG_SYSTEM);
  828. if (SystemPartition == NULL) {
  829. return 0;
  830. }
  831. InstallPartitionSize = SystemPartition->Size;
  832. InstallPartitionSize /= _1MB;
  833. if ((InstallPartitionSize != 0) &&
  834. (PageFileSize >
  835. (InstallPartitionSize / SETUP_MAX_PAGE_FILE_DISK_DIVISOR))) {
  836. PageFileSize = InstallPartitionSize / SETUP_MAX_PAGE_FILE_DISK_DIVISOR;
  837. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  838. printf("Clipping page file to %lldMB, as install partition is "
  839. "only %lldMB.\n",
  840. PageFileSize,
  841. InstallPartitionSize);
  842. }
  843. }
  844. Context->PageFileSize = PageFileSize;
  845. return 0;
  846. }
  847. INT
  848. SetupWriteBootDriversFile (
  849. PSETUP_CONTEXT Context,
  850. PVOID DestinationVolume
  851. )
  852. /*++
  853. Routine Description:
  854. This routine writes the boot drivers file out to the system volume.
  855. Arguments:
  856. Context - Supplies a pointer to the applicaton context.
  857. DestinationVolume - Supplies a pointer to the open destination volume
  858. handle.
  859. Return Value:
  860. 0 on success.
  861. Non-zero on failure.
  862. --*/
  863. {
  864. PSETUP_CONFIGURATION Configuration;
  865. PSTR Contents;
  866. UINTN ContentsSize;
  867. INT Status;
  868. Contents = NULL;
  869. Configuration = Context->Configuration;
  870. if (Configuration->BootDriversPath == NULL) {
  871. return 0;
  872. }
  873. Status = SetupConvertStringArrayToLines(Configuration->BootDrivers,
  874. &Contents,
  875. &ContentsSize);
  876. if (Status != 0) {
  877. return Status;
  878. }
  879. assert(ContentsSize != 0);
  880. Status = SetupCreateAndWriteFile(Context,
  881. DestinationVolume,
  882. Configuration->BootDriversPath,
  883. Contents,
  884. ContentsSize - 1);
  885. free(Contents);
  886. return Status;
  887. }
  888. INT
  889. SetupExecuteCopy (
  890. PSETUP_CONTEXT Context,
  891. PVOID DestinationVolume,
  892. PSETUP_COPY Command
  893. )
  894. /*++
  895. Routine Description:
  896. This routine executes a copy command.
  897. Arguments:
  898. Context - Supplies a pointer to the applicaton context.
  899. DestinationVolume - Supplies a pointer to the open destination volume
  900. handle.
  901. Command - Supplies the copy command, which may direct this routine to
  902. copy a single file, recursive directory, or a list of files and/or
  903. directories.
  904. Return Value:
  905. 0 on success.
  906. Non-zero on failure.
  907. --*/
  908. {
  909. PSTR AppendedDestination;
  910. PSTR AppendedSource;
  911. PCSTR File;
  912. UINTN Index;
  913. PVOID Source;
  914. INT Status;
  915. //
  916. // Do nothing if the source is empty.
  917. //
  918. if ((Command->Source == NULL) || (Command->Source[0] == '\0')) {
  919. return 0;
  920. }
  921. Source = SetupGetSourceVolume(Context, Command->SourceVolume);
  922. if (Source == NULL) {
  923. return EINVAL;
  924. }
  925. if (Command->Files == NULL) {
  926. Status = SetupCopyFile(Context,
  927. DestinationVolume,
  928. Source,
  929. Command->Destination,
  930. Command->Source,
  931. Command->Flags);
  932. return Status;
  933. }
  934. Index = 0;
  935. while (Command->Files[Index] != NULL) {
  936. File = Command->Files[Index];
  937. Index += 1;
  938. AppendedDestination = SetupAppendPaths(Command->Destination, File);
  939. if (AppendedDestination == NULL) {
  940. return ENOMEM;
  941. }
  942. AppendedSource = SetupAppendPaths(Command->Source, File);
  943. if (AppendedSource == NULL) {
  944. free(AppendedDestination);
  945. return ENOMEM;
  946. }
  947. Status = SetupCopyFile(Context,
  948. DestinationVolume,
  949. Source,
  950. AppendedDestination,
  951. AppendedSource,
  952. Command->Flags);
  953. if (Status != 0) {
  954. fprintf(stderr,
  955. "Failed to copy %s -> %s: %s.\n",
  956. AppendedSource,
  957. AppendedDestination,
  958. strerror(Status));
  959. }
  960. free(AppendedDestination);
  961. free(AppendedSource);
  962. if (Status != 0) {
  963. return Status;
  964. }
  965. }
  966. return 0;
  967. }
  968. INT
  969. SetupWriteBootSectorFile (
  970. PSETUP_CONTEXT Context,
  971. PSETUP_COPY Command,
  972. BOOL WriteLbaOffset,
  973. BOOL Clobber
  974. )
  975. /*++
  976. Routine Description:
  977. This routine writes a file's contents out to the boot sector of the disk.
  978. Arguments:
  979. Context - Supplies a pointer to the applicaton context.
  980. Command - Supplies a pointer to the copy command to execute.
  981. WriteLbaOffset - Supplies a boolean indicating if the function should
  982. write the LBA offset into the boot sector at the magic locations.
  983. Clobber - Supplies a boolean indicating whether to ignore previous
  984. disagreeing contents on the disk (TRUE) or to fail if writing the
  985. boot sector file overwrites some other data (FALSE).
  986. Return Value:
  987. 0 on success.
  988. Non-zero on failure.
  989. --*/
  990. {
  991. PUCHAR Block;
  992. PULONG BlockAddressPointer;
  993. ULONGLONG BlockCount;
  994. PUCHAR BootCodeSizePointer;
  995. ULONG ByteIndex;
  996. ssize_t BytesDone;
  997. LONGLONG DiskOffset;
  998. PUCHAR FileData;
  999. ULONG FileSize;
  1000. ULONG Offset;
  1001. INT Result;
  1002. LONGLONG SeekResult;
  1003. PVOID Source;
  1004. Block = NULL;
  1005. FileData = NULL;
  1006. FileSize = 0;
  1007. Source = SetupGetSourceVolume(Context, Command->SourceVolume);
  1008. if (Source == NULL) {
  1009. return EINVAL;
  1010. }
  1011. Result = SetupReadEntireFile(Context,
  1012. Source,
  1013. Command->Source,
  1014. (PVOID *)&FileData,
  1015. &FileSize);
  1016. if (Result != 0) {
  1017. fprintf(stderr,
  1018. "Error: Failed to read boot sector file %s: %s.\n",
  1019. Command->Source,
  1020. strerror(Result));
  1021. goto WriteBootSectorFileEnd;
  1022. }
  1023. Block = malloc(SETUP_BLOCK_SIZE);
  1024. if (Block == NULL) {
  1025. Result = ENOMEM;
  1026. goto WriteBootSectorFileEnd;
  1027. }
  1028. //
  1029. // Loop reading, modifying, and writing back sectors.
  1030. //
  1031. DiskOffset = Command->Offset / SETUP_BLOCK_SIZE;
  1032. assert((DiskOffset * SETUP_BLOCK_SIZE) == Command->Offset);
  1033. SeekResult = SetupPartitionSeek(Context, Context->Disk, DiskOffset);
  1034. if (SeekResult != DiskOffset) {
  1035. Result = errno;
  1036. goto WriteBootSectorFileEnd;
  1037. }
  1038. Offset = 0;
  1039. while (Offset < FileSize) {
  1040. //
  1041. // If clobbering, just write the contents over what's there.
  1042. //
  1043. if (Clobber != FALSE) {
  1044. if (FileSize - Offset >= SETUP_BLOCK_SIZE) {
  1045. memcpy(Block, FileData + Offset, SETUP_BLOCK_SIZE);
  1046. Offset += SETUP_BLOCK_SIZE;
  1047. } else {
  1048. memset(Block, 0, SETUP_BLOCK_SIZE);
  1049. memcpy(Block, FileData + Offset, FileSize - Offset);
  1050. Offset = FileSize;
  1051. }
  1052. //
  1053. // If not clobbering, carefully merge the bytes with what's already on
  1054. // disk.
  1055. //
  1056. } else {
  1057. BytesDone = SetupPartitionRead(Context,
  1058. Context->Disk,
  1059. Block,
  1060. SETUP_BLOCK_SIZE);
  1061. if (BytesDone != SETUP_BLOCK_SIZE) {
  1062. fprintf(stderr,
  1063. "Read only %ld of %d bytes.\n",
  1064. (long)BytesDone,
  1065. SETUP_BLOCK_SIZE);
  1066. Result = errno;
  1067. if (Result == 0) {
  1068. Result = -1;
  1069. }
  1070. goto WriteBootSectorFileEnd;
  1071. }
  1072. //
  1073. // Merge the boot file contents with what's on the disk. There
  1074. // should be no byte set in both.
  1075. //
  1076. ByteIndex = 0;
  1077. while (ByteIndex < SETUP_BLOCK_SIZE) {
  1078. if ((Offset < FileSize) && (FileData[Offset] != 0)) {
  1079. if ((Block[ByteIndex] != 0) &&
  1080. (FileData[Offset] != Block[ByteIndex])) {
  1081. fprintf(stderr,
  1082. "Error: Aborted writing boot file %s, as "
  1083. "offset 0x%x contains byte 0x%x in the boot "
  1084. "file, but already contains byte 0x%x on "
  1085. "disk.\n",
  1086. Command->Source,
  1087. Offset,
  1088. FileData[Offset],
  1089. Block[ByteIndex]);
  1090. Result = EIO;
  1091. goto WriteBootSectorFileEnd;
  1092. }
  1093. Block[ByteIndex] = FileData[Offset];
  1094. }
  1095. ByteIndex += 1;
  1096. Offset += 1;
  1097. }
  1098. }
  1099. if (WriteLbaOffset != FALSE) {
  1100. WriteLbaOffset = FALSE;
  1101. assert(Offset == SETUP_BLOCK_SIZE);
  1102. BlockCount = ALIGN_RANGE_UP(FileSize, SETUP_BLOCK_SIZE) /
  1103. SETUP_BLOCK_SIZE;
  1104. if (BlockCount > MAX_UCHAR) {
  1105. printf("Error: Boot code is too big at %lld sectors. Max is "
  1106. "%d.\n",
  1107. BlockCount,
  1108. MAX_UCHAR);
  1109. Result = EIO;
  1110. goto WriteBootSectorFileEnd;
  1111. }
  1112. BlockAddressPointer =
  1113. (PULONG)(Block + SETUP_BOOT_SECTOR_BLOCK_ADDRESS_OFFSET);
  1114. if (*BlockAddressPointer != 0) {
  1115. fprintf(stderr,
  1116. "Error: Location for boot sector LBA had %x in it.\n",
  1117. *BlockAddressPointer);
  1118. Result = EIO;
  1119. goto WriteBootSectorFileEnd;
  1120. }
  1121. assert((ULONG)DiskOffset == DiskOffset);
  1122. *BlockAddressPointer = (ULONG)DiskOffset +
  1123. Context->CurrentPartitionOffset;
  1124. BootCodeSizePointer = Block + SETUP_BOOT_SECTOR_BLOCK_LENGTH_OFFSET;
  1125. if (*BootCodeSizePointer != 0) {
  1126. fprintf(stderr,
  1127. "Error: Location for boot sector size had %x in "
  1128. "it.\n",
  1129. *BootCodeSizePointer);
  1130. Result = EIO;
  1131. goto WriteBootSectorFileEnd;
  1132. }
  1133. *BootCodeSizePointer = (UCHAR)BlockCount;
  1134. }
  1135. //
  1136. // Go back to that block and write it out.
  1137. //
  1138. SeekResult = SetupPartitionSeek(
  1139. Context,
  1140. Context->Disk,
  1141. DiskOffset + (Offset / SETUP_BLOCK_SIZE) - 1);
  1142. if (SeekResult != DiskOffset + (Offset / SETUP_BLOCK_SIZE) - 1) {
  1143. fprintf(stderr, "Error: Seek failed.\n");
  1144. Result = errno;
  1145. if (Result == 0) {
  1146. Result = -1;
  1147. }
  1148. goto WriteBootSectorFileEnd;
  1149. }
  1150. BytesDone = SetupPartitionWrite(Context,
  1151. Context->Disk,
  1152. Block,
  1153. SETUP_BLOCK_SIZE);
  1154. if (BytesDone != SETUP_BLOCK_SIZE) {
  1155. fprintf(stderr,
  1156. "Error: Wrote only %ld of %d bytes.\n",
  1157. (long)BytesDone,
  1158. SETUP_BLOCK_SIZE);
  1159. Result = errno;
  1160. if (Result == 0) {
  1161. Result = -1;
  1162. }
  1163. goto WriteBootSectorFileEnd;
  1164. }
  1165. }
  1166. Result = 0;
  1167. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  1168. printf("Wrote file %s, size %d to boot sector 0x%llx.\n",
  1169. Command->Source,
  1170. FileSize,
  1171. DiskOffset);
  1172. }
  1173. WriteBootSectorFileEnd:
  1174. if (Block != NULL) {
  1175. free(Block);
  1176. }
  1177. if (FileData != NULL) {
  1178. free(FileData);
  1179. }
  1180. return Result;
  1181. }
  1182. INT
  1183. SetupReadEntireFile (
  1184. PSETUP_CONTEXT Context,
  1185. PVOID Source,
  1186. PCSTR SourcePath,
  1187. PVOID *FileContents,
  1188. PULONG FileContentsSize
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. This routine reads a file's contents into memory.
  1193. Arguments:
  1194. Context - Supplies a pointer to the applicaton context.
  1195. Source - Supplies a pointer to the open source volume handle.
  1196. SourcePath - Supplies the source path of the file to read.
  1197. FileContents - Supplies a pointer where a pointer to the file data will be
  1198. returned on success. The caller is responsible for freeing this
  1199. memory when done.
  1200. FileContentsSize - Supplies a pointer where the size of the file in bytes
  1201. will be returned on success.
  1202. Return Value:
  1203. 0 on success.
  1204. Non-zero on failure.
  1205. --*/
  1206. {
  1207. PVOID Buffer;
  1208. ULONGLONG FileSize;
  1209. mode_t Mode;
  1210. time_t ModificationDate;
  1211. INT Result;
  1212. ssize_t Size;
  1213. PVOID SourceFile;
  1214. FileSize = 0;
  1215. Buffer = NULL;
  1216. SourceFile = SetupFileOpen(Source, SourcePath, O_RDONLY, 0);
  1217. if (SourceFile == NULL) {
  1218. fprintf(stderr, "Failed to open source file %s.\n", SourcePath);
  1219. Result = errno;
  1220. if (Result == 0) {
  1221. Result = -1;
  1222. }
  1223. goto ReadEntireFileEnd;
  1224. }
  1225. Result = SetupFileFileStat(SourceFile, &FileSize, &ModificationDate, &Mode);
  1226. if (Result != 0) {
  1227. goto ReadEntireFileEnd;
  1228. }
  1229. //
  1230. // If this is a directory, create a directory in the destination.
  1231. //
  1232. if (S_ISDIR(Mode) != 0) {
  1233. fprintf(stderr,
  1234. "Error: Setup tried to read in file %s but got a directory.\n",
  1235. SourcePath);
  1236. Result = EISDIR;
  1237. goto ReadEntireFileEnd;
  1238. }
  1239. //
  1240. // This is a regular file, so open it up and read it.
  1241. //
  1242. Buffer = malloc(FileSize);
  1243. if (Buffer == NULL) {
  1244. Result = ENOMEM;
  1245. goto ReadEntireFileEnd;
  1246. }
  1247. Size = SetupFileRead(SourceFile, Buffer, FileSize);
  1248. if (Size != FileSize) {
  1249. fprintf(stderr,
  1250. "Failed to read in file %s, got %d of %d bytes.\n",
  1251. SourcePath,
  1252. (ULONG)Size,
  1253. (ULONG)FileSize);
  1254. Result = errno;
  1255. goto ReadEntireFileEnd;
  1256. }
  1257. Result = 0;
  1258. ReadEntireFileEnd:
  1259. if (SourceFile != NULL) {
  1260. SetupFileClose(SourceFile);
  1261. }
  1262. if (Result != 0) {
  1263. if (Buffer != NULL) {
  1264. free(Buffer);
  1265. }
  1266. FileSize = 0;
  1267. }
  1268. *FileContents = Buffer;
  1269. assert((ULONG)FileSize == FileSize);
  1270. *FileContentsSize = FileSize;
  1271. return Result;
  1272. }
  1273. PSETUP_PARTITION_CONFIGURATION
  1274. SetupGetPartition (
  1275. PSETUP_CONTEXT Context,
  1276. ULONG Flag
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. This routine is used to retrieve a given partition, usually either the boot
  1281. or system partition.
  1282. Arguments:
  1283. Context - Supplies a pointer to the application context.
  1284. Flag - Supplies the partition flag to search for. See
  1285. SETUP_PARTITION_FLAG_* definitions.
  1286. Return Value:
  1287. Returns a pointer to the desired partition on success.
  1288. NULL if no matching partition could be found.
  1289. --*/
  1290. {
  1291. ULONG Count;
  1292. ULONG Index;
  1293. PSETUP_PARTITION_CONFIGURATION Partition;
  1294. Partition = Context->Configuration->Disk.Partitions;
  1295. Count = Context->Configuration->Disk.PartitionCount;
  1296. for (Index = 0; Index < Count; Index += 1) {
  1297. if ((Partition->Flags & Flag) != 0) {
  1298. return Partition;
  1299. }
  1300. Partition += 1;
  1301. }
  1302. return NULL;
  1303. }
  1304. PVOID
  1305. SetupGetSourceVolume (
  1306. PSETUP_CONTEXT Context,
  1307. ULONG SourceVolume
  1308. )
  1309. /*++
  1310. Routine Description:
  1311. This routine gets the source volume given the source volume index.
  1312. Arguments:
  1313. Context - Supplies a pointer to the application context.
  1314. SourceVolume - Supplies the source volume index.
  1315. Return Value:
  1316. Returns a pointer to the open volume on success.
  1317. NULL if the source volume index is invalid.
  1318. --*/
  1319. {
  1320. PVOID Source;
  1321. if (SourceVolume == 0) {
  1322. Source = Context->SourceVolume;
  1323. } else if (SourceVolume == (ULONG)-1L) {
  1324. Source = Context->HostFileSystem;
  1325. } else {
  1326. fprintf(stderr,
  1327. "Error: Invalid source volume %d.\n",
  1328. SourceVolume);
  1329. Source = NULL;
  1330. }
  1331. return Source;
  1332. }