L4Re Operating System Framework
Interface and Usage Documentation
•All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
18Ref_ptr<L4Re::Vfs::File>
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 int 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
29 return Ref_ptr<L4Re::Vfs::File>();
30
31 *err = -EPROTO;
32 Ref_ptr<L4Re::Vfs::File_factory> factory;
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)
41 return Ref_ptr<L4Re::Vfs::File>();
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::fstat64(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 Vfs::Path p(path);
222 Vfs::Path first = p.strip_first();
223
224 if (first.empty())
225 return -ENOENT;
226
228 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
229
230 if (!c.is_valid())
231 return -ENOENT;
232
233 if (p.empty())
234 {
235 *ds = L4Re::Unique_cap<L4Re::Dataspace>(L4::cap_reinterpret_cast<L4Re::Dataspace>(c));
236 return 0;
237 }
238
239 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
240
241 if (!file.is_valid())
242 return -ENOMEM;
243
244 int err = c->query(p.path(), p.length(), file.get());
245
246 if (err < 0)
247 return -ENOENT;
248
249 *ds = cxx::move(file);
250 return err;
251}
252
253int
254Env_dir::get_entry(const char *path, int /*flags*/, mode_t /*mode*/,
255 Ref_ptr<L4Re::Vfs::File> *f) noexcept
256{
257 if (!*path)
258 {
259 *f = cxx::ref_ptr(this);
260 return 0;
261 }
262
264 int err = get_ds(path, &file);
265
266 if (err < 0)
267 return -ENOENT;
268
269 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
270 if (!fi)
271 return err;
272
273 file.release();
274 *f = cxx::move(fi);
275 return 0;
276}
277
278int
279Env_dir::faccessat(const char *path, int mode, int /*flags*/) noexcept
280{
281 Vfs::Path p(path);
282 Vfs::Path first = p.strip_first();
283
284 if (first.empty())
285 return -ENOENT;
286
288 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
289
290 if (!c.is_valid())
291 return -ENOENT;
292
293 if (p.empty())
294 {
295 if (mode & W_OK)
296 return -EACCES;
297
298 return 0;
299 }
300
301 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
302
303 if (!tmpcap.is_valid())
304 return -ENOMEM;
305
306 if (c->query(p.path(), p.length(), tmpcap.get()))
307 return -ENOENT;
308
309 if (mode & W_OK)
310 return -EACCES;
311
312 return 0;
313}
314
315bool
316Env_dir::check_type(Env::Cap_entry const *e, long protocol) noexcept
317{
318 L4::Cap<L4::Meta> m(e->cap);
319 return m->supports(protocol).label();
320}
321
322int
323Env_dir::fstat64(struct stat64 *b) const noexcept
324{
325 b->st_dev = 1;
326 b->st_ino = 1;
327 b->st_mode = S_IRWXU | S_IFDIR;
328 b->st_nlink = 0;
329 b->st_uid = 0;
330 b->st_gid = 0;
331 b->st_rdev = 0;
332 b->st_size = 0;
333 b->st_blksize = 0;
334 b->st_blocks = 0;
335 b->st_atime = 0;
336 b->st_mtime = 0;
337 b->st_ctime = 0;
338 return 0;
339}
340
341ssize_t
342Env_dir::getdents(char *buf, size_t sz) noexcept
343{
344 struct dirent64 *d = reinterpret_cast<struct dirent64 *>(buf);
345 ssize_t ret = 0;
346
347 while (d
348 && _current_cap_entry
349 && _current_cap_entry->flags != ~0UL)
350 {
351 unsigned l = strlen(_current_cap_entry->name) + 1;
352 if (l > sizeof(d->d_name))
353 l = sizeof(d->d_name);
354
355 unsigned n = offsetof (struct dirent64, d_name) + l;
356 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
357
358 if (n <= sz)
359 {
360 d->d_ino = 1;
361 d->d_off = 0;
362 memcpy(d->d_name, _current_cap_entry->name, l);
363 d->d_name[l - 1] = 0;
364 d->d_reclen = n;
365 if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
366 d->d_type = DT_DIR;
367 else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
368 d->d_type = DT_REG;
369 else
370 d->d_type = DT_UNKNOWN;
371 ret += n;
372 sz -= n;
373 d = reinterpret_cast<struct dirent64 *>
374 (reinterpret_cast<unsigned long>(d) + n);
375 _current_cap_entry++;
376 }
377 else
378 return ret;
379 }
380
381 // bit of a hack because we should only (re)set this when opening the dir
382 if (!ret)
383 _current_cap_entry = _env->initial_caps();
384
385 return ret;
386}
387
388}}
static Env const * env() noexcept
Returns the initial environment for the current task.
Definition env:95
l4re_env_cap_entry_t Cap_entry
C++ type for an entry in the initial objects array.
Definition env:86
L4::Cap< Rm > rm() const noexcept
Object-capability to the region map.
Definition env:119
Name-space interface.
Definition namespace:52
bool is_valid() const noexcept
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
Definition capability.h:57
C++ interface for capabilities.
Definition capability.h:219
A reference-counting pointer with automatic cleanup.
Definition ref_ptr:71
Dataspace interface.
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
long 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:646
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:395
L4Re C++ Interfaces.
Definition cmd_control:14
L4::Detail::Unique_cap_impl< T, 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
@ R
Readable region.
Definition rm:133
@ Search_addr
Search for a suitable address range.
Definition rm:114
Unique_cap / Unique_del_cap.