io.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /*++
  2. Copyright (c) 2016 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 generic POSIX systems in
  11. the setup application.
  12. Author:
  13. Evan Green 19-Jan-2016
  14. Environment:
  15. User
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #define _FILE_OFFSET_BITS 64
  21. #include <assert.h>
  22. #include <dirent.h>
  23. #include <errno.h>
  24. #include <fcntl.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/stat.h>
  30. #include <time.h>
  31. #include <unistd.h>
  32. #include <utime.h>
  33. #if defined(__APPLE__) || defined(__FreeBSD__)
  34. #include <sys/disk.h>
  35. #endif
  36. #if defined(__linux__)
  37. #include <sys/mount.h>
  38. #endif
  39. #include "../setup.h"
  40. //
  41. // ---------------------------------------------------------------- Definitions
  42. //
  43. //
  44. // ------------------------------------------------------ Data Type Definitions
  45. //
  46. //
  47. // ----------------------------------------------- Internal Function Prototypes
  48. //
  49. INT
  50. SetupOsGetBlockDeviceSize (
  51. INT Descriptor,
  52. PULONGLONG Size
  53. );
  54. //
  55. // -------------------------------------------------------------------- Globals
  56. //
  57. //
  58. // ------------------------------------------------------------------ Functions
  59. //
  60. INT
  61. SetupOsReadLink (
  62. PSTR Path,
  63. PSTR *LinkTarget,
  64. INT *LinkTargetSize
  65. )
  66. /*++
  67. Routine Description:
  68. This routine attempts to read a symbolic link.
  69. Arguments:
  70. Path - Supplies a pointer to the path to open.
  71. LinkTarget - Supplies a pointer where an allocated link target will be
  72. returned on success. The caller is responsible for freeing this memory.
  73. LinkTargetSize - Supplies a pointer where the size of the link target will
  74. be returned on success.
  75. Return Value:
  76. 0 on success.
  77. Returns an error number on failure.
  78. --*/
  79. {
  80. int Size;
  81. *LinkTarget = malloc(SETUP_SYMLINK_MAX);
  82. if (*LinkTarget == NULL) {
  83. return errno;
  84. }
  85. Size = readlink(Path, *LinkTarget, SETUP_SYMLINK_MAX - 1);
  86. if (Size < 0) {
  87. free(*LinkTarget);
  88. *LinkTarget = NULL;
  89. return errno;
  90. }
  91. (*LinkTarget)[Size] = '\0';
  92. *LinkTargetSize = Size;
  93. return 0;
  94. }
  95. INT
  96. SetupOsSymlink (
  97. PSTR Path,
  98. PSTR LinkTarget,
  99. INT LinkTargetSize
  100. )
  101. /*++
  102. Routine Description:
  103. This routine creates a symbolic link.
  104. Arguments:
  105. Path - Supplies a pointer to the path of the symbolic link to create.
  106. LinkTarget - Supplies a pointer to the target of the link.
  107. LinkTargetSize - Supplies a the size of the link target buffer in bytes.
  108. Return Value:
  109. Returns the link size on success.
  110. -1 on failure.
  111. --*/
  112. {
  113. INT Result;
  114. //
  115. // Create the symlink. If it already exists, attempt to unlink that file
  116. // and create a new one.
  117. //
  118. Result = symlink(LinkTarget, Path);
  119. if ((Result < 0) && (errno == EEXIST)) {
  120. if (unlink(LinkTarget) == 0) {
  121. Result = symlink(LinkTarget, Path);
  122. }
  123. }
  124. return Result;
  125. }
  126. PVOID
  127. SetupOsOpenDestination (
  128. PSETUP_DESTINATION Destination,
  129. INT Flags,
  130. INT CreatePermissions
  131. )
  132. /*++
  133. Routine Description:
  134. This routine opens a handle to a given destination.
  135. Arguments:
  136. Destination - Supplies a pointer to the destination to open.
  137. Flags - Supplies open flags. See O_* definitions.
  138. CreatePermissions - Supplies optional create permissions.
  139. Return Value:
  140. Returns a pointer to an opaque context on success.
  141. NULL on failure.
  142. --*/
  143. {
  144. int Descriptor;
  145. if (Destination->Path == NULL) {
  146. fprintf(stderr, "Error: Device ID paths not supported.\n");
  147. errno = ENOENT;
  148. return NULL;
  149. }
  150. Descriptor = open(Destination->Path, Flags, CreatePermissions);
  151. if (Descriptor == -1) {
  152. return NULL;
  153. }
  154. return (PVOID)(INTN)Descriptor;
  155. }
  156. VOID
  157. SetupOsClose (
  158. PVOID Handle
  159. )
  160. /*++
  161. Routine Description:
  162. This routine closes a handle.
  163. Arguments:
  164. Handle - Supplies a pointer to the destination to open.
  165. Return Value:
  166. None.
  167. --*/
  168. {
  169. close((INTN)Handle);
  170. return;
  171. }
  172. ssize_t
  173. SetupOsRead (
  174. PVOID Handle,
  175. void *Buffer,
  176. size_t ByteCount
  177. )
  178. /*++
  179. Routine Description:
  180. This routine reads from an open handle.
  181. Arguments:
  182. Handle - Supplies the handle.
  183. Buffer - Supplies a pointer where the read bytes will be returned.
  184. ByteCount - Supplies the number of bytes to read.
  185. Return Value:
  186. Returns the number of bytes read.
  187. -1 on failure.
  188. --*/
  189. {
  190. ssize_t BytesRead;
  191. do {
  192. BytesRead = read((INTN)Handle, Buffer, ByteCount);
  193. } while ((BytesRead < 0) && (errno == EINTR));
  194. return BytesRead;
  195. }
  196. ssize_t
  197. SetupOsWrite (
  198. PVOID Handle,
  199. void *Buffer,
  200. size_t ByteCount
  201. )
  202. /*++
  203. Routine Description:
  204. This routine writes data to an open handle.
  205. Arguments:
  206. Handle - Supplies the handle.
  207. Buffer - Supplies a pointer to the bytes to write.
  208. ByteCount - Supplies the number of bytes to read.
  209. Return Value:
  210. Returns the number of bytes written.
  211. -1 on failure.
  212. --*/
  213. {
  214. ssize_t BytesWritten;
  215. do {
  216. BytesWritten = write((INTN)Handle, Buffer, ByteCount);
  217. } while ((BytesWritten < 0) && (errno == EINTR));
  218. return BytesWritten;
  219. }
  220. LONGLONG
  221. SetupOsSeek (
  222. PVOID Handle,
  223. LONGLONG Offset
  224. )
  225. /*++
  226. Routine Description:
  227. This routine seeks in the current file or device.
  228. Arguments:
  229. Handle - Supplies the handle.
  230. Offset - Supplies the new offset to set.
  231. Return Value:
  232. Returns the resulting file offset after the operation.
  233. -1 on failure, and errno will contain more information. The file offset
  234. will remain unchanged.
  235. --*/
  236. {
  237. return lseek((INTN)Handle, Offset, SEEK_SET);
  238. }
  239. LONGLONG
  240. SetupOsTell (
  241. PVOID Handle
  242. )
  243. /*++
  244. Routine Description:
  245. This routine returns the current offset in the given file or device.
  246. Arguments:
  247. Handle - Supplies the handle.
  248. Return Value:
  249. Returns the file offset on success.
  250. -1 on failure, and errno will contain more information. The file offset
  251. will remain unchanged.
  252. --*/
  253. {
  254. return lseek((INTN)Handle, 0, SEEK_CUR);
  255. }
  256. INT
  257. SetupOsFstat (
  258. PVOID Handle,
  259. PULONGLONG FileSize,
  260. time_t *ModificationDate,
  261. mode_t *Mode
  262. )
  263. /*++
  264. Routine Description:
  265. This routine gets details for the given open file.
  266. Arguments:
  267. Handle - Supplies the handle.
  268. FileSize - Supplies an optional pointer where the file size will be
  269. returned on success.
  270. ModificationDate - Supplies an optional pointer where the file's
  271. modification date will be returned on success.
  272. Mode - Supplies an optional pointer where the file's mode information will
  273. be returned on success.
  274. Return Value:
  275. 0 on success.
  276. Non-zero on failure.
  277. --*/
  278. {
  279. int Result;
  280. struct stat Stat;
  281. Result = fstat((INTN)Handle, &Stat);
  282. if (Result != 0) {
  283. return Result;
  284. }
  285. if (FileSize != NULL) {
  286. if (S_ISBLK(Stat.st_mode)) {
  287. Result = SetupOsGetBlockDeviceSize((INTN)Handle, FileSize);
  288. if (Result != 0) {
  289. return Result;
  290. }
  291. } else {
  292. *FileSize = Stat.st_size;
  293. }
  294. }
  295. if (ModificationDate != NULL) {
  296. *ModificationDate = Stat.st_mtime;
  297. }
  298. if (Mode != NULL) {
  299. *Mode = Stat.st_mode;
  300. }
  301. return Result;
  302. }
  303. INT
  304. SetupOsFtruncate (
  305. PVOID Handle,
  306. ULONGLONG NewSize
  307. )
  308. /*++
  309. Routine Description:
  310. This routine sets the file size of the given file.
  311. Arguments:
  312. Handle - Supplies the handle.
  313. NewSize - Supplies the new file size.
  314. Return Value:
  315. 0 on success.
  316. Non-zero on failure.
  317. --*/
  318. {
  319. int Result;
  320. Result = ftruncate((INTN)Handle, NewSize);
  321. if (Result != 0) {
  322. return Result;
  323. }
  324. return Result;
  325. }
  326. INT
  327. SetupOsEnumerateDirectory (
  328. PVOID Handle,
  329. PSTR DirectoryPath,
  330. PSTR *Enumeration
  331. )
  332. /*++
  333. Routine Description:
  334. This routine enumerates the contents of a given directory.
  335. Arguments:
  336. Handle - Supplies the open volume handle.
  337. DirectoryPath - Supplies a pointer to a string containing the path to the
  338. directory to enumerate.
  339. Enumeration - Supplies a pointer where a pointer to a sequence of
  340. strings will be returned containing the files in the directory. The
  341. sequence will be terminated by an empty string. The caller is
  342. responsible for freeing this memory when done.
  343. Return Value:
  344. 0 on success.
  345. Non-zero on failure.
  346. --*/
  347. {
  348. PSTR Array;
  349. size_t ArrayCapacity;
  350. DIR *Directory;
  351. struct dirent *DirectoryEntry;
  352. size_t NameSize;
  353. PVOID NewBuffer;
  354. size_t NewCapacity;
  355. INT Result;
  356. size_t UsedSize;
  357. Array = NULL;
  358. ArrayCapacity = 0;
  359. Directory = NULL;
  360. UsedSize = 0;
  361. Directory = opendir(DirectoryPath);
  362. if (Directory == NULL) {
  363. Result = errno;
  364. goto OsEnumerateDirectoryEnd;
  365. }
  366. //
  367. // Loop reading directory entries.
  368. //
  369. while (TRUE) {
  370. errno = 0;
  371. DirectoryEntry = readdir(Directory);
  372. if (DirectoryEntry == NULL) {
  373. if (errno != 0) {
  374. Result = errno;
  375. goto OsEnumerateDirectoryEnd;
  376. }
  377. NameSize = 1;
  378. } else {
  379. if ((strcmp(DirectoryEntry->d_name, ".") == 0) ||
  380. (strcmp(DirectoryEntry->d_name, "..") == 0)) {
  381. continue;
  382. }
  383. NameSize = strlen(DirectoryEntry->d_name) + 1;
  384. }
  385. //
  386. // Reallocate the array if needed.
  387. //
  388. if (ArrayCapacity - UsedSize < NameSize) {
  389. NewCapacity = ArrayCapacity;
  390. if (NewCapacity == 0) {
  391. NewCapacity = 2;
  392. }
  393. while (NewCapacity - UsedSize < NameSize) {
  394. NewCapacity *= 2;
  395. }
  396. NewBuffer = realloc(Array, NewCapacity);
  397. if (NewBuffer == NULL) {
  398. Result = ENOMEM;
  399. goto OsEnumerateDirectoryEnd;
  400. }
  401. Array = NewBuffer;
  402. ArrayCapacity = NewCapacity;
  403. }
  404. //
  405. // Copy the entry (or an empty file if this is the end).
  406. //
  407. if (DirectoryEntry == NULL) {
  408. strcpy(Array + UsedSize, "");
  409. UsedSize += 1;
  410. break;
  411. } else {
  412. strcpy(Array + UsedSize, DirectoryEntry->d_name);
  413. UsedSize += NameSize;
  414. }
  415. }
  416. Result = 0;
  417. OsEnumerateDirectoryEnd:
  418. if (Directory != NULL) {
  419. closedir(Directory);
  420. }
  421. if (Result != 0) {
  422. if (Array != NULL) {
  423. free(Array);
  424. Array = NULL;
  425. }
  426. }
  427. *Enumeration = Array;
  428. return Result;
  429. }
  430. INT
  431. SetupOsCreateDirectory (
  432. PSTR Path,
  433. mode_t Permissions
  434. )
  435. /*++
  436. Routine Description:
  437. This routine creates a new directory.
  438. Arguments:
  439. Path - Supplies the path string of the directory to create.
  440. Permissions - Supplies the permission bits to create the file with.
  441. Return Value:
  442. 0 on success.
  443. Non-zero on failure.
  444. --*/
  445. {
  446. INT Result;
  447. Result = mkdir(Path, Permissions);
  448. if (Result != 0) {
  449. Result = errno;
  450. if (Result == 0) {
  451. Result = -1;
  452. }
  453. }
  454. return Result;
  455. }
  456. INT
  457. SetupOsSetAttributes (
  458. PSTR Path,
  459. time_t ModificationDate,
  460. mode_t Permissions
  461. )
  462. /*++
  463. Routine Description:
  464. This routine sets attributes on a given path.
  465. Arguments:
  466. Path - Supplies the path string of the file to modify.
  467. ModificationDate - Supplies the new modification date to set.
  468. Permissions - Supplies the new permissions to set.
  469. Return Value:
  470. 0 on success.
  471. Non-zero on failure.
  472. --*/
  473. {
  474. INT Result;
  475. struct utimbuf Times;
  476. Times.actime = time(NULL);
  477. Times.modtime = ModificationDate;
  478. Result = utime(Path, &Times);
  479. if (Result != 0) {
  480. Result = errno;
  481. return Result;
  482. }
  483. Result = chmod(Path, Permissions);
  484. if (Result != 0) {
  485. Result = errno;
  486. return Result;
  487. }
  488. return 0;
  489. }
  490. VOID
  491. SetupOsDetermineExecuteBit (
  492. PVOID Handle,
  493. PCSTR Path,
  494. mode_t *Mode
  495. )
  496. /*++
  497. Routine Description:
  498. This routine determines whether the open file is executable.
  499. Arguments:
  500. Handle - Supplies the open file handle.
  501. Path - Supplies the path the file was opened from (sometimes the file name
  502. is used as a hint).
  503. Mode - Supplies a pointer to the current mode bits. This routine may add
  504. the executable bit to user/group/other if it determines this file is
  505. executable.
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. //
  511. // Since POSIX systems have support for executable bits, don't screw with
  512. // the permissions that are already set.
  513. //
  514. return;
  515. }
  516. //
  517. // --------------------------------------------------------- Internal Functions
  518. //
  519. INT
  520. SetupOsGetBlockDeviceSize (
  521. INT Descriptor,
  522. PULONGLONG Size
  523. )
  524. /*++
  525. Routine Description:
  526. This routine gets the size of the open block device size.
  527. Arguments:
  528. Descriptor - Supplies the open file descriptor.
  529. Size - Supplies a pointer where the block device size will be returned on
  530. success.
  531. Return Value:
  532. 0 on success.
  533. Non-zero on failure.
  534. --*/
  535. {
  536. //
  537. // The IOCTL for Apple devices.
  538. //
  539. #ifdef DKIOCGETBLOCKCOUNT
  540. if (ioctl(Descriptor, DKIOCGETBLOCKCOUNT, Size) >= 0) {
  541. *Size *= 512;
  542. return 0;
  543. }
  544. #endif
  545. //
  546. // The IOCTLs for Linux devices.
  547. //
  548. #ifdef BLKGETSIZE64
  549. if (ioctl(Descriptor, BLKGETSIZE64, Size) >= 0) {
  550. return 0;
  551. }
  552. #endif
  553. #ifdef BLKGETSIZE
  554. if (ioctl(Descriptor, BLKGETSIZE, Size) >= 0) {
  555. *Size *= 512;
  556. return 0;
  557. }
  558. #endif
  559. //
  560. // The IOCTL for FreeBSD.
  561. //
  562. #ifdef DIOCGMEDIASIZE
  563. if (ioctl(Descriptor, DIOCGMEDIASIZE, Size) >= 0) {
  564. return 0;
  565. }
  566. #endif
  567. return ENOSYS;
  568. }