L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
ns_fs_impl.h
1/*
2 * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 *
6 * License: see LICENSE.spdx (in this directory or the directories above)
7 */
8#include "ns_fs.h"
9
10#include <l4/re/dataspace>
11#include <l4/re/util/env_ns>
12#include <l4/re/unique_cap>
13#include <dirent.h>
14
15namespace L4Re { namespace Core {
16
17static
19cap_to_vfs_object(L4::Cap<void> o, int *err)
20{
21 L4::Cap<L4::Meta> m = L4::cap_reinterpret_cast<L4::Meta>(o);
22 long proto = 0;
23 char name_buf[256];
24 L4::Ipc::String<char> name(sizeof(name_buf), name_buf);
25 l4_ret_t r = l4_error(m->interface(0, &proto, &name));
26 *err = -ENOPROTOOPT;
27 if (r < 0)
28 // could not get type of object so bail out
30
31 *err = -EPROTO;
33
34 if (proto != 0)
35 factory = L4Re::Vfs::vfs_ops->get_file_factory(proto);
36
37 if (!factory)
38 factory = L4Re::Vfs::vfs_ops->get_file_factory(name.data);
39
40 if (!factory)
42
43 *err = -ENOMEM;
44 return factory->create(o);
45}
46
47
48int
49Ns_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) noexcept
50{
51 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
52
53 if (!file.is_valid())
54 return -ENOMEM;
55
56 int err = _ns->query(path, file.get());
57
58 if (err < 0)
59 return -ENOENT;
60
61 *ds = cxx::move(file);
62 return err;
63}
64
65int
66Ns_dir::get_entry(const char *path, int /*flags*/, mode_t /*mode*/,
67 Ref_ptr<L4Re::Vfs::File> *f) noexcept
68{
69 if (!*path)
70 {
71 *f = cxx::ref_ptr(this);
72 return 0;
73 }
74
76 int err = get_ds(path, &file);
77
78 if (err < 0)
79 return -ENOENT;
80
81 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
82 if (!fi)
83 return err;
84
85 file.release();
86 *f = cxx::move(fi);
87 return 0;
88}
89
90int
91Ns_dir::faccessat(const char *path, int mode, int /*flags*/) noexcept
92{
93 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
94
95 if (!tmpcap.is_valid())
96 return -ENOMEM;
97
98 if (_ns->query(path, tmpcap.get()))
99 return -ENOENT;
100
101 if (mode & W_OK)
102 return -EACCES;
103
104 return 0;
105}
106
107int
108Ns_dir::fstat(struct stat64 *b) const noexcept
109{
110 b->st_dev = 1;
111 b->st_ino = 1;
112 b->st_mode = S_IRWXU | S_IFDIR;
113 b->st_nlink = 0;
114 b->st_uid = 0;
115 b->st_gid = 0;
116 b->st_rdev = 0;
117 b->st_size = 0;
118 b->st_blksize = 0;
119 b->st_blocks = 0;
120 b->st_atime = 0;
121 b->st_mtime = 0;
122 b->st_ctime = 0;
123 return 0;
124}
125
126ssize_t
127Ns_dir::getdents(char *buf, size_t dest_sz) noexcept
128{
129 struct dirent64 *dest = reinterpret_cast<struct dirent64 *>(buf);
130 ssize_t ret = 0;
131 l4_addr_t infoaddr;
132 size_t infosz;
133
134 L4Re::Unique_cap<Dataspace> dirinfofile;
135 int err = get_ds(".dirinfo", &dirinfofile);
136 if (err)
137 return 0;
138
139 infosz = dirinfofile->size();
140 if (infosz <= 0)
141 return 0;
142
143 infoaddr = L4_PAGESIZE;
144 err = L4Re::Env::env()->rm()->attach(&infoaddr, infosz,
146 dirinfofile.get(), 0);
147 if (err < 0)
148 return 0;
149
150 char *p = reinterpret_cast<char *>(infoaddr) + _current_dir_pos;
151 char *end = reinterpret_cast<char *>(infoaddr) + infosz;
152
153 char *current_dirinfo_entry = p;
154 while (dest && p < end)
155 {
156 // parse lines of dirinfofile
157 long len = 0;
158 for (; p < end && *p >= '0' && *p <= '9'; ++p)
159 {
160 len *= 10;
161 len += *p - '0';
162 }
163
164 if (len == 0)
165 break;
166
167 if (p == end)
168 break;
169
170 if (*p != ':')
171 break;
172 p++; // skip colon
173
174 if (p + len >= end)
175 break;
176
177 unsigned l = len + 1;
178 if (l > sizeof(dest->d_name))
179 l = sizeof(dest->d_name);
180
181 unsigned n = offsetof (struct dirent64, d_name) + l;
182 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
183
184 if (n > dest_sz)
185 break;
186
187 dest->d_ino = 1;
188 dest->d_off = 0;
189 memcpy(dest->d_name, p, l - 1);
190 dest->d_name[l - 1] = 0;
191 dest->d_reclen = n;
192 dest->d_type = DT_UNKNOWN;
193 ret += n;
194 dest_sz -= n;
195
196 // next entry
197 dest = reinterpret_cast<struct dirent64 *>
198 (reinterpret_cast<unsigned long>(dest) + n);
199
200 // next infodirfile line
201 p += len;
202 while (p < end && *p && (*p == '\n' || *p == '\r'))
203 p++;
204
205 current_dirinfo_entry = p;
206 }
207
208 _current_dir_pos = current_dirinfo_entry - reinterpret_cast<char *>(infoaddr);
209
210 if (!ret) // hack since we should only reset this at open times
211 _current_dir_pos = 0;
212
213 L4Re::Env::env()->rm()->detach(infoaddr, 0);
214
215 return ret;
216}
217
218int
219Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) noexcept
220{
221 while (*path == '/')
222 ++path;
223 Vfs::Path p(path);
224 Vfs::Path first = p.strip_first();
225
226 if (first.empty())
227 return -ENOENT;
228
229 L4::Cap<L4Re::Namespace>
230 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
231
232 if (!c.is_valid())
233 return -ENOENT;
234
235 if (p.empty())
236 {
238 return 0;
239 }
240
241 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
242
243 if (!file.is_valid())
244 return -ENOMEM;
245
246 int err = c->query(p.path(), p.length(), file.get());
247
248 if (err < 0)
249 return -ENOENT;
250
251 *ds = cxx::move(file);
252 return err;
253}
254
255int
256Env_dir::get_entry(const char *path, int /*flags*/, mode_t /*mode*/,
257 Ref_ptr<L4Re::Vfs::File> *f) noexcept
258{
259 if (!*path)
260 {
261 *f = cxx::ref_ptr(this);
262 return 0;
263 }
264
266 int err = get_ds(path, &file);
267
268 if (err < 0)
269 return -ENOENT;
270
271 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
272 if (!fi)
273 return err;
274
275 file.release();
276 *f = cxx::move(fi);
277 return 0;
278}
279
280int
281Env_dir::faccessat(const char *path, int mode, int /*flags*/) noexcept
282{
283 while (*path == '/')
284 ++path;
285 Vfs::Path p(path);
286 Vfs::Path first = p.strip_first();
287
288 if (first.empty())
289 return -ENOENT;
290
291 L4::Cap<L4Re::Namespace>
292 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
293
294 if (!c.is_valid())
295 return -ENOENT;
296
297 if (p.empty())
298 {
299 if (mode & W_OK)
300 return -EACCES;
301
302 return 0;
303 }
304
305 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
306
307 if (!tmpcap.is_valid())
308 return -ENOMEM;
309
310 if (c->query(p.path(), p.length(), tmpcap.get()))
311 return -ENOENT;
312
313 if (mode & W_OK)
314 return -EACCES;
315
316 return 0;
317}
318
319bool
320Env_dir::check_type(Env::Cap_entry const *e, long protocol) noexcept
321{
322 L4::Cap<L4::Meta> m(e->cap);
323 return m->supports(protocol).label();
324}
325
326int
327Env_dir::fstat(struct stat64 *b) const noexcept
328{
329 b->st_dev = 1;
330 b->st_ino = 1;
331 b->st_mode = S_IRWXU | S_IFDIR;
332 b->st_nlink = 0;
333 b->st_uid = 0;
334 b->st_gid = 0;
335 b->st_rdev = 0;
336 b->st_size = 0;
337 b->st_blksize = 0;
338 b->st_blocks = 0;
339 b->st_atime = 0;
340 b->st_mtime = 0;
341 b->st_ctime = 0;
342 return 0;
343}
344
345ssize_t
346Env_dir::getdents(char *buf, size_t sz) noexcept
347{
348 struct dirent64 *d = reinterpret_cast<struct dirent64 *>(buf);
349 ssize_t ret = 0;
350
351 while (d
352 && _current_cap_entry
353 && _current_cap_entry->flags != ~0UL)
354 {
355 unsigned l = strlen(_current_cap_entry->name) + 1;
356 if (l > sizeof(d->d_name))
357 l = sizeof(d->d_name);
358
359 unsigned n = offsetof (struct dirent64, d_name) + l;
360 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
361
362 if (n <= sz)
363 {
364 d->d_ino = 1;
365 d->d_off = 0;
366 memcpy(d->d_name, _current_cap_entry->name, l);
367 d->d_name[l - 1] = 0;
368 d->d_reclen = n;
369 if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
370 d->d_type = DT_DIR;
371 else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
372 d->d_type = DT_REG;
373 else
374 d->d_type = DT_UNKNOWN;
375 ret += n;
376 sz -= n;
377 d = reinterpret_cast<struct dirent64 *>
378 (reinterpret_cast<unsigned long>(d) + n);
379 _current_cap_entry++;
380 }
381 else
382 return ret;
383 }
384
385 // bit of a hack because we should only (re)set this when opening the dir
386 if (!ret)
387 _current_cap_entry = _env->initial_caps();
388
389 return ret;
390}
391
392}}
static Env const * env() noexcept
Returns the initial environment for the current task.
Definition env:96
l4re_env_cap_entry_t Cap_entry
C++ type for an entry in the initial objects array.
Definition env:87
L4::Cap< Rm > rm() const noexcept
Object-capability to the region map.
Definition env:120
bool is_valid() const noexcept
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
Definition capability.h:57
A reference-counting pointer with automatic cleanup.
Definition ref_ptr:71
Dataspace interface.
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
l4_ret_t l4_error(l4_msgtag_t tag) L4_NOTHROW
Get IPC error code if any or message tag label otherwise for an IPC call.
Definition ipc.h:650
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:389
l4_int16_t l4_ret_t
Return value of an IPC call as well as an RPC call.
Definition types.h:28
L4Re C++ Interfaces.
Definition cmd_control:14
L4::Detail::Unique_cap_impl< T, L4Re::Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
Definition unique_cap:31
Unique_cap< T > make_unique_cap(L4Re::Cap_alloc *ca)
Allocate a capability slot and wrap it in an Unique_cap.
Definition unique_cap:48
Cap< T > cap_reinterpret_cast(Cap< F > const &c) noexcept
reinterpret_cast for capabilities.
Definition capability.h:447
@ R
Readable region.
Definition rm:133
@ Search_addr
Search for a suitable address range.
Definition rm:113
Unique_cap / Unique_del_cap.