1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
#if canImport(Glibc)
@_exported import Glibc
#elseif canImport(Musl)
@_exported import Musl
#elseif os(Windows)
@_exported import CRT
@_exported import WinSDK
#elseif canImport(Android)
@_exported import Android
#else
@_exported import Darwin.C
#endif
#if os(Windows)
private func __randname(_ buffer: UnsafeMutablePointer<CChar>) {
let alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
_ = (0 ..< 6).map { index in
buffer[index] = CChar(alpha.shuffled().randomElement()!.utf8.first!)
}
}
// char *mkdtemp(char *template);
// NOTE(compnerd) this is unsafe! This assumes that the template is *ASCII*.
public func mkdtemp(
_ template: UnsafeMutablePointer<CChar>?
) -> UnsafeMutablePointer<CChar>? {
// Although the signature of the function is `char *(*)(char *)`, the C
// library treats it as `char *(*)(char * _Nonull)`. Most implementations
// will simply use and trigger a segmentation fault on x86 (and similar faults
// on other architectures) when the memory is accessed. This roughly emulates
// that by terminating in the case even though it is possible for us to return
// an error.
guard let template = template else { fatalError() }
let length: Int = strlen(template)
// Validate the precondition: the template must terminate with 6 `X` which
// will be filled in to generate a unique directory.
guard length >= 6, memcmp(template + length - 6, "XXXXXX", 6) == 0 else {
_set_errno(EINVAL)
return nil
}
// Attempt to create the directory
var retries: Int = 100
repeat {
__randname(template + length - 6)
if _mkdir(template) == 0 {
return template
}
retries = retries - 1
} while retries > 0
return nil
}
// int mkstemps(char *template, int suffixlen);
public func mkstemps(
_ template: UnsafeMutablePointer<CChar>?,
_ suffixlen: Int32
) -> Int32 {
// Although the signature of the function is `char *(*)(char *)`, the C
// library treats it as `char *(*)(char * _Nonull)`. Most implementations
// will simply use and trigger a segmentation fault on x86 (and similar faults
// on other architectures) when the memory is accessed. This roughly emulates
// that by terminating in the case even though it is possible for us to return
// an error.
guard let template = template else { fatalError() }
let length: Int = strlen(template)
// Validate the precondition: the template must terminate with 6 `X` which
// will be filled in to generate a unique directory.
guard length >= 6, memcmp(template + length - Int(suffixlen) - 6, "XXXXXX", 6) == 0 else {
_set_errno(EINVAL)
return -1
}
// Attempt to create file
var retries: Int = 100
repeat {
__randname(template + length - Int(suffixlen) - 6)
var fd: CInt = -1
if _sopen_s(&fd, template, _O_RDWR | _O_CREAT | _O_BINARY | _O_NOINHERIT,
_SH_DENYNO, _S_IREAD | _S_IWRITE) == 0 {
return fd
}
retries = retries - 1
} while retries > 0
return -1
}
#endif
|