WindowsSyscallAdapters.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. This source file is part of the Swift System open source project
  3. Copyright (c) 2020 Apple Inc. and the Swift System project authors
  4. Licensed under Apache License v2.0 with Runtime Library Exception
  5. See https://swift.org/LICENSE.txt for license information
  6. */
  7. #if os(Windows)
  8. import ucrt
  9. import WinSDK
  10. import Synchronization
  11. private let _umask = Atomic<CInterop.Mode>(0o22)
  12. @inline(__always)
  13. func umask(
  14. _ mode: CInterop.Mode
  15. ) -> CInterop.Mode {
  16. _umask.exchange(mode, ordering: .relaxed)
  17. }
  18. @inline(__always)
  19. internal func open(
  20. _ path: UnsafePointer<CInterop.PlatformChar>, _ oflag: Int32
  21. ) -> CInt {
  22. let decodedFlags = DecodedOpenFlags(oflag)
  23. var saAttrs = SECURITY_ATTRIBUTES(
  24. nLength: DWORD(MemoryLayout<SECURITY_ATTRIBUTES>.size),
  25. lpSecurityDescriptor: nil,
  26. bInheritHandle: decodedFlags.bInheritHandle
  27. )
  28. guard let hFile = try? path.withCanonicalPathRepresentation({ path in
  29. CreateFileW(path,
  30. decodedFlags.dwDesiredAccess,
  31. FILE_SHARE_DELETE
  32. | FILE_SHARE_READ
  33. | FILE_SHARE_WRITE,
  34. &saAttrs,
  35. decodedFlags.dwCreationDisposition,
  36. decodedFlags.dwFlagsAndAttributes,
  37. nil)
  38. }), hFile != INVALID_HANDLE_VALUE else {
  39. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  40. return -1
  41. }
  42. return _open_osfhandle(intptr_t(bitPattern: hFile), oflag);
  43. }
  44. @inline(__always)
  45. internal func open(
  46. _ path: UnsafePointer<CInterop.PlatformChar>, _ oflag: Int32,
  47. _ mode: CInterop.Mode
  48. ) -> CInt {
  49. let actualMode = mode & ~_umask.load(ordering: .relaxed)
  50. guard let pSD = _createSecurityDescriptor(from: actualMode, for: .file) else {
  51. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  52. return -1
  53. }
  54. defer {
  55. pSD.deallocate()
  56. }
  57. let decodedFlags = DecodedOpenFlags(oflag)
  58. var saAttrs = SECURITY_ATTRIBUTES(
  59. nLength: DWORD(MemoryLayout<SECURITY_ATTRIBUTES>.size),
  60. lpSecurityDescriptor: pSD,
  61. bInheritHandle: decodedFlags.bInheritHandle
  62. )
  63. guard let hFile = try? path.withCanonicalPathRepresentation({ path in
  64. CreateFileW(path,
  65. decodedFlags.dwDesiredAccess,
  66. FILE_SHARE_DELETE
  67. | FILE_SHARE_READ
  68. | FILE_SHARE_WRITE,
  69. &saAttrs,
  70. decodedFlags.dwCreationDisposition,
  71. decodedFlags.dwFlagsAndAttributes,
  72. nil)
  73. }), hFile != INVALID_HANDLE_VALUE else {
  74. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  75. return -1
  76. }
  77. return _open_osfhandle(intptr_t(bitPattern: hFile), oflag);
  78. }
  79. @inline(__always)
  80. internal func close(_ fd: Int32) -> Int32 {
  81. _close(fd)
  82. }
  83. @inline(__always)
  84. internal func lseek(
  85. _ fd: Int32, _ off: Int64, _ whence: Int32
  86. ) -> Int64 {
  87. _lseeki64(fd, off, whence)
  88. }
  89. @inline(__always)
  90. internal func read(
  91. _ fd: Int32, _ buf: UnsafeMutableRawPointer!, _ nbyte: Int
  92. ) -> Int {
  93. Int(_read(fd, buf, numericCast(nbyte)))
  94. }
  95. @inline(__always)
  96. internal func write(
  97. _ fd: Int32, _ buf: UnsafeRawPointer!, _ nbyte: Int
  98. ) -> Int {
  99. Int(_write(fd, buf, numericCast(nbyte)))
  100. }
  101. @inline(__always)
  102. internal func lseek(
  103. _ fd: Int32, _ off: off_t, _ whence: Int32
  104. ) -> off_t {
  105. _lseek(fd, off, whence)
  106. }
  107. @inline(__always)
  108. internal func dup(_ fd: Int32) -> Int32 {
  109. _dup(fd)
  110. }
  111. @inline(__always)
  112. internal func dup2(_ fd: Int32, _ fd2: Int32) -> Int32 {
  113. // _dup2 returns 0 to indicate success.
  114. if _dup2(fd, fd2) == 0 {
  115. return fd2
  116. }
  117. return -1
  118. }
  119. @inline(__always)
  120. internal func pread(
  121. _ fd: Int32, _ buf: UnsafeMutableRawPointer!, _ nbyte: Int, _ offset: off_t
  122. ) -> Int {
  123. let handle: intptr_t = _get_osfhandle(fd)
  124. if handle == /* INVALID_HANDLE_VALUE */ -1 { ucrt._set_errno(EBADF); return -1 }
  125. // Windows ReadFile accepts DWORD (32-bit) for buffer size, so validate nbyte doesn't exceed it
  126. if nbyte > Int(DWORD.max) {
  127. ucrt._set_errno(EINVAL)
  128. return -1
  129. }
  130. // NOTE: this is a non-owning handle, do *not* call CloseHandle on it
  131. let hFile: HANDLE = HANDLE(bitPattern: handle)!
  132. var ovlOverlapped: OVERLAPPED = OVERLAPPED()
  133. ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
  134. ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
  135. var nNumberOfBytesRead: DWORD = 0
  136. if !ReadFile(hFile, buf, DWORD(nbyte), &nNumberOfBytesRead, &ovlOverlapped) {
  137. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  138. return Int(-1)
  139. }
  140. return Int(nNumberOfBytesRead)
  141. }
  142. @inline(__always)
  143. internal func pwrite(
  144. _ fd: Int32, _ buf: UnsafeRawPointer!, _ nbyte: Int, _ offset: off_t
  145. ) -> Int {
  146. let handle: intptr_t = _get_osfhandle(fd)
  147. if handle == /* INVALID_HANDLE_VALUE */ -1 { ucrt._set_errno(EBADF); return -1 }
  148. // Windows WriteFile accepts DWORD (32-bit) for buffer size, so validate nbyte doesn't exceed it
  149. if nbyte > Int(DWORD.max) {
  150. ucrt._set_errno(EINVAL)
  151. return -1
  152. }
  153. // NOTE: this is a non-owning handle, do *not* call CloseHandle on it
  154. let hFile: HANDLE = HANDLE(bitPattern: handle)!
  155. var ovlOverlapped: OVERLAPPED = OVERLAPPED()
  156. ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
  157. ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
  158. var nNumberOfBytesWritten: DWORD = 0
  159. if !WriteFile(hFile, buf, DWORD(nbyte), &nNumberOfBytesWritten,
  160. &ovlOverlapped) {
  161. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  162. return Int(-1)
  163. }
  164. return Int(nNumberOfBytesWritten)
  165. }
  166. @inline(__always)
  167. internal func pipe(
  168. _ fds: UnsafeMutablePointer<Int32>, bytesReserved: UInt32 = 0
  169. ) -> CInt {
  170. return _pipe(fds, bytesReserved, _O_BINARY | _O_NOINHERIT);
  171. }
  172. @inline(__always)
  173. internal func csystem_posix_pipe2(
  174. _ fds: UnsafeMutablePointer<Int32>, bytesReserved: UInt32 = 0, _ oflag: Int32
  175. ) -> CInt {
  176. return _pipe(fds, bytesReserved, _O_BINARY | oflag)
  177. }
  178. @inline(__always)
  179. internal func ftruncate(_ fd: Int32, _ length: off_t) -> Int32 {
  180. let handle: intptr_t = _get_osfhandle(fd)
  181. if handle == /* INVALID_HANDLE_VALUE */ -1 { ucrt._set_errno(EBADF); return -1 }
  182. // NOTE: this is a non-owning handle, do *not* call CloseHandle on it
  183. let hFile: HANDLE = HANDLE(bitPattern: handle)!
  184. let liDesiredLength = LARGE_INTEGER(QuadPart: LONGLONG(length))
  185. var liCurrentOffset = LARGE_INTEGER(QuadPart: 0)
  186. // Save the current position and restore it when we're done
  187. if !SetFilePointerEx(hFile, liCurrentOffset, &liCurrentOffset,
  188. FILE_CURRENT) {
  189. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  190. return -1
  191. }
  192. defer {
  193. _ = SetFilePointerEx(hFile, liCurrentOffset, nil, FILE_BEGIN);
  194. }
  195. // Truncate (or extend) the file
  196. if !SetFilePointerEx(hFile, liDesiredLength, nil, FILE_BEGIN)
  197. || !SetEndOfFile(hFile) {
  198. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  199. return -1
  200. }
  201. return 0;
  202. }
  203. @inline(__always)
  204. internal func mkdir(
  205. _ path: UnsafePointer<CInterop.PlatformChar>,
  206. _ mode: CInterop.Mode
  207. ) -> CInt {
  208. let actualMode = mode & ~_umask.load(ordering: .relaxed)
  209. guard let pSD = _createSecurityDescriptor(from: actualMode,
  210. for: .directory) else {
  211. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  212. return -1
  213. }
  214. defer {
  215. pSD.deallocate()
  216. }
  217. var saAttrs = SECURITY_ATTRIBUTES(
  218. nLength: DWORD(MemoryLayout<SECURITY_ATTRIBUTES>.size),
  219. lpSecurityDescriptor: pSD,
  220. bInheritHandle: false
  221. )
  222. guard (try? path.withCanonicalPathRepresentation({ path in CreateDirectoryW(path, &saAttrs) })) == true else {
  223. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  224. return -1
  225. }
  226. return 0;
  227. }
  228. @inline(__always)
  229. internal func rmdir(
  230. _ path: UnsafePointer<CInterop.PlatformChar>
  231. ) -> CInt {
  232. guard (try? path.withCanonicalPathRepresentation({ path in RemoveDirectoryW(path) })) == true else {
  233. ucrt._set_errno(_mapWindowsErrorToErrno(GetLastError()))
  234. return -1
  235. }
  236. return 0;
  237. }
  238. internal func _mapWindowsErrorToErrno(_ errorCode: DWORD) -> CInt {
  239. switch errorCode {
  240. case ERROR_SUCCESS:
  241. return 0
  242. case ERROR_INVALID_FUNCTION,
  243. ERROR_INVALID_ACCESS,
  244. ERROR_INVALID_DATA,
  245. ERROR_INVALID_PARAMETER,
  246. ERROR_NEGATIVE_SEEK:
  247. return EINVAL
  248. case ERROR_FILE_NOT_FOUND,
  249. ERROR_PATH_NOT_FOUND,
  250. ERROR_INVALID_DRIVE,
  251. ERROR_NO_MORE_FILES,
  252. ERROR_BAD_NETPATH,
  253. ERROR_BAD_NET_NAME,
  254. ERROR_BAD_PATHNAME,
  255. ERROR_FILENAME_EXCED_RANGE:
  256. return ENOENT
  257. case ERROR_TOO_MANY_OPEN_FILES:
  258. return EMFILE
  259. case ERROR_ACCESS_DENIED,
  260. ERROR_CURRENT_DIRECTORY,
  261. ERROR_LOCK_VIOLATION,
  262. ERROR_NETWORK_ACCESS_DENIED,
  263. ERROR_CANNOT_MAKE,
  264. ERROR_FAIL_I24,
  265. ERROR_DRIVE_LOCKED,
  266. ERROR_SEEK_ON_DEVICE,
  267. ERROR_NOT_LOCKED,
  268. ERROR_LOCK_FAILED,
  269. ERROR_WRITE_PROTECT...ERROR_SHARING_BUFFER_EXCEEDED:
  270. return EACCES
  271. case ERROR_INVALID_HANDLE,
  272. ERROR_INVALID_TARGET_HANDLE,
  273. ERROR_DIRECT_ACCESS_HANDLE:
  274. return EBADF
  275. case ERROR_ARENA_TRASHED,
  276. ERROR_NOT_ENOUGH_MEMORY,
  277. ERROR_INVALID_BLOCK,
  278. ERROR_NOT_ENOUGH_QUOTA:
  279. return ENOMEM
  280. case ERROR_BAD_ENVIRONMENT:
  281. return E2BIG
  282. case ERROR_BAD_FORMAT,
  283. ERROR_INVALID_STARTING_CODESEG...ERROR_INFLOOP_IN_RELOC_CHAIN:
  284. return ENOEXEC
  285. case ERROR_NOT_SAME_DEVICE:
  286. return EXDEV
  287. case ERROR_FILE_EXISTS,
  288. ERROR_ALREADY_EXISTS:
  289. return EEXIST
  290. case ERROR_NO_PROC_SLOTS,
  291. ERROR_MAX_THRDS_REACHED,
  292. ERROR_NESTING_NOT_ALLOWED:
  293. return EAGAIN
  294. case ERROR_BROKEN_PIPE:
  295. return EPIPE
  296. case ERROR_DISK_FULL:
  297. return ENOSPC
  298. case ERROR_WAIT_NO_CHILDREN,
  299. ERROR_CHILD_NOT_COMPLETE:
  300. return ECHILD
  301. case ERROR_DIR_NOT_EMPTY:
  302. return ENOTEMPTY
  303. case ERROR_NO_UNICODE_TRANSLATION:
  304. return EILSEQ
  305. default:
  306. return EINVAL
  307. }
  308. }
  309. fileprivate func rightsFromModeBits(
  310. _ bits: Int,
  311. sticky: Bool = false,
  312. for fileOrDirectory: _FileOrDirectory
  313. ) -> DWORD {
  314. var rights: DWORD = 0
  315. if (bits & 0o4) != 0 {
  316. rights |= (FILE_READ_ATTRIBUTES
  317. | FILE_READ_DATA
  318. | FILE_READ_EA
  319. | STANDARD_RIGHTS_READ
  320. | SYNCHRONIZE)
  321. }
  322. if (bits & 0o2) != 0 {
  323. rights |= (FILE_APPEND_DATA
  324. | FILE_WRITE_ATTRIBUTES
  325. | FILE_WRITE_DATA
  326. | FILE_WRITE_EA
  327. | STANDARD_RIGHTS_WRITE
  328. | SYNCHRONIZE)
  329. if fileOrDirectory == .directory && !sticky {
  330. rights |= FILE_DELETE_CHILD
  331. }
  332. }
  333. if (bits & 0o1) != 0 {
  334. rights |= (FILE_EXECUTE
  335. | FILE_READ_ATTRIBUTES
  336. | STANDARD_RIGHTS_EXECUTE
  337. | SYNCHRONIZE)
  338. }
  339. return rights
  340. }
  341. fileprivate func getTokenInformation<T>(
  342. of: T.Type,
  343. hToken: HANDLE,
  344. ticTokenClass: TOKEN_INFORMATION_CLASS
  345. ) -> UnsafePointer<T>? {
  346. var capacity = 1024
  347. for _ in 0..<2 {
  348. let buffer = UnsafeMutableRawPointer.allocate(
  349. byteCount: capacity,
  350. alignment: MemoryLayout<T>.alignment
  351. )
  352. var dwLength = DWORD(0)
  353. if GetTokenInformation(hToken,
  354. ticTokenClass,
  355. buffer,
  356. DWORD(capacity),
  357. &dwLength) {
  358. return UnsafePointer(buffer.assumingMemoryBound(to: T.self))
  359. }
  360. buffer.deallocate()
  361. capacity = Int(dwLength)
  362. }
  363. return nil
  364. }
  365. internal enum _FileOrDirectory {
  366. case file
  367. case directory
  368. }
  369. /// Build a SECURITY_DESCRIPTOR from UNIX-style "mode" bits. This only
  370. /// takes account of the rwx and sticky bits; there's really nothing that
  371. /// we can do about setuid/setgid.
  372. internal func _createSecurityDescriptor(from mode: CInterop.Mode,
  373. for fileOrDirectory: _FileOrDirectory)
  374. -> PSECURITY_DESCRIPTOR? {
  375. let ownerPerm = (Int(mode) >> 6) & 0o7
  376. let groupPerm = (Int(mode) >> 3) & 0o7
  377. let otherPerm = Int(mode) & 0o7
  378. let ownerRights = rightsFromModeBits(ownerPerm, for: fileOrDirectory)
  379. let groupRights = rightsFromModeBits(groupPerm,
  380. sticky: (mode & 0o1000) != 0,
  381. for: fileOrDirectory)
  382. let otherRights = rightsFromModeBits(otherPerm,
  383. sticky: (mode & 0o1000) != 0,
  384. for: fileOrDirectory)
  385. // If group or other permissions are *more* permissive, then we need
  386. // some DENY ACEs as well to implement the expected semantics
  387. let ownerDenyRights = ((ownerRights ^ groupRights) & groupRights) |
  388. ((ownerRights ^ otherRights) & otherRights)
  389. let groupDenyRights = (groupRights ^ otherRights) & otherRights
  390. var SIDAuthWorld = SID_IDENTIFIER_AUTHORITY(Value: (0, 0, 0, 0, 0, 1))
  391. var everyone: PSID? = nil
  392. guard AllocateAndInitializeSid(&SIDAuthWorld, 1,
  393. SECURITY_WORLD_RID,
  394. 0, 0, 0, 0, 0, 0, 0,
  395. &everyone) else {
  396. return nil
  397. }
  398. guard let everyone = everyone else {
  399. return nil
  400. }
  401. defer {
  402. FreeSid(everyone)
  403. }
  404. let hToken = GetCurrentThreadEffectiveToken()!
  405. guard let pTokenUser = getTokenInformation(of: TOKEN_USER.self,
  406. hToken: hToken,
  407. ticTokenClass: TokenUser) else {
  408. return nil
  409. }
  410. defer {
  411. pTokenUser.deallocate()
  412. }
  413. guard let pTokenPrimaryGroup = getTokenInformation(
  414. of: TOKEN_PRIMARY_GROUP.self,
  415. hToken: hToken,
  416. ticTokenClass: TokenPrimaryGroup
  417. ) else {
  418. return nil
  419. }
  420. defer {
  421. pTokenPrimaryGroup.deallocate()
  422. }
  423. let user = pTokenUser.pointee.User.Sid!
  424. let group = pTokenPrimaryGroup.pointee.PrimaryGroup!
  425. var eas = [
  426. EXPLICIT_ACCESS_W(
  427. grfAccessPermissions: ownerRights,
  428. grfAccessMode: GRANT_ACCESS,
  429. grfInheritance: NO_INHERITANCE,
  430. Trustee: TRUSTEE_W(
  431. pMultipleTrustee: nil,
  432. MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
  433. TrusteeForm: TRUSTEE_IS_SID,
  434. TrusteeType: TRUSTEE_IS_USER,
  435. ptstrName:
  436. user.assumingMemoryBound(to: CInterop.PlatformChar.self)
  437. )
  438. ),
  439. EXPLICIT_ACCESS_W(
  440. grfAccessPermissions: groupRights,
  441. grfAccessMode: GRANT_ACCESS,
  442. grfInheritance: NO_INHERITANCE,
  443. Trustee: TRUSTEE_W(
  444. pMultipleTrustee: nil,
  445. MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
  446. TrusteeForm: TRUSTEE_IS_SID,
  447. TrusteeType: TRUSTEE_IS_GROUP,
  448. ptstrName:
  449. group.assumingMemoryBound(to: CInterop.PlatformChar.self)
  450. )
  451. ),
  452. EXPLICIT_ACCESS_W(
  453. grfAccessPermissions: otherRights,
  454. grfAccessMode: GRANT_ACCESS,
  455. grfInheritance: NO_INHERITANCE,
  456. Trustee: TRUSTEE_W(
  457. pMultipleTrustee: nil,
  458. MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
  459. TrusteeForm: TRUSTEE_IS_SID,
  460. TrusteeType: TRUSTEE_IS_GROUP,
  461. ptstrName:
  462. everyone.assumingMemoryBound(to: CInterop.PlatformChar.self)
  463. )
  464. )
  465. ]
  466. if ownerDenyRights != 0 {
  467. eas.append(
  468. EXPLICIT_ACCESS_W(
  469. grfAccessPermissions: ownerDenyRights,
  470. grfAccessMode: DENY_ACCESS,
  471. grfInheritance: NO_INHERITANCE,
  472. Trustee: TRUSTEE_W(
  473. pMultipleTrustee: nil,
  474. MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
  475. TrusteeForm: TRUSTEE_IS_SID,
  476. TrusteeType: TRUSTEE_IS_USER,
  477. ptstrName:
  478. user.assumingMemoryBound(to: CInterop.PlatformChar.self)
  479. )
  480. )
  481. )
  482. }
  483. if groupDenyRights != 0 {
  484. eas.append(
  485. EXPLICIT_ACCESS_W(
  486. grfAccessPermissions: groupDenyRights,
  487. grfAccessMode: DENY_ACCESS,
  488. grfInheritance: NO_INHERITANCE,
  489. Trustee: TRUSTEE_W(
  490. pMultipleTrustee: nil,
  491. MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
  492. TrusteeForm: TRUSTEE_IS_SID,
  493. TrusteeType: TRUSTEE_IS_GROUP,
  494. ptstrName:
  495. group.assumingMemoryBound(to: CInterop.PlatformChar.self)
  496. )
  497. )
  498. )
  499. }
  500. var pACL: PACL? = nil
  501. guard SetEntriesInAclW(ULONG(eas.count),
  502. &eas,
  503. nil,
  504. &pACL) == ERROR_SUCCESS else {
  505. return nil
  506. }
  507. defer {
  508. LocalFree(pACL)
  509. }
  510. // Create the security descriptor, making sure that inherited ACEs don't
  511. // take effect, since that wouldn't match the behaviour of mode bits.
  512. var descriptor = SECURITY_DESCRIPTOR()
  513. guard InitializeSecurityDescriptor(&descriptor,
  514. SECURITY_DESCRIPTOR_REVISION) else {
  515. return nil
  516. }
  517. guard SetSecurityDescriptorControl(&descriptor,
  518. SE_DACL_PROTECTED,
  519. SE_DACL_PROTECTED)
  520. && SetSecurityDescriptorOwner(&descriptor, user, false)
  521. && SetSecurityDescriptorGroup(&descriptor, group, false)
  522. && SetSecurityDescriptorDacl(&descriptor,
  523. true,
  524. pACL,
  525. false) else {
  526. return nil
  527. }
  528. // Make it self-contained (up to this point it uses pointers)
  529. var dwRelativeSize = DWORD(0)
  530. guard !MakeSelfRelativeSD(&descriptor, nil, &dwRelativeSize)
  531. && GetLastError() == ERROR_INSUFFICIENT_BUFFER else {
  532. return nil
  533. }
  534. let pDescriptor = UnsafeMutableRawPointer.allocate(
  535. byteCount: Int(dwRelativeSize),
  536. alignment: MemoryLayout<SECURITY_DESCRIPTOR>.alignment
  537. ).assumingMemoryBound(to: SECURITY_DESCRIPTOR.self)
  538. guard MakeSelfRelativeSD(&descriptor, pDescriptor, &dwRelativeSize) else {
  539. pDescriptor.deallocate()
  540. return nil
  541. }
  542. return UnsafeMutableRawPointer(pDescriptor)
  543. }
  544. fileprivate struct DecodedOpenFlags {
  545. var dwDesiredAccess: DWORD
  546. var dwCreationDisposition: DWORD
  547. var bInheritHandle: WindowsBool
  548. var dwFlagsAndAttributes: DWORD
  549. init(_ oflag: Int32) {
  550. switch oflag & (_O_CREAT | _O_EXCL | _O_TRUNC) {
  551. case _O_CREAT | _O_EXCL, _O_CREAT | _O_EXCL | _O_TRUNC:
  552. dwCreationDisposition = CREATE_NEW
  553. case _O_CREAT:
  554. dwCreationDisposition = OPEN_ALWAYS
  555. case _O_CREAT | _O_TRUNC:
  556. dwCreationDisposition = CREATE_ALWAYS
  557. case _O_TRUNC:
  558. dwCreationDisposition = TRUNCATE_EXISTING
  559. default:
  560. dwCreationDisposition = OPEN_EXISTING
  561. }
  562. // The _O_RDONLY, _O_WRONLY and _O_RDWR flags are non-overlapping
  563. // on Windows; in particular, _O_RDONLY is zero, which means we can't
  564. // test for it by AND-ing.
  565. dwDesiredAccess = 0
  566. switch (oflag & (_O_RDONLY|_O_WRONLY|_O_RDWR)) {
  567. case _O_RDONLY:
  568. dwDesiredAccess |= GENERIC_READ
  569. case _O_WRONLY:
  570. dwDesiredAccess |= GENERIC_WRITE
  571. case _O_RDWR:
  572. dwDesiredAccess |= GENERIC_READ | GENERIC_WRITE
  573. default:
  574. break
  575. }
  576. bInheritHandle = WindowsBool((oflag & _O_NOINHERIT) == 0)
  577. dwFlagsAndAttributes = 0
  578. if (oflag & _O_SEQUENTIAL) != 0 {
  579. dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN
  580. }
  581. if (oflag & _O_RANDOM) != 0 {
  582. dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS
  583. }
  584. if (oflag & _O_TEMPORARY) != 0 {
  585. dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE
  586. }
  587. if (oflag & _O_SHORT_LIVED) != 0 {
  588. dwFlagsAndAttributes |= FILE_ATTRIBUTE_TEMPORARY
  589. } else {
  590. dwFlagsAndAttributes |= FILE_ATTRIBUTE_NORMAL
  591. }
  592. }
  593. }
  594. #endif