util.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  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. util.c
  9. Abstract:
  10. This module implements utility functions for the setup program.
  11. Author:
  12. Evan Green 10-Apr-2014
  13. Environment:
  14. User
  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 "setup.h"
  28. #include "sconf.h"
  29. //
  30. // ---------------------------------------------------------------- Definitions
  31. //
  32. #define SETUP_FILE_BUFFER_SIZE (1024 * 512)
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // ----------------------------------------------- Internal Function Prototypes
  38. //
  39. //
  40. // -------------------------------------------------------------------- Globals
  41. //
  42. PSTR SetupPartitionDescriptions[] = {
  43. "Invalid",
  44. "",
  45. "Unknown",
  46. "Empty",
  47. "FAT12",
  48. "FAT16",
  49. "Extended",
  50. "NTFS",
  51. "FAT32",
  52. "FAT32L",
  53. "FAT16",
  54. "ExtendedLba",
  55. "WinRE",
  56. "Plan9",
  57. "Hurd",
  58. "Minoca",
  59. "Minix",
  60. "Minix",
  61. "Linux Swap",
  62. "Linux",
  63. "LinuxExtended",
  64. "LinuxLVM",
  65. "BSD",
  66. "FreeBSD",
  67. "OpenBSD",
  68. "NeXTStep",
  69. "MacOSX",
  70. "NetBSD",
  71. "MacOSXBoot",
  72. "HFS",
  73. "EFIGPT",
  74. "EFISystem",
  75. };
  76. //
  77. // ------------------------------------------------------------------ Functions
  78. //
  79. PSETUP_DESTINATION
  80. SetupCreateDestination (
  81. SETUP_DESTINATION_TYPE Type,
  82. PSTR Path,
  83. DEVICE_ID DeviceId
  84. )
  85. /*++
  86. Routine Description:
  87. This routine creates a setup destination structure.
  88. Arguments:
  89. Type - Supplies the destination type.
  90. Path - Supplies an optional pointer to the path. A copy of this string will
  91. be made.
  92. DeviceId - Supplies an optional device ID.
  93. Return Value:
  94. Returns a pointer to the newly created destination on success.
  95. NULL on allocation failure.
  96. --*/
  97. {
  98. PSETUP_DESTINATION Destination;
  99. Destination = malloc(sizeof(SETUP_DESTINATION));
  100. if (Destination == NULL) {
  101. return NULL;
  102. }
  103. memset(Destination, 0, sizeof(SETUP_DESTINATION));
  104. Destination->Type = Type;
  105. Destination->DeviceId = DeviceId;
  106. if (Path != NULL) {
  107. Destination->Path = strdup(Path);
  108. if (Destination->Path == NULL) {
  109. free(Destination);
  110. return NULL;
  111. }
  112. }
  113. return Destination;
  114. }
  115. VOID
  116. SetupDestroyDestination (
  117. PSETUP_DESTINATION Destination
  118. )
  119. /*++
  120. Routine Description:
  121. This routine destroys a setup destination structure.
  122. Arguments:
  123. Destination - Supplies a pointer to the destination structure to free.
  124. Return Value:
  125. None.
  126. --*/
  127. {
  128. if (Destination->Path != NULL) {
  129. free(Destination->Path);
  130. }
  131. free(Destination);
  132. return;
  133. }
  134. VOID
  135. SetupDestroyDeviceDescriptions (
  136. PSETUP_PARTITION_DESCRIPTION Devices,
  137. ULONG DeviceCount
  138. )
  139. /*++
  140. Routine Description:
  141. This routine destroys an array of device descriptions.
  142. Arguments:
  143. Devices - Supplies a pointer to the array to destroy.
  144. DeviceCount - Supplies the number of elements in the array.
  145. Return Value:
  146. None.
  147. --*/
  148. {
  149. ULONG Index;
  150. for (Index = 0; Index < DeviceCount; Index += 1) {
  151. if (Devices[Index].Destination != NULL) {
  152. SetupDestroyDestination(Devices[Index].Destination);
  153. }
  154. }
  155. free(Devices);
  156. return;
  157. }
  158. VOID
  159. SetupPrintDeviceDescription (
  160. PSETUP_PARTITION_DESCRIPTION Device,
  161. BOOL PrintHeader
  162. )
  163. /*++
  164. Routine Description:
  165. This routine prints a device description.
  166. Arguments:
  167. Device - Supplies a pointer to the device description.
  168. PrintHeader - Supplies a boolean indicating if the column descriptions
  169. should be printed.
  170. Return Value:
  171. None.
  172. --*/
  173. {
  174. PSTR DeviceType;
  175. ULONG DiskId;
  176. ULONGLONG Offset;
  177. CHAR OffsetString[20];
  178. CHAR PartitionFlavor;
  179. ULONG PartitionId;
  180. PSTR PartitionScheme;
  181. PSTR PartitionTypeString;
  182. ULONGLONG Size;
  183. CHAR SizeString[20];
  184. CHAR System;
  185. DeviceType = "Partition";
  186. PartitionFlavor = ' ';
  187. System = ' ';
  188. PartitionScheme = "";
  189. if (Device->Partition.PartitionFormat == PartitionFormatGpt) {
  190. PartitionScheme = "GPT";
  191. } else if (Device->Partition.PartitionFormat == PartitionFormatMbr) {
  192. PartitionScheme = "MBR";
  193. }
  194. if ((Device->Partition.Flags & PARTITION_FLAG_RAW_DISK) != 0) {
  195. DeviceType = "Disk";
  196. } else if ((Device->Partition.Flags & PARTITION_FLAG_BOOT) != 0) {
  197. PartitionFlavor = 'B';
  198. } else if ((Device->Partition.Flags & PARTITION_FLAG_EXTENDED) != 0) {
  199. PartitionFlavor = 'E';
  200. } else if ((Device->Partition.Flags & PARTITION_FLAG_LOGICAL) != 0) {
  201. PartitionFlavor = 'L';
  202. }
  203. if ((Device->Flags & SETUP_DEVICE_FLAG_SYSTEM) != 0) {
  204. System = 'S';
  205. }
  206. RtlCopyMemory(&DiskId, &(Device->Partition.DiskId[0]), sizeof(ULONG));
  207. if (Device->Partition.PartitionFormat == PartitionFormatMbr) {
  208. RtlCopyMemory(&PartitionId,
  209. &(Device->Partition.PartitionId[sizeof(ULONG)]),
  210. sizeof(ULONG));
  211. } else {
  212. RtlCopyMemory(&PartitionId,
  213. &(Device->Partition.PartitionId[0]),
  214. sizeof(ULONG));
  215. }
  216. PartitionTypeString = "";
  217. if (Device->Partition.PartitionType <
  218. sizeof(SetupPartitionDescriptions) /
  219. sizeof(SetupPartitionDescriptions[0])) {
  220. PartitionTypeString =
  221. SetupPartitionDescriptions[Device->Partition.PartitionType];
  222. }
  223. Offset = Device->Partition.FirstBlock * Device->Partition.BlockSize;
  224. SetupPrintSize(OffsetString, sizeof(OffsetString), Offset);
  225. Size = ((Device->Partition.LastBlock + 1) * Device->Partition.BlockSize) -
  226. Offset;
  227. SetupPrintSize(SizeString, sizeof(SizeString), Size);
  228. if (PrintHeader != FALSE) {
  229. printf(" DiskId PartID DevType Fmt Type Offset "
  230. "Size Path\n");
  231. printf(" --------------------------------------------------------"
  232. "--------------------\n");
  233. }
  234. printf(" %08X %08X %-9s %3s %c%c %-13s %-6s %-6s ",
  235. DiskId,
  236. PartitionId,
  237. DeviceType,
  238. PartitionScheme,
  239. PartitionFlavor,
  240. System,
  241. PartitionTypeString,
  242. OffsetString,
  243. SizeString);
  244. SetupPrintDestination(Device->Destination);
  245. printf("\n");
  246. return;
  247. }
  248. ULONG
  249. SetupPrintSize (
  250. PCHAR String,
  251. ULONG StringSize,
  252. ULONGLONG Value
  253. )
  254. /*++
  255. Routine Description:
  256. This routine prints a formatted size a la 5.8M (M for megabytes).
  257. Arguments:
  258. String - Supplies a pointer to the string buffer to print to.
  259. StringSize - Supplies the total size of the string buffer in bytes.
  260. Value - Supplies the value in bytes to print.
  261. Return Value:
  262. Returns the number of bytes successfully converted.
  263. --*/
  264. {
  265. ULONG Size;
  266. CHAR Suffix;
  267. Suffix = 'B';
  268. if (Value > 1024) {
  269. Suffix = 'K';
  270. Value = (Value * 10) / 1024;
  271. if (Value / 10 >= 1024) {
  272. Suffix = 'M';
  273. Value /= 1024;
  274. if (Value / 10 >= 1024) {
  275. Suffix = 'G';
  276. Value /= 1024;
  277. if (Value / 10 >= 1024) {
  278. Suffix = 'T';
  279. Value /= 1024;
  280. }
  281. }
  282. }
  283. }
  284. if (Suffix == 'B') {
  285. Size = snprintf(String, StringSize, "%d", (ULONG)Value);
  286. } else {
  287. if (Value < 100) {
  288. Size = snprintf(String,
  289. StringSize,
  290. "%d.%d%c",
  291. (ULONG)Value / 10,
  292. (ULONG)Value % 10,
  293. Suffix);
  294. } else {
  295. Size = snprintf(String,
  296. StringSize,
  297. "%d%c",
  298. (ULONG)Value / 10,
  299. Suffix);
  300. }
  301. }
  302. return Size;
  303. }
  304. VOID
  305. SetupPrintDestination (
  306. PSETUP_DESTINATION Destination
  307. )
  308. /*++
  309. Routine Description:
  310. This routine prints a destination structure.
  311. Arguments:
  312. Destination - Supplies a pointer to the destination.
  313. Return Value:
  314. None.
  315. --*/
  316. {
  317. if (Destination->Path != NULL) {
  318. printf("%s", Destination->Path);
  319. } else {
  320. printf("Device 0x%llX", Destination->DeviceId);
  321. }
  322. return;
  323. }
  324. PSETUP_DESTINATION
  325. SetupParseDestination (
  326. SETUP_DESTINATION_TYPE DestinationType,
  327. PSTR Argument
  328. )
  329. /*++
  330. Routine Description:
  331. This routine converts a string argument into a destination. Device ID
  332. destinations can start with "0x", and everything else is treated as a
  333. path. An empty string is not valid.
  334. Arguments:
  335. DestinationType - Supplies the destination type.
  336. Argument - Supplies the string argument.
  337. Return Value:
  338. Returns a pointer to a newly created destination on success. The caller
  339. is responsible for destroying this structure.
  340. NULL if the argument is not valid.
  341. --*/
  342. {
  343. PSTR AfterScan;
  344. ULONGLONG DeviceId;
  345. if (*Argument == '\0') {
  346. return NULL;
  347. }
  348. if ((Argument[0] == '0') &&
  349. ((Argument[1] == 'x') || (Argument[1] == 'X'))) {
  350. DeviceId = strtoull(Argument, &AfterScan, 16);
  351. if (*AfterScan != '\0') {
  352. return NULL;
  353. }
  354. return SetupCreateDestination(DestinationType, NULL, DeviceId);
  355. }
  356. return SetupCreateDestination(DestinationType, Argument, 0);
  357. }
  358. PSTR
  359. SetupAppendPaths (
  360. PCSTR Path1,
  361. PCSTR Path2
  362. )
  363. /*++
  364. Routine Description:
  365. This routine appends two paths to one another.
  366. Arguments:
  367. Path1 - Supplies a pointer to the first path.
  368. Path2 - Supplies a pointer to the second path.
  369. Return Value:
  370. Returns a pointer to a newly created combined path on success. The caller
  371. is responsible for freeing this new path.
  372. NULL on allocation failure.
  373. --*/
  374. {
  375. size_t Length1;
  376. size_t Length2;
  377. PSTR NewPath;
  378. if (Path1 == NULL) {
  379. return strdup(Path2);
  380. }
  381. Length1 = strlen(Path1);
  382. Length2 = strlen(Path2);
  383. NewPath = malloc(Length1 + Length2 + 2);
  384. if (NewPath == NULL) {
  385. return NULL;
  386. }
  387. strcpy(NewPath, Path1);
  388. if ((Length1 != 0) && (Path1[Length1 - 1] != '/')) {
  389. NewPath[Length1] = '/';
  390. Length1 += 1;
  391. }
  392. strcpy(NewPath + Length1, Path2);
  393. return NewPath;
  394. }
  395. INT
  396. SetupConvertStringArrayToLines (
  397. PCSTR *StringArray,
  398. PSTR *ResultBuffer,
  399. PUINTN ResultBufferSize
  400. )
  401. /*++
  402. Routine Description:
  403. This routine converts a null-terminated array of strings into a single
  404. buffer where each element is separated by a newline.
  405. Arguments:
  406. StringArray - Supplies a pointer to the array of strings. The array must be
  407. terminated by a NULL entry.
  408. ResultBuffer - Supplies a pointer where a string will be returned
  409. containing all the lines. The caller is responsible for freeing this
  410. buffer.
  411. ResultBufferSize - Supplies a pointer where size of the buffer in bytes
  412. will be returned, including the null terminator.
  413. Return Value:
  414. 0 on success.
  415. ENOMEM on allocation failure.
  416. --*/
  417. {
  418. UINTN AllocationSize;
  419. PCSTR *Array;
  420. PSTR Buffer;
  421. PSTR Current;
  422. size_t Length;
  423. AllocationSize = 1;
  424. Array = StringArray;
  425. while (*Array != NULL) {
  426. AllocationSize += strlen(*Array) + 1;
  427. Array += 1;
  428. }
  429. Buffer = malloc(AllocationSize);
  430. if (Buffer == NULL) {
  431. return ENOMEM;
  432. }
  433. Current = Buffer;
  434. Array = StringArray;
  435. while (*Array != NULL) {
  436. Length = strlen(*Array);
  437. memcpy(Current, *Array, Length);
  438. Current[Length] = '\n';
  439. Current += Length + 1;
  440. Array += 1;
  441. }
  442. *Current = '\0';
  443. *ResultBuffer = Buffer;
  444. *ResultBufferSize = AllocationSize;
  445. return 0;
  446. }
  447. INT
  448. SetupCopyFile (
  449. PSETUP_CONTEXT Context,
  450. PVOID Destination,
  451. PVOID Source,
  452. PCSTR DestinationPath,
  453. PCSTR SourcePath,
  454. ULONG Flags
  455. )
  456. /*++
  457. Routine Description:
  458. This routine copies the given path from the source to the destination. If
  459. the source is a directory, the contents of that directory are recursively
  460. copied to the destination.
  461. Arguments:
  462. Context - Supplies a pointer to the applicaton context.
  463. Destination - Supplies a pointer to the open destination volume
  464. handle.
  465. Source - Supplies a pointer to the open source volume handle.
  466. DestinationPath - Supplies a pointer to the path of the file to create at
  467. the destination.
  468. SourcePath - Supplies the source path of the copy.
  469. Flags - Supplies a bitfield of flags governing the operation. See
  470. SETUP_COPY_FLAG_* definitions.
  471. Return Value:
  472. 0 on success.
  473. Non-zero on failure.
  474. --*/
  475. {
  476. PSTR AppendedDestinationPath;
  477. PSTR AppendedSourcePath;
  478. PVOID Buffer;
  479. PVOID DestinationFile;
  480. PSTR DirectoryEntry;
  481. PSTR Enumeration;
  482. mode_t ExistingMode;
  483. time_t ExistingModificationDate;
  484. ULONGLONG FileSize;
  485. PSTR LinkTarget;
  486. INT LinkTargetSize;
  487. mode_t Mode;
  488. time_t ModificationDate;
  489. INT Result;
  490. ssize_t Size;
  491. ssize_t SizeWritten;
  492. PVOID SourceFile;
  493. AppendedDestinationPath = NULL;
  494. AppendedSourcePath = NULL;
  495. Buffer = NULL;
  496. DestinationFile = NULL;
  497. FileSize = 0;
  498. Enumeration = NULL;
  499. LinkTarget = NULL;
  500. Mode = 0;
  501. ModificationDate = 0;
  502. Result = -1;
  503. SourceFile = SetupFileOpen(Source, SourcePath, O_RDONLY | O_NOFOLLOW, 0);
  504. //
  505. // Some OSes don't allow opening of directories. If the source open failed
  506. // and the error is that it's a directory, then handle that.
  507. //
  508. if ((SourceFile == NULL) && (errno == EISDIR)) {
  509. Mode = S_IFDIR | FILE_PERMISSION_USER_ALL | FILE_PERMISSION_GROUP_ALL |
  510. FILE_PERMISSION_OTHER_READ |
  511. FILE_PERMISSION_OTHER_EXECUTE;
  512. ModificationDate = time(NULL);
  513. } else if (SourceFile == NULL) {
  514. //
  515. // If the file could not be opened, maybe it's a symbolic link. Try to
  516. // read that.
  517. //
  518. Result = SetupFileReadLink(Source,
  519. SourcePath,
  520. &LinkTarget,
  521. &LinkTargetSize);
  522. if (Result != 0) {
  523. Result = errno;
  524. //
  525. // Forgive optional copies if they don't exist.
  526. //
  527. if ((Result == ENOENT) &&
  528. ((Flags & SETUP_COPY_FLAG_OPTIONAL) != 0)) {
  529. Result = 0;
  530. } else {
  531. fprintf(stderr,
  532. "Failed to open source file %s: %s\n",
  533. SourcePath,
  534. strerror(Result));
  535. if (Result == 0) {
  536. Result = -1;
  537. }
  538. }
  539. goto CopyFileEnd;
  540. }
  541. //
  542. // Try to create a link in the target.
  543. //
  544. Result = SetupFileSymlink(Destination,
  545. DestinationPath,
  546. LinkTarget,
  547. LinkTargetSize);
  548. //
  549. // If not possible, fall back to copying the file.
  550. //
  551. if (Result == 0) {
  552. goto CopyFileEnd;
  553. }
  554. fprintf(stderr,
  555. "Failed to create symbolic link at %s, copying instead.\n",
  556. DestinationPath);
  557. SourceFile = SetupFileOpen(Source, LinkTarget, O_RDONLY, 0);
  558. if (SourceFile == NULL) {
  559. fprintf(stderr,
  560. "Failed to open source file link %s.\n",
  561. LinkTarget);
  562. Result = errno;
  563. if (Result == 0) {
  564. Result = -1;
  565. }
  566. goto CopyFileEnd;
  567. }
  568. }
  569. if (SourceFile != NULL) {
  570. Result = SetupFileFileStat(SourceFile,
  571. &FileSize,
  572. &ModificationDate,
  573. &Mode);
  574. if (Result != 0) {
  575. goto CopyFileEnd;
  576. }
  577. }
  578. //
  579. // If this is a directory, create a directory in the destination.
  580. //
  581. if (S_ISDIR(Mode) != 0) {
  582. if (S_IRGRP == 0) {
  583. if ((Mode & S_IRUSR) != 0) {
  584. Mode |= FILE_PERMISSION_GROUP_READ |
  585. FILE_PERMISSION_OTHER_READ |
  586. FILE_PERMISSION_USER_EXECUTE |
  587. FILE_PERMISSION_GROUP_EXECUTE |
  588. FILE_PERMISSION_OTHER_EXECUTE;
  589. }
  590. }
  591. //
  592. // Attempt to create the destination directory at once. If it fails,
  593. // perhaps the directories leading up to it must be created.
  594. //
  595. Result = SetupFileCreateDirectory(Destination,
  596. DestinationPath,
  597. Mode);
  598. if (Result != 0) {
  599. Result = SetupCreateDirectories(Context,
  600. Destination,
  601. DestinationPath);
  602. if (Result == 0) {
  603. Result = SetupFileCreateDirectory(Destination,
  604. DestinationPath,
  605. Mode);
  606. }
  607. }
  608. if (Result != 0) {
  609. Result = errno;
  610. fprintf(stderr,
  611. "Failed to create destination directory %s.\n",
  612. DestinationPath);
  613. if (Result == 0) {
  614. Result = -1;
  615. }
  616. goto CopyFileEnd;
  617. }
  618. Result = SetupFileEnumerateDirectory(Source, SourcePath, &Enumeration);
  619. if (Result != 0) {
  620. fprintf(stderr, "Failed to enumerate directory %s.\n", SourcePath);
  621. goto CopyFileEnd;
  622. }
  623. //
  624. // Loop over every file in the directory.
  625. //
  626. DirectoryEntry = Enumeration;
  627. while (*DirectoryEntry != '\0') {
  628. AppendedDestinationPath = SetupAppendPaths(DestinationPath,
  629. DirectoryEntry);
  630. if (AppendedDestinationPath == NULL) {
  631. Result = ENOMEM;
  632. goto CopyFileEnd;
  633. }
  634. AppendedSourcePath = SetupAppendPaths(SourcePath, DirectoryEntry);
  635. if (AppendedSourcePath == NULL) {
  636. Result = ENOMEM;
  637. goto CopyFileEnd;
  638. }
  639. //
  640. // Recurse and copy each file inside the directory.
  641. //
  642. Result = SetupCopyFile(Context,
  643. Destination,
  644. Source,
  645. AppendedDestinationPath,
  646. AppendedSourcePath,
  647. Flags);
  648. if (Result != 0) {
  649. fprintf(stderr,
  650. "Failed to copy %s.\n",
  651. AppendedDestinationPath);
  652. goto CopyFileEnd;
  653. }
  654. free(AppendedDestinationPath);
  655. free(AppendedSourcePath);
  656. AppendedDestinationPath = NULL;
  657. AppendedSourcePath = NULL;
  658. DirectoryEntry += strlen(DirectoryEntry) + 1;
  659. }
  660. //
  661. // Set directory permissions.
  662. //
  663. Result = SetupFileSetAttributes(Destination,
  664. DestinationPath,
  665. ModificationDate,
  666. Mode);
  667. if (Result != 0) {
  668. fprintf(stderr,
  669. "Failed to set mode on directory %s.\n",
  670. DestinationPath);
  671. goto CopyFileEnd;
  672. }
  673. //
  674. // This is a regular file, so open it up in the destination and copy it in
  675. // chunks.
  676. //
  677. } else {
  678. //
  679. // If this is an update operation, first try to open up the destination
  680. // to see if it is newer than the source.
  681. //
  682. if ((Flags & SETUP_COPY_FLAG_UPDATE) != 0) {
  683. DestinationFile = SetupFileOpen(Destination,
  684. DestinationPath,
  685. O_RDONLY | O_NOFOLLOW,
  686. 0);
  687. if (DestinationFile != NULL) {
  688. Result = SetupFileFileStat(DestinationFile,
  689. NULL,
  690. &ExistingModificationDate,
  691. &ExistingMode);
  692. SetupFileClose(DestinationFile);
  693. DestinationFile = NULL;
  694. if (Result != 0) {
  695. goto CopyFileEnd;
  696. }
  697. //
  698. // If the existing one is the same type of file and is at least
  699. // as new, don't update it.
  700. //
  701. if ((ExistingModificationDate >= ModificationDate) &&
  702. (((ExistingMode ^ Mode) & S_IFMT) == 0)) {
  703. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  704. printf("Skipping %s -> %s\n",
  705. SourcePath,
  706. DestinationPath);
  707. }
  708. Result = 0;
  709. goto CopyFileEnd;
  710. }
  711. }
  712. }
  713. //
  714. // Some OSes don't have an executable bit, but still need to be able
  715. // to install executables onto OSes that do. Probe around a bit to see
  716. // if the file should be set executable.
  717. //
  718. if ((Mode & FILE_PERMISSION_ALL_EXECUTE) == 0) {
  719. SetupFileDetermineExecuteBit(SourceFile, SourcePath, &Mode);
  720. }
  721. Buffer = malloc(SETUP_FILE_BUFFER_SIZE);
  722. if (Buffer == NULL) {
  723. Result = ENOMEM;
  724. goto CopyFileEnd;
  725. }
  726. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  727. printf("Copying %s -> %s\n", SourcePath, DestinationPath);
  728. }
  729. SetupCreateDirectories(Context, Destination, DestinationPath);
  730. DestinationFile = SetupFileOpen(Destination,
  731. DestinationPath,
  732. O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW,
  733. Mode);
  734. if (DestinationFile == NULL) {
  735. Result = errno;
  736. fprintf(stderr,
  737. "Failed to create destination file %s.\n",
  738. DestinationPath);
  739. if (Result == 0) {
  740. Result = -1;
  741. }
  742. goto CopyFileEnd;
  743. }
  744. //
  745. // Loop copying chunks.
  746. //
  747. while (FileSize != 0) {
  748. Size = SETUP_FILE_BUFFER_SIZE;
  749. if (Size > FileSize) {
  750. Size = FileSize;
  751. }
  752. Size = SetupFileRead(SourceFile, Buffer, Size);
  753. if (Size <= 0) {
  754. if (Size < 0) {
  755. Result = errno;
  756. if (Result == 0) {
  757. Result = EINVAL;
  758. }
  759. goto CopyFileEnd;
  760. }
  761. break;
  762. }
  763. SizeWritten = SetupFileWrite(DestinationFile, Buffer, Size);
  764. if (SizeWritten != Size) {
  765. fprintf(stderr,
  766. "Failed to write to file %s.\n",
  767. DestinationPath);
  768. Result = errno;
  769. if (Result == 0) {
  770. Result = errno;
  771. }
  772. goto CopyFileEnd;
  773. }
  774. FileSize -= Size;
  775. }
  776. //
  777. // Set file permissions.
  778. //
  779. SetupFileClose(DestinationFile);
  780. DestinationFile = NULL;
  781. Result = SetupFileSetAttributes(Destination,
  782. DestinationPath,
  783. ModificationDate,
  784. Mode);
  785. if (Result != 0) {
  786. fprintf(stderr,
  787. "Failed to set mode on file %s, ModData %llx Mode %x, "
  788. "Result %d\n",
  789. DestinationPath,
  790. (ULONGLONG)ModificationDate,
  791. Mode,
  792. Result);
  793. goto CopyFileEnd;
  794. }
  795. }
  796. CopyFileEnd:
  797. if (AppendedDestinationPath != NULL) {
  798. free(AppendedDestinationPath);
  799. }
  800. if (AppendedSourcePath != NULL) {
  801. free(AppendedSourcePath);
  802. }
  803. if (DestinationFile != NULL) {
  804. SetupFileClose(DestinationFile);
  805. }
  806. if (SourceFile != NULL) {
  807. SetupFileClose(SourceFile);
  808. }
  809. if (Enumeration != NULL) {
  810. free(Enumeration);
  811. }
  812. if (Buffer != NULL) {
  813. free(Buffer);
  814. }
  815. return Result;
  816. }
  817. INT
  818. SetupCreateAndWriteFile (
  819. PSETUP_CONTEXT Context,
  820. PVOID Destination,
  821. PCSTR DestinationPath,
  822. PVOID Contents,
  823. ULONG ContentsSize
  824. )
  825. /*++
  826. Routine Description:
  827. This routine creates a file and writes the given contents out to it.
  828. Arguments:
  829. Context - Supplies a pointer to the applicaton context.
  830. Destination - Supplies a pointer to the open destination volume
  831. handle.
  832. DestinationPath - Supplies a pointer to the path of the file to create at
  833. the destination.
  834. Contents - Supplies the buffer containing the file contents to write.
  835. ContentsSize - Supplies the size of the buffer in bytes.
  836. Return Value:
  837. 0 on success.
  838. Non-zero on failure.
  839. --*/
  840. {
  841. PVOID DestinationFile;
  842. mode_t Mode;
  843. INT Status;
  844. size_t TotalWritten;
  845. ssize_t Written;
  846. Status = 0;
  847. Mode = FILE_PERMISSION_USER_READ |
  848. FILE_PERMISSION_USER_WRITE |
  849. FILE_PERMISSION_GROUP_READ |
  850. FILE_PERMISSION_GROUP_WRITE |
  851. FILE_PERMISSION_OTHER_READ;
  852. if ((Context->Flags & SETUP_FLAG_VERBOSE) != 0) {
  853. printf("Creating %s\n", DestinationPath);
  854. }
  855. SetupCreateDirectories(Context, Destination, DestinationPath);
  856. DestinationFile = SetupFileOpen(Destination,
  857. DestinationPath,
  858. O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW,
  859. Mode);
  860. if (DestinationFile == NULL) {
  861. fprintf(stderr,
  862. "Failed to create destination file %s.\n",
  863. DestinationPath);
  864. goto CreateAndWriteFileEnd;
  865. }
  866. //
  867. // Loop copying chunks.
  868. //
  869. TotalWritten = 0;
  870. while (TotalWritten != ContentsSize) {
  871. Written = SetupFileWrite(DestinationFile,
  872. Contents + TotalWritten,
  873. ContentsSize - TotalWritten);
  874. if (Written <= 0) {
  875. fprintf(stderr,
  876. "Failed to write %s.\n",
  877. DestinationPath);
  878. Status = errno;
  879. goto CreateAndWriteFileEnd;
  880. }
  881. TotalWritten += Written;
  882. }
  883. CreateAndWriteFileEnd:
  884. if (DestinationFile != NULL) {
  885. SetupFileClose(DestinationFile);
  886. }
  887. return Status;
  888. }
  889. INT
  890. SetupCreateDirectories (
  891. PSETUP_CONTEXT Context,
  892. PVOID Volume,
  893. PCSTR Path
  894. )
  895. /*++
  896. Routine Description:
  897. This routine creates directories up to but not including the final
  898. component of the given path.
  899. Arguments:
  900. Context - Supplies a pointer to the applicaton context.
  901. Volume - Supplies a pointer to the open destination volume handle.
  902. Path - Supplies the full file path. The file itself won't be created, but
  903. all directories leading up to it will. If the path ends in a slash,
  904. all components will be created.
  905. Return Value:
  906. 0 on success.
  907. Non-zero on failure.
  908. --*/
  909. {
  910. PSTR Copy;
  911. ULONG Mode;
  912. PSTR Next;
  913. INT Status;
  914. Copy = strdup(Path);
  915. if (Copy == NULL) {
  916. return ENOMEM;
  917. }
  918. Status = 0;
  919. Mode = FILE_PERMISSION_USER_READ |
  920. FILE_PERMISSION_USER_WRITE |
  921. FILE_PERMISSION_USER_EXECUTE |
  922. FILE_PERMISSION_GROUP_READ |
  923. FILE_PERMISSION_GROUP_WRITE |
  924. FILE_PERMISSION_GROUP_EXECUTE |
  925. FILE_PERMISSION_OTHER_READ |
  926. FILE_PERMISSION_OTHER_EXECUTE;
  927. //
  928. // Get past any leading slashes.
  929. //
  930. Next = Copy;
  931. while (*Next == '/') {
  932. Next += 1;
  933. }
  934. while (TRUE) {
  935. while ((*Next != '\0') && (*Next != '/')) {
  936. Next += 1;
  937. }
  938. //
  939. // If the next character is the ending one, then this was the last
  940. // component. Don't create a directory for it.
  941. //
  942. if (*Next == '\0') {
  943. break;
  944. }
  945. //
  946. // Terminate the string and create the directory.
  947. //
  948. *Next = '\0';
  949. Status = SetupFileCreateDirectory(Volume, Copy, Mode);
  950. if (Status != 0) {
  951. fprintf(stderr,
  952. "Error: Cannot create directories for path %s: %s.\n",
  953. Copy,
  954. strerror(Status));
  955. goto CreateDirectoriesEnd;
  956. }
  957. *Next = '/';
  958. while (*Next == '/') {
  959. Next += 1;
  960. }
  961. }
  962. CreateDirectoriesEnd:
  963. if (Copy != NULL) {
  964. free(Copy);
  965. }
  966. return Status;
  967. }
  968. //
  969. // --------------------------------------------------------- Internal Functions
  970. //