1 = Components = 2 3 Access to files is provided by a number of programs acting as components. For 4 convenience, the component-level operations are wrapped up in a 5 [[ClientLibrary|client library]] that aims to provide simpler, more familiar 6 mechanisms for opening, reading, writing, and closing files, together with 7 various other operations. 8 9 <<TableOfContents(2,3)>> 10 11 Components are accessed via interfaces defined using the interface description 12 language supported by the ``idl4re`` tool. Interface operations in this 13 document are described using excerpts from the appropriate interface 14 descriptions. 15 16 ######## A graph showing the interactions between components 17 18 {{{#!graphviz 19 #format svg 20 #transform notugly 21 digraph components { 22 node [fontsize="12.0",fontname="sans-serif",shape=box]; 23 edge [fontsize="12.0",fontname="sans-serif"]; 24 rankdir=LR; 25 26 subgraph { 27 node [label="Client",style=solid,color="#000000",fontcolor="#000000"]; 28 rank=min; 29 30 Client1; Client2; Client3; Client4; Client5; Client6; Client7; 31 } 32 33 subgraph { 34 rank=same; 35 Memory [label="filename",shape=note]; 36 } 37 38 subgraph { 39 rank=same; 40 Filesystem; 41 42 subgraph { 43 node [label="Opener\n(user)"]; 44 Opener1; Opener2; 45 } 46 47 subgraph { 48 node [label="OpenerContext"]; 49 OpenerContext1; OpenerContext2; OpenerContext3; 50 } 51 52 MappedFile; 53 } 54 55 Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 -> Client7 [arrowhead=none,style=dotted]; 56 Opener1 -> Opener2 [arrowhead=none,style=dotted]; 57 OpenerContext1 -> OpenerContext2 -> OpenerContext3 [arrowhead=none,style=dotted]; 58 59 Client1 -> Filesystem [label="open_for_user(user)"]; 60 Filesystem -> Opener1; 61 Opener1 -> Client2; 62 63 Client3 -> Opener2 [label="context()"]; 64 Opener2 -> OpenerContext1; 65 OpenerContext1 -> Client4; 66 67 Client5 -> Memory -> OpenerContext2; 68 69 Client6 -> OpenerContext3 [label="open(flags, ...)"]; 70 OpenerContext3 -> MappedFile; 71 MappedFile -> Client7; 72 } 73 }}} 74 75 ######## 76 77 == Filesystems == 78 79 Filesystems implement the `Filesystem` interface which provides the 80 `open_for_user` operation: 81 82 {{{ 83 open_for_user(in user_t user, out cap opener) 84 }}} 85 86 The operation yields a file opener appropriate for the given [[Users|user]] 87 credentials. 88 89 == File Openers == 90 91 File openers implement the `Opener` interface which provides the `context` 92 operation: 93 94 {{{ 95 context(out cap context) 96 }}} 97 98 Each client program, task or thread obtains its own context because it will 99 need its own dedicated channel for communication with the filesystem. 100 101 == Opener Contexts == 102 103 An opener context acts as a dataspace, meaning that it can be attached to a 104 task using a region manager and provide a buffer via a region of mapped memory 105 that the task can write to. In the case of a context, the task will write a 106 filesystem path indicating the file to be opened. 107 108 Each context allows a client program to request access to individual files via 109 operations provided by the `OpenerContext` interface, of which the most 110 pertinent is the `open` operation: 111 112 {{{ 113 open(in flags_t flags, out offset_t size, out cap file, 114 out object_flags_t object_flags) 115 }}} 116 117 Using the path information written to the context's memory region, the `open` 118 operation will obtain a reference to a file-like object whose characteristics 119 are described by the accompanying `object_flags`, these helping the client to 120 distinguish between files that support arbitrary memory mapping operations and 121 pipes that mandate sequential region-by-region access. 122 123 Alongside regular files, directories may also be opened. Reading from them 124 yields a listing of directory entries. 125 126 == Files == 127 128 Files themselves act as dataspaces, meaning that they can be attached to a 129 task using a region manager and provide their content via a region of mapped 130 memory. Files implement the `MappedFile` interface. 131 132 Control over the region of the file provided via mapped memory occurs 133 using the `mmap` operation: 134 135 {{{ 136 mmap(in offset_t position, in offset_t length, 137 out offset_t start_pos, out offset_t end_pos, 138 out offset_t size) 139 }}} 140 141 Files also implement the more general `File` interface that provides the 142 `resize` operation: 143 144 {{{ 145 resize(inout offset_t size) 146 }}} 147 148 This allows the portion of the memory region dedicated to the file's contents 149 to be extended. 150 151 == Directories == 152 153 Directories are also meant to be accessed like files, meaning that it should 154 be possible to attach them to a task using a region manager and access the 155 provided content, this being a listing of directory entries, via the mapped 156 region. 157 158 However, unlike files which may support arbitrary mapping of their contents, 159 the provided content may be supplied by a pipe endpoint, thereby not 160 supporting precisely the same navigation mechanisms as those supported by 161 files. 162 163 '''Note''' that directories may well be redefined to support multiple 164 operations, one of which supporting the file-like access described above. 165 166 == Pipe Openers == 167 168 Distinct from filesystems but potentially used by them, pipe openers provide a 169 means of obtaining pipes, which are channels that support unidirectional 170 communication via shared memory. 171 172 Pipe openers implement the `PipeOpener` interface and support the following 173 operation: 174 175 {{{ 176 pipe(in offset_t size, out cap reader, out cap writer) 177 }}} 178 179 The size is indicated to request pipe regions long enough for the needs of the 180 communicating parties, with both reader and writer endpoint capabilities being 181 returned. Such capabilities may be propagated to the eventual parties, these 182 typically being separate tasks. 183 184 == Pipes == 185 186 Although not generally obtained from filesystems, pipes may be involved in 187 providing content from some filesystem objects such as directories. However, 188 they are also obtained directly from an appropriate pipe server providing pipe 189 opening facilities. 190 191 Pipes expose single regions of shared memory to their endpoints, with the 192 writing endpoint populating one region while the reading endpoint accesses the 193 other. The reading endpoint may advance to the region being written, and this 194 will free up a new region for the writer when it has filled its region. When 195 the writer itself advances, it permits the reader to consume all data in the 196 fully populated region. Naturally, the reader may not advance ahead of the 197 writer. 198 199 Pipes implement the `Pipe` interface and a number of operations to support 200 this interaction mechanism. 201 202 The details of an endpoint's current region can be queried using the following 203 operation: 204 205 {{{ 206 current_region(out offset_t populated_size, out offset_t size) 207 }}} 208 209 This provides details of the populated size (or amount of written data) in a 210 region along with the size of the region. 211 212 Navigation to the next available region of the pipe is performed using the 213 following operation: 214 215 {{{ 216 next_region(inout offset_t populated_size, out offset_t size) 217 }}} 218 219 Here, the populated size may be specified by the writer so that the reader may 220 query the current region's properties using the appropriate operation. 221 222 The status of the pipe can be queried using the `closed` operation: 223 224 {{{ 225 closed(out int closed) 226 }}} 227 228 This indicates through a boolean-equivalent parameter whether one or both 229 endpoints have been closed.