io.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  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. io.c
  9. Abstract:
  10. This module implements support for doing I/O on a Windows host in the setup
  11. application.
  12. Author:
  13. Evan Green 8-Oct-2014
  14. Environment:
  15. User
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. //
  21. // Use CRT 6.1 for stat64.
  22. //
  23. #define __MSVCRT_VERSION__ 0x0601
  24. #include <assert.h>
  25. #include <dirent.h>
  26. #include <errno.h>
  27. #include <fcntl.h>
  28. #include <getopt.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <sys/stat.h>
  33. #include <time.h>
  34. #include <utime.h>
  35. #include <unistd.h>
  36. #include "../setup.h"
  37. #include "win32sup.h"
  38. //
  39. // ---------------------------------------------------------------- Definitions
  40. //
  41. //
  42. // Define some executable file magic words.
  43. //
  44. #define ELF_MAGIC 0x464C457F
  45. #define IMAGE_DOS_SIGNATURE 0x5A4D
  46. #define SCRIPT_SHEBANG 0x2123
  47. //
  48. // ------------------------------------------------------ Data Type Definitions
  49. //
  50. /*++
  51. Structure Description:
  52. This structure describes a handle to an I/O object in the setup app.
  53. Members:
  54. Handle - Stores the device handle.
  55. WinHandle - Stores the Windows handle.
  56. --*/
  57. typedef struct _SETUP_OS_HANDLE {
  58. int Handle;
  59. void *WinHandle;
  60. } SETUP_OS_HANDLE, *PSETUP_OS_HANDLE;
  61. //
  62. // ----------------------------------------------- Internal Function Prototypes
  63. //
  64. //
  65. // -------------------------------------------------------------------- Globals
  66. //
  67. //
  68. // ------------------------------------------------------------------ Functions
  69. //
  70. INT
  71. SetupOsReadLink (
  72. PSTR Path,
  73. PSTR *LinkTarget,
  74. INT *LinkTargetSize
  75. )
  76. /*++
  77. Routine Description:
  78. This routine attempts to read a symbolic link.
  79. Arguments:
  80. Path - Supplies a pointer to the path to open.
  81. LinkTarget - Supplies a pointer where an allocated link target will be
  82. returned on success. The caller is responsible for freeing this memory.
  83. LinkTargetSize - Supplies a pointer where the size of the link target will
  84. be returned on success.
  85. Return Value:
  86. 0 on success.
  87. Returns an error number on failure.
  88. --*/
  89. {
  90. return ENOSYS;
  91. }
  92. INT
  93. SetupOsSymlink (
  94. PSTR Path,
  95. PSTR LinkTarget,
  96. INT LinkTargetSize
  97. )
  98. /*++
  99. Routine Description:
  100. This routine creates a symbolic link.
  101. Arguments:
  102. Path - Supplies a pointer to the path of the symbolic link to create.
  103. LinkTarget - Supplies a pointer to the target of the link.
  104. LinkTargetSize - Supplies a the size of the link target buffer in bytes.
  105. Return Value:
  106. Returns the link size on success.
  107. -1 on failure.
  108. --*/
  109. {
  110. return -1;
  111. }
  112. PVOID
  113. SetupOsOpenDestination (
  114. PSETUP_DESTINATION Destination,
  115. INT Flags,
  116. INT CreatePermissions
  117. )
  118. /*++
  119. Routine Description:
  120. This routine opens a handle to a given destination.
  121. Arguments:
  122. Destination - Supplies a pointer to the destination to open.
  123. Flags - Supplies open flags. See O_* definitions.
  124. CreatePermissions - Supplies optional create permissions.
  125. Return Value:
  126. Returns a pointer to an opaque context on success.
  127. NULL on failure.
  128. --*/
  129. {
  130. PSETUP_OS_HANDLE IoHandle;
  131. PSTR PathCopy;
  132. size_t PathLength;
  133. struct stat Stat;
  134. IoHandle = malloc(sizeof(SETUP_OS_HANDLE));
  135. if (IoHandle == NULL) {
  136. errno = ENOMEM;
  137. return NULL;
  138. }
  139. IoHandle->Handle = -1;
  140. IoHandle->WinHandle = NULL;
  141. if (Destination->Path != NULL) {
  142. IoHandle->Handle = open(Destination->Path,
  143. Flags | O_BINARY,
  144. CreatePermissions);
  145. if (IoHandle->Handle < 0) {
  146. //
  147. // Windows doesn't allow opening directories. Make the error
  148. // unambiguous if this is a directory.
  149. //
  150. if ((stat(Destination->Path, &Stat) == 0) &&
  151. (S_ISDIR(Stat.st_mode))) {
  152. errno = EISDIR;
  153. } else {
  154. //
  155. // Windows doesn't allow opening a path with a slash on the
  156. // end. If the non-slash version works, then the error is it's
  157. // a directory.
  158. //
  159. PathLength = strlen(Destination->Path);
  160. if ((PathLength != 0) &&
  161. (Destination->Path[PathLength - 1] == '/')) {
  162. PathCopy = strdup(Destination->Path);
  163. if (PathCopy == NULL) {
  164. free(IoHandle);
  165. return NULL;
  166. }
  167. while ((PathLength > 1) &&
  168. (PathCopy[PathLength - 1] == '/')) {
  169. PathCopy[PathLength - 1] = '\0';
  170. PathLength -= 1;
  171. }
  172. if ((stat(PathCopy, &Stat) == 0) &&
  173. (S_ISDIR(Stat.st_mode))) {
  174. errno = EISDIR;
  175. }
  176. free(PathCopy);
  177. }
  178. }
  179. free(IoHandle);
  180. return NULL;
  181. }
  182. } else {
  183. IoHandle->WinHandle = SetupWin32OpenDeviceId(Destination->DeviceId);
  184. if (IoHandle->WinHandle == NULL) {
  185. free(IoHandle);
  186. return NULL;
  187. }
  188. }
  189. return IoHandle;
  190. }
  191. VOID
  192. SetupOsClose (
  193. PVOID Handle
  194. )
  195. /*++
  196. Routine Description:
  197. This routine closes a handle.
  198. Arguments:
  199. Handle - Supplies a pointer to the destination to open.
  200. Return Value:
  201. None.
  202. --*/
  203. {
  204. PSETUP_OS_HANDLE IoHandle;
  205. IoHandle = Handle;
  206. if (IoHandle->WinHandle != NULL) {
  207. SetupWin32Close(IoHandle->WinHandle);
  208. }
  209. if (IoHandle->Handle >= 0) {
  210. close(IoHandle->Handle);
  211. }
  212. free(IoHandle);
  213. return;
  214. }
  215. ssize_t
  216. SetupOsRead (
  217. PVOID Handle,
  218. void *Buffer,
  219. size_t ByteCount
  220. )
  221. /*++
  222. Routine Description:
  223. This routine reads from an open handle.
  224. Arguments:
  225. Handle - Supplies the handle.
  226. Buffer - Supplies a pointer where the read bytes will be returned.
  227. ByteCount - Supplies the number of bytes to read.
  228. Return Value:
  229. Returns the number of bytes read.
  230. -1 on failure.
  231. --*/
  232. {
  233. ssize_t BytesCompleted;
  234. PSETUP_OS_HANDLE IoHandle;
  235. ssize_t TotalBytesRead;
  236. IoHandle = Handle;
  237. if (IoHandle->WinHandle != NULL) {
  238. return SetupWin32Read(IoHandle->WinHandle, Buffer, ByteCount);
  239. }
  240. TotalBytesRead = 0;
  241. while (ByteCount != 0) {
  242. BytesCompleted = read(IoHandle->Handle, Buffer, ByteCount);
  243. if (BytesCompleted <= 0) {
  244. break;
  245. }
  246. Buffer += BytesCompleted;
  247. TotalBytesRead += BytesCompleted;
  248. ByteCount -= BytesCompleted;
  249. }
  250. return TotalBytesRead;
  251. }
  252. ssize_t
  253. SetupOsWrite (
  254. PVOID Handle,
  255. void *Buffer,
  256. size_t ByteCount
  257. )
  258. /*++
  259. Routine Description:
  260. This routine writes data to an open handle.
  261. Arguments:
  262. Handle - Supplies the handle.
  263. Buffer - Supplies a pointer to the bytes to write.
  264. ByteCount - Supplies the number of bytes to read.
  265. Return Value:
  266. Returns the number of bytes written.
  267. -1 on failure.
  268. --*/
  269. {
  270. ssize_t BytesCompleted;
  271. PSETUP_OS_HANDLE IoHandle;
  272. ssize_t TotalBytesWritten;
  273. IoHandle = Handle;
  274. if (IoHandle->WinHandle != NULL) {
  275. return SetupWin32Write(IoHandle->WinHandle, Buffer, ByteCount);
  276. }
  277. TotalBytesWritten = 0;
  278. while (ByteCount != 0) {
  279. BytesCompleted = write(IoHandle->Handle, Buffer, ByteCount);
  280. if (BytesCompleted <= 0) {
  281. perror("Write failed");
  282. break;
  283. }
  284. Buffer += BytesCompleted;
  285. TotalBytesWritten += BytesCompleted;
  286. ByteCount -= BytesCompleted;
  287. }
  288. return TotalBytesWritten;
  289. }
  290. LONGLONG
  291. SetupOsSeek (
  292. PVOID Handle,
  293. LONGLONG Offset
  294. )
  295. /*++
  296. Routine Description:
  297. This routine seeks in the current file or device.
  298. Arguments:
  299. Handle - Supplies the handle.
  300. Offset - Supplies the new offset to set.
  301. Return Value:
  302. Returns the resulting file offset after the operation.
  303. -1 on failure, and errno will contain more information. The file offset
  304. will remain unchanged.
  305. --*/
  306. {
  307. PSETUP_OS_HANDLE IoHandle;
  308. LONGLONG NewOffset;
  309. IoHandle = Handle;
  310. if (IoHandle->WinHandle != NULL) {
  311. return SetupWin32Seek(IoHandle->WinHandle, Offset);
  312. }
  313. NewOffset = _lseeki64(IoHandle->Handle, Offset, SEEK_SET);
  314. return NewOffset;
  315. }
  316. LONGLONG
  317. SetupOsTell (
  318. PVOID Handle
  319. )
  320. /*++
  321. Routine Description:
  322. This routine returns the current offset in the given file or device.
  323. Arguments:
  324. Handle - Supplies the handle.
  325. Return Value:
  326. Returns the file offset on success.
  327. -1 on failure, and errno will contain more information. The file offset
  328. will remain unchanged.
  329. --*/
  330. {
  331. PSETUP_OS_HANDLE IoHandle;
  332. ULONGLONG NewOffset;
  333. IoHandle = Handle;
  334. if (IoHandle->WinHandle != NULL) {
  335. return SetupWin32Tell(IoHandle->WinHandle);
  336. }
  337. NewOffset = _lseeki64(IoHandle->Handle, 0, SEEK_CUR);
  338. return NewOffset;
  339. }
  340. INT
  341. SetupOsFstat (
  342. PVOID Handle,
  343. PULONGLONG FileSize,
  344. time_t *ModificationDate,
  345. mode_t *Mode
  346. )
  347. /*++
  348. Routine Description:
  349. This routine gets details for the given open file.
  350. Arguments:
  351. Handle - Supplies the handle.
  352. FileSize - Supplies an optional pointer where the file size will be
  353. returned on success.
  354. ModificationDate - Supplies an optional pointer where the file's
  355. modification date will be returned on success.
  356. Mode - Supplies an optional pointer where the file's mode information will
  357. be returned on success.
  358. Return Value:
  359. 0 on success.
  360. Non-zero on failure.
  361. --*/
  362. {
  363. PSETUP_OS_HANDLE IoHandle;
  364. int Result;
  365. struct __stat64 Stat;
  366. IoHandle = Handle;
  367. if (IoHandle->WinHandle != NULL) {
  368. if ((ModificationDate != NULL) || (Mode != NULL)) {
  369. fprintf(stderr,
  370. "Error: Modification date and mode cannot be read from a "
  371. "device.\n");
  372. return ENOSYS;
  373. }
  374. if (FileSize == NULL) {
  375. return 0;
  376. }
  377. return SetupWin32FileStat(IoHandle->WinHandle, FileSize);
  378. }
  379. Result = _fstat64(IoHandle->Handle, &Stat);
  380. if (Result != 0) {
  381. return Result;
  382. }
  383. if (FileSize != NULL) {
  384. *FileSize = Stat.st_size;
  385. }
  386. if (ModificationDate != NULL) {
  387. *ModificationDate = Stat.st_mtime;
  388. }
  389. if (Mode != NULL) {
  390. *Mode = Stat.st_mode;
  391. }
  392. return Result;
  393. }
  394. INT
  395. SetupOsFtruncate (
  396. PVOID Handle,
  397. ULONGLONG NewSize
  398. )
  399. /*++
  400. Routine Description:
  401. This routine sets the file size of the given file.
  402. Arguments:
  403. Handle - Supplies the handle.
  404. NewSize - Supplies the new file size.
  405. Return Value:
  406. 0 on success.
  407. Non-zero on failure.
  408. --*/
  409. {
  410. PSETUP_OS_HANDLE IoHandle;
  411. int Result;
  412. IoHandle = Handle;
  413. Result = ftruncate(IoHandle->Handle, NewSize);
  414. return Result;
  415. }
  416. INT
  417. SetupOsEnumerateDirectory (
  418. PVOID Handle,
  419. PSTR DirectoryPath,
  420. PSTR *Enumeration
  421. )
  422. /*++
  423. Routine Description:
  424. This routine enumerates the contents of a given directory.
  425. Arguments:
  426. Handle - Supplies the open volume handle.
  427. DirectoryPath - Supplies a pointer to a string containing the path to the
  428. directory to enumerate.
  429. Enumeration - Supplies a pointer where a pointer to a sequence of
  430. strings will be returned containing the files in the directory. The
  431. sequence will be terminated by an empty string. The caller is
  432. responsible for freeing this memory when done.
  433. Return Value:
  434. 0 on success.
  435. Non-zero on failure.
  436. --*/
  437. {
  438. PSTR Array;
  439. size_t ArrayCapacity;
  440. DIR *Directory;
  441. size_t NameSize;
  442. PVOID NewBuffer;
  443. size_t NewCapacity;
  444. INT Result;
  445. struct dirent *ResultPointer;
  446. size_t UsedSize;
  447. Array = NULL;
  448. ArrayCapacity = 0;
  449. Directory = NULL;
  450. UsedSize = 0;
  451. Directory = opendir(DirectoryPath);
  452. if (Directory == NULL) {
  453. Result = errno;
  454. goto OsEnumerateDirectoryEnd;
  455. }
  456. //
  457. // Loop reading directory entries.
  458. //
  459. while (TRUE) {
  460. ResultPointer = readdir(Directory);
  461. if (ResultPointer == NULL) {
  462. NameSize = 1;
  463. } else {
  464. if ((strcmp(ResultPointer->d_name, ".") == 0) ||
  465. (strcmp(ResultPointer->d_name, "..") == 0)) {
  466. continue;
  467. }
  468. NameSize = strlen(ResultPointer->d_name) + 1;
  469. }
  470. //
  471. // Reallocate the array if needed.
  472. //
  473. if (ArrayCapacity - UsedSize < NameSize) {
  474. NewCapacity = ArrayCapacity;
  475. if (NewCapacity == 0) {
  476. NewCapacity = 2;
  477. }
  478. while (NewCapacity - UsedSize < NameSize) {
  479. NewCapacity *= 2;
  480. }
  481. NewBuffer = realloc(Array, NewCapacity);
  482. if (NewBuffer == NULL) {
  483. Result = ENOMEM;
  484. goto OsEnumerateDirectoryEnd;
  485. }
  486. Array = NewBuffer;
  487. ArrayCapacity = NewCapacity;
  488. }
  489. //
  490. // Copy the entry (or an empty file if this is the end).
  491. //
  492. if (ResultPointer == NULL) {
  493. strcpy(Array + UsedSize, "");
  494. UsedSize += 1;
  495. break;
  496. } else {
  497. strcpy(Array + UsedSize, ResultPointer->d_name);
  498. UsedSize += NameSize;
  499. }
  500. }
  501. Result = 0;
  502. OsEnumerateDirectoryEnd:
  503. if (Directory != NULL) {
  504. closedir(Directory);
  505. }
  506. if (Result != 0) {
  507. if (Array != NULL) {
  508. free(Array);
  509. Array = NULL;
  510. }
  511. }
  512. *Enumeration = Array;
  513. return Result;
  514. }
  515. INT
  516. SetupOsCreateDirectory (
  517. PSTR Path,
  518. mode_t Permissions
  519. )
  520. /*++
  521. Routine Description:
  522. This routine creates a new directory.
  523. Arguments:
  524. Path - Supplies the path string of the directory to create.
  525. Permissions - Supplies the permission bits to create the file with.
  526. Return Value:
  527. 0 on success.
  528. Non-zero on failure.
  529. --*/
  530. {
  531. INT Result;
  532. Result = mkdir(Path);
  533. if (Result != 0) {
  534. Result = errno;
  535. if (Result == 0) {
  536. Result = -1;
  537. }
  538. }
  539. return Result;
  540. }
  541. INT
  542. SetupOsSetAttributes (
  543. PSTR Path,
  544. time_t ModificationDate,
  545. mode_t Permissions
  546. )
  547. /*++
  548. Routine Description:
  549. This routine sets attributes on a given path.
  550. Arguments:
  551. Path - Supplies the path string of the file to modify.
  552. ModificationDate - Supplies the new modification date to set.
  553. Permissions - Supplies the new permissions to set.
  554. Return Value:
  555. 0 on success.
  556. Non-zero on failure.
  557. --*/
  558. {
  559. INT Result;
  560. struct utimbuf Times;
  561. Times.actime = time(NULL);
  562. Times.modtime = ModificationDate;
  563. Result = utime(Path, &Times);
  564. if (Result != 0) {
  565. Result = errno;
  566. return Result;
  567. }
  568. Result = chmod(Path, Permissions);
  569. if (Result != 0) {
  570. Result = errno;
  571. return Result;
  572. }
  573. return 0;
  574. }
  575. VOID
  576. SetupOsDetermineExecuteBit (
  577. PVOID Handle,
  578. PCSTR Path,
  579. mode_t *Mode
  580. )
  581. /*++
  582. Routine Description:
  583. This routine determines whether the open file is executable.
  584. Arguments:
  585. Handle - Supplies the open file handle.
  586. Path - Supplies the path the file was opened from (sometimes the file name
  587. is used as a hint).
  588. Mode - Supplies a pointer to the current mode bits. This routine may add
  589. the executable bit to user/group/other if it determines this file is
  590. executable.
  591. Return Value:
  592. None.
  593. --*/
  594. {
  595. ssize_t BytesRead;
  596. BOOL Executable;
  597. PSETUP_OS_HANDLE IoHandle;
  598. PSTR LastDot;
  599. off_t Offset;
  600. ULONG Word;
  601. Executable = FALSE;
  602. IoHandle = Handle;
  603. //
  604. // First try to guess based on the name.
  605. //
  606. LastDot = strrchr(Path, '.');
  607. if (LastDot != NULL) {
  608. LastDot += 1;
  609. if ((strcmp(LastDot, "sh") == 0) ||
  610. (strcmp(LastDot, "exe") == 0)) {
  611. Executable = TRUE;
  612. }
  613. }
  614. if (Executable == FALSE) {
  615. //
  616. // Go to the beginning of the file and read the first word.
  617. //
  618. Offset = lseek(IoHandle->Handle, 0, SEEK_CUR);
  619. lseek(IoHandle->Handle, 0, SEEK_SET);
  620. Word = 0;
  621. do {
  622. BytesRead = read(IoHandle->Handle, &Word, sizeof(Word));
  623. } while ((BytesRead < 0) && (errno == EINTR));
  624. if (BytesRead > 0) {
  625. if (Word == ELF_MAGIC) {
  626. Executable = TRUE;
  627. } else {
  628. //
  629. // Now just look at the first two bytes.
  630. //
  631. Word &= 0x0000FFFF;
  632. if ((Word == IMAGE_DOS_SIGNATURE) ||
  633. (Word == SCRIPT_SHEBANG)) {
  634. Executable = TRUE;
  635. }
  636. }
  637. }
  638. //
  639. // Restore the previous offset.
  640. //
  641. lseek(IoHandle->Handle, Offset, SEEK_SET);
  642. }
  643. if (Executable != FALSE) {
  644. *Mode |= FILE_PERMISSION_ALL_EXECUTE;
  645. }
  646. return;
  647. }
  648. //
  649. // --------------------------------------------------------- Internal Functions
  650. //