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 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
9 *
10 * As a special exception, you may use this file as part of a free software
11 * library without restriction. Specifically, if other files instantiate
12 * templates or use macros or inline functions from this file, or you compile
13 * this file and link it with other files to produce an executable, this
14 * file does not by itself cause the resulting executable to be covered by
15 * the GNU General Public License. This exception does not however
16 * invalidate any other reasons why the executable file might be covered by
17 * the GNU General Public License.
18 */
19#include "ns_fs.h"
20
21#include <l4/re/dataspace>
22#include <l4/re/util/env_ns>
23#include <l4/re/unique_cap>
24#include <dirent.h>
25
26namespace L4Re { namespace Core {
27
28static
29Ref_ptr<L4Re::Vfs::File>
30cap_to_vfs_object(L4::Cap<void> o, int *err)
31{
32 L4::Cap<L4::Meta> m = L4::cap_reinterpret_cast<L4::Meta>(o);
33 long proto = 0;
34 char name_buf[256];
35 L4::Ipc::String<char> name(sizeof(name_buf), name_buf);
36 int r = l4_error(m->interface(0, &proto, &name));
37 *err = -ENOPROTOOPT;
38 if (r < 0)
39 // could not get type of object so bail out
40 return Ref_ptr<L4Re::Vfs::File>();
41
42 *err = -EPROTO;
43 Ref_ptr<L4Re::Vfs::File_factory> factory;
44
45 if (proto != 0)
46 factory = L4Re::Vfs::vfs_ops->get_file_factory(proto);
47
48 if (!factory)
49 factory = L4Re::Vfs::vfs_ops->get_file_factory(name.data);
50
51 if (!factory)
52 return Ref_ptr<L4Re::Vfs::File>();
53
54 *err = -ENOMEM;
55 return factory->create(o);
56}
57
58
59int
60Ns_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) noexcept
61{
62 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
63
64 if (!file.is_valid())
65 return -ENOMEM;
66
67 int err = _ns->query(path, file.get());
68
69 if (err < 0)
70 return -ENOENT;
71
72 *ds = cxx::move(file);
73 return err;
74}
75
76int
77Ns_dir::get_entry(const char *path, int /*flags*/, mode_t /*mode*/,
78 Ref_ptr<L4Re::Vfs::File> *f) noexcept
79{
80 if (!*path)
81 {
82 *f = cxx::ref_ptr(this);
83 return 0;
84 }
85
87 int err = get_ds(path, &file);
88
89 if (err < 0)
90 return -ENOENT;
91
92 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
93 if (!fi)
94 return err;
95
96 file.release();
97 *f = cxx::move(fi);
98 return 0;
99}
100
101int
102Ns_dir::faccessat(const char *path, int mode, int /*flags*/) noexcept
103{
104 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
105
106 if (!tmpcap.is_valid())
107 return -ENOMEM;
108
109 if (_ns->query(path, tmpcap.get()))
110 return -ENOENT;
111
112 if (mode & W_OK)
113 return -EACCES;
114
115 return 0;
116}
117
118int
119Ns_dir::fstat64(struct stat64 *b) const noexcept
120{
121 b->st_dev = 1;
122 b->st_ino = 1;
123 b->st_mode = S_IRWXU | S_IFDIR;
124 b->st_nlink = 0;
125 b->st_uid = 0;
126 b->st_gid = 0;
127 b->st_rdev = 0;
128 b->st_size = 0;
129 b->st_blksize = 0;
130 b->st_blocks = 0;
131 b->st_atime = 0;
132 b->st_mtime = 0;
133 b->st_ctime = 0;
134 return 0;
135}
136
137ssize_t
138Ns_dir::getdents(char *buf, size_t dest_sz) noexcept
139{
140 struct dirent64 *dest = reinterpret_cast<struct dirent64 *>(buf);
141 ssize_t ret = 0;
142 l4_addr_t infoaddr;
143 size_t infosz;
144
145 L4Re::Unique_cap<Dataspace> dirinfofile;
146 int err = get_ds(".dirinfo", &dirinfofile);
147 if (err)
148 return 0;
149
150 infosz = dirinfofile->size();
151 if (infosz <= 0)
152 return 0;
153
154 infoaddr = L4_PAGESIZE;
155 err = L4Re::Env::env()->rm()->attach(&infoaddr, infosz,
157 dirinfofile.get(), 0);
158 if (err < 0)
159 return 0;
160
161 char *p = reinterpret_cast<char *>(infoaddr) + _current_dir_pos;
162 char *end = reinterpret_cast<char *>(infoaddr) + infosz;
163
164 char *current_dirinfo_entry = p;
165 while (dest && p < end)
166 {
167 // parse lines of dirinfofile
168 long len = 0;
169 for (; p < end && *p >= '0' && *p <= '9'; ++p)
170 {
171 len *= 10;
172 len += *p - '0';
173 }
174
175 if (len == 0)
176 break;
177
178 if (p == end)
179 break;
180
181 if (*p != ':')
182 break;
183 p++; // skip colon
184
185 if (p + len >= end)
186 break;
187
188 unsigned l = len + 1;
189 if (l > sizeof(dest->d_name))
190 l = sizeof(dest->d_name);
191
192 unsigned n = offsetof (struct dirent64, d_name) + l;
193 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
194
195 if (n > dest_sz)
196 break;
197
198 dest->d_ino = 1;
199 dest->d_off = 0;
200 memcpy(dest->d_name, p, l - 1);
201 dest->d_name[l - 1] = 0;
202 dest->d_reclen = n;
203 dest->d_type = DT_UNKNOWN;
204 ret += n;
205 dest_sz -= n;
206
207 // next entry
208 dest = reinterpret_cast<struct dirent64 *>
209 (reinterpret_cast<unsigned long>(dest) + n);
210
211 // next infodirfile line
212 p += len;
213 while (p < end && *p && (*p == '\n' || *p == '\r'))
214 p++;
215
216 current_dirinfo_entry = p;
217 }
218
219 _current_dir_pos = current_dirinfo_entry - reinterpret_cast<char *>(infoaddr);
220
221 if (!ret) // hack since we should only reset this at open times
222 _current_dir_pos = 0;
223
224 L4Re::Env::env()->rm()->detach(infoaddr, 0);
225
226 return ret;
227}
228
229int
230Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) noexcept
231{
232 Vfs::Path p(path);
233 Vfs::Path first = p.strip_first();
234
235 if (first.empty())
236 return -ENOENT;
237
239 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
240
241 if (!c.is_valid())
242 return -ENOENT;
243
244 if (p.empty())
245 {
246 *ds = L4Re::Unique_cap<L4Re::Dataspace>(L4::cap_reinterpret_cast<L4Re::Dataspace>(c));
247 return 0;
248 }
249
250 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
251
252 if (!file.is_valid())
253 return -ENOMEM;
254
255 int err = c->query(p.path(), p.length(), file.get());
256
257 if (err < 0)
258 return -ENOENT;
259
260 *ds = cxx::move(file);
261 return err;
262}
263
264int
265Env_dir::get_entry(const char *path, int /*flags*/, mode_t /*mode*/,
266 Ref_ptr<L4Re::Vfs::File> *f) noexcept
267{
268 if (!*path)
269 {
270 *f = cxx::ref_ptr(this);
271 return 0;
272 }
273
275 int err = get_ds(path, &file);
276
277 if (err < 0)
278 return -ENOENT;
279
280 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
281 if (!fi)
282 return err;
283
284 file.release();
285 *f = cxx::move(fi);
286 return 0;
287}
288
289int
290Env_dir::faccessat(const char *path, int mode, int /*flags*/) noexcept
291{
292 Vfs::Path p(path);
293 Vfs::Path first = p.strip_first();
294
295 if (first.empty())
296 return -ENOENT;
297
299 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
300
301 if (!c.is_valid())
302 return -ENOENT;
303
304 if (p.empty())
305 {
306 if (mode & W_OK)
307 return -EACCES;
308
309 return 0;
310 }
311
312 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
313
314 if (!tmpcap.is_valid())
315 return -ENOMEM;
316
317 if (c->query(p.path(), p.length(), tmpcap.get()))
318 return -ENOENT;
319
320 if (mode & W_OK)
321 return -EACCES;
322
323 return 0;
324}
325
326bool
327Env_dir::check_type(Env::Cap_entry const *e, long protocol) noexcept
328{
329 L4::Cap<L4::Meta> m(e->cap);
330 return m->supports(protocol).label();
331}
332
333int
334Env_dir::fstat64(struct stat64 *b) const noexcept
335{
336 b->st_dev = 1;
337 b->st_ino = 1;
338 b->st_mode = S_IRWXU | S_IFDIR;
339 b->st_nlink = 0;
340 b->st_uid = 0;
341 b->st_gid = 0;
342 b->st_rdev = 0;
343 b->st_size = 0;
344 b->st_blksize = 0;
345 b->st_blocks = 0;
346 b->st_atime = 0;
347 b->st_mtime = 0;
348 b->st_ctime = 0;
349 return 0;
350}
351
352ssize_t
353Env_dir::getdents(char *buf, size_t sz) noexcept
354{
355 struct dirent64 *d = reinterpret_cast<struct dirent64 *>(buf);
356 ssize_t ret = 0;
357
358 while (d
359 && _current_cap_entry
360 && _current_cap_entry->flags != ~0UL)
361 {
362 unsigned l = strlen(_current_cap_entry->name) + 1;
363 if (l > sizeof(d->d_name))
364 l = sizeof(d->d_name);
365
366 unsigned n = offsetof (struct dirent64, d_name) + l;
367 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
368
369 if (n <= sz)
370 {
371 d->d_ino = 1;
372 d->d_off = 0;
373 memcpy(d->d_name, _current_cap_entry->name, l);
374 d->d_name[l - 1] = 0;
375 d->d_reclen = n;
376 if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
377 d->d_type = DT_DIR;
378 else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
379 d->d_type = DT_REG;
380 else
381 d->d_type = DT_UNKNOWN;
382 ret += n;
383 sz -= n;
384 d = reinterpret_cast<struct dirent64 *>
385 (reinterpret_cast<unsigned long>(d) + n);
386 _current_cap_entry++;
387 }
388 else
389 return ret;
390 }
391
392 // bit of a hack because we should only (re)set this when opening the dir
393 if (!ret)
394 _current_cap_entry = _env->initial_caps();
395
396 return ret;
397}
398
399}}
static Env const * env() noexcept
Returns the initial environment for the current task.
Definition env:103
l4re_env_cap_entry_t Cap_entry
C++ type for an entry in the initial objects array.
Definition env:94
L4::Cap< Rm > rm() const noexcept
Object-capability to the region map.
Definition env:127
Name-space interface.
Definition namespace:63
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:82
Dataspace interface.
unsigned long l4_addr_t
Address type.
Definition l4int.h:45
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:657
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:380
L4Re C++ Interfaces.
Definition l4re.dox:17
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:42
@ R
Readable region.
Definition rm:144
@ Search_addr
Search for a suitable address range.
Definition rm:125
Unique_cap / Unique_del_cap.