File: FilePathTemp.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (97 lines) | stat: -rw-r--r-- 2,846 bytes parent folder | download
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
/*
 This source file is part of the Swift System open source project

 Copyright (c) 2024 Apple Inc. and the Swift System project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See https://swift.org/LICENSE.txt for license information
*/

// MARK: - API

/// Create a temporary path for the duration of the closure.
///
/// - Parameters:
///   - basename: The base name for the temporary path.
///   - body: The closure to execute.
///
/// Creates a temporary directory with a name based on the given `basename`,
/// executes `body`, passing in the path of the created directory, then
/// deletes the directory and all of its contents before returning.
internal func withTemporaryFilePath<R>(
  basename: FilePath.Component,
  _ body: (FilePath) throws -> R
) throws -> R {
  let temporaryDir = try createUniqueTemporaryDirectory(basename: basename)
  defer {
    try? _recursiveRemove(at: temporaryDir)
  }

  return try body(temporaryDir)
}

// MARK: - Internals

fileprivate let base64 = Array<UInt8>(
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".utf8
)

/// Create a directory that is only accessible to the current user.
///
/// - Parameters:
///   - path: The path of the directory to create.
/// - Returns: `true` if a new directory was created.
///
/// This function will throw if there is an error, except if the error
/// is that the directory exists, in which case it returns `false`.
fileprivate func makeLockedDownDirectory(at path: FilePath) throws -> Bool {
  return try path.withPlatformString {
    if system_mkdir($0, 0o700) == 0 {
      return true
    }
    let err = system_errno
    if err == Errno.fileExists.rawValue {
      return false
    } else {
      throw Errno(rawValue: err)
    }
  }
}

/// Generate a random string of base64 filename safe characters.
///
/// - Parameters:
///   - length: The number of characters in the returned string.
/// - Returns: A random string of length `length`.
fileprivate func createRandomString(length: Int) -> String {
  return String(
    decoding: (0..<length).map{
      _ in base64[Int.random(in: 0..<64)]
    },
    as: UTF8.self
  )
}

/// Given a base name, create a uniquely named temporary directory.
///
/// - Parameters:
///   - basename: The base name for the new directory.
/// - Returns: The path to the new directory.
///
/// Creates a directory in the system temporary directory whose name
/// starts with `basename`, followed by a `.` and then a random
/// string of characters.
fileprivate func createUniqueTemporaryDirectory(
  basename: FilePath.Component
) throws -> FilePath {
  var tempDir = try _getTemporaryDirectory()
  tempDir.append(basename)

  while true {
    tempDir.extension = createRandomString(length: 16)

    if try makeLockedDownDirectory(at: tempDir) {
      return tempDir
    }
  }
}