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