File: FileSystem.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (120 lines) | stat: -rw-r--r-- 3,769 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import Foundation
import SystemPackage

struct FileAccessMode: OptionSet {
    let rawValue: UInt32
    static let read = FileAccessMode(rawValue: 1)
    static let write = FileAccessMode(rawValue: 1 << 1)
}

protocol WASIEntry {
    func attributes() throws -> WASIAbi.Filestat
    func fileType() throws -> WASIAbi.FileType
    func status() throws -> WASIAbi.Fdflags
    func setTimes(
        atim: WASIAbi.Timestamp, mtim: WASIAbi.Timestamp,
        fstFlags: WASIAbi.FstFlags
    ) throws
    func advise(
        offset: WASIAbi.FileSize, length: WASIAbi.FileSize, advice: WASIAbi.Advice
    ) throws
    func close() throws
}

protocol WASIFile: WASIEntry {
    func fdStat() throws -> WASIAbi.FdStat
    func setFdStatFlags(_ flags: WASIAbi.Fdflags) throws
    func setFilestatSize(_ size: WASIAbi.FileSize) throws

    func tell() throws -> WASIAbi.FileSize
    func seek(offset: WASIAbi.FileDelta, whence: WASIAbi.Whence) throws -> WASIAbi.FileSize

    func write<Buffer: Sequence>(
        vectored buffer: Buffer
    ) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec
    func pwrite<Buffer: Sequence>(
        vectored buffer: Buffer, offset: WASIAbi.FileSize
    ) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec
    func read<Buffer: Sequence>(
        into buffer: Buffer
    ) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec
    func pread<Buffer: Sequence>(
        into buffer: Buffer, offset: WASIAbi.FileSize
    ) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec
}

protocol WASIDir: WASIEntry {
    typealias ReaddirElement = (dirent: WASIAbi.Dirent, name: String)

    var preopenPath: String? { get }

    func openFile(
        symlinkFollow: Bool,
        path: String,
        oflags: WASIAbi.Oflags,
        accessMode: FileAccessMode,
        fdflags: WASIAbi.Fdflags
    ) throws -> FileDescriptor

    func createDirectory(atPath path: String) throws
    func removeDirectory(atPath path: String) throws
    func removeFile(atPath path: String) throws
    func symlink(from sourcePath: String, to destPath: String) throws
    func readEntries(cookie: WASIAbi.DirCookie) throws -> AnyIterator<Result<ReaddirElement, any Error>>
    func attributes(path: String, symlinkFollow: Bool) throws -> WASIAbi.Filestat
    func setFilestatTimes(
        path: String,
        atim: WASIAbi.Timestamp, mtim: WASIAbi.Timestamp,
        fstFlags: WASIAbi.FstFlags, symlinkFollow: Bool
    ) throws
}

enum FdEntry {
    case file(any WASIFile)
    case directory(any WASIDir)

    func asEntry() -> any WASIEntry {
        switch self {
        case .file(let entry):
            return entry
        case .directory(let directory):
            return directory
        }
    }
}

/// A table that maps file descriptor to actual resource in host environment
struct FdTable {
    private var map: [WASIAbi.Fd: FdEntry]
    private var nextFd: WASIAbi.Fd

    init() {
        self.map = [:]
        // 0, 1 and 2 are reserved for stdio
        self.nextFd = 3
    }

    /// Inserts a resource as the given file descriptor
    subscript(_ fd: WASIAbi.Fd) -> FdEntry? {
        get { self.map[fd] }
        set { self.map[fd] = newValue }
    }

    /// Inserts an entry and returns the corresponding file descriptor
    mutating func push(_ entry: FdEntry) throws -> WASIAbi.Fd {
        guard map.count < WASIAbi.Fd.max else {
            throw WASIAbi.Errno.ENFILE
        }
        // Find a free fd
        while true {
            let fd = self.nextFd
            // Wrapping to find fd again from 0 after overflow
            self.nextFd &+= 1
            if self.map[fd] != nil {
                continue
            }
            self.map[fd] = entry
            return fd
        }
    }
}