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 (void)mode; (void)flags;
81 if (!*path)
82 {
83 *f = cxx::ref_ptr(this);
84 return 0;
85 }
86
88 int err = get_ds(path, &file);
89
90 if (err < 0)
91 return -ENOENT;
92
93 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
94 if (!fi)
95 return err;
96
97 file.release();
98 *f = cxx::move(fi);
99 return 0;
100}
101
102int
103Ns_dir::faccessat(const char *path, int mode, int flags) noexcept
104{
105 (void)flags;
106 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
107
108 if (!tmpcap.is_valid())
109 return -ENOMEM;
110
111 if (_ns->query(path, tmpcap.get()))
112 return -ENOENT;
113
114 if (mode & W_OK)
115 return -EACCES;
116
117 return 0;
118}
119
120int
121Ns_dir::fstat64(struct stat64 *b) const noexcept
122{
123 b->st_dev = 1;
124 b->st_ino = 1;
125 b->st_mode = S_IRWXU | S_IFDIR;
126 b->st_nlink = 0;
127 b->st_uid = 0;
128 b->st_gid = 0;
129 b->st_rdev = 0;
130 b->st_size = 0;
131 b->st_blksize = 0;
132 b->st_blocks = 0;
133 b->st_atime = 0;
134 b->st_mtime = 0;
135 b->st_ctime = 0;
136 return 0;
137}
138
139ssize_t
140Ns_dir::getdents(char *buf, size_t dest_sz) noexcept
141{
142 struct dirent64 *dest = (struct dirent64 *)buf;
143 ssize_t ret = 0;
144 l4_addr_t infoaddr;
145 size_t infosz;
146
147 L4Re::Unique_cap<Dataspace> dirinfofile;
148 int err = get_ds(".dirinfo", &dirinfofile);
149 if (err)
150 return 0;
151
152 infosz = dirinfofile->size();
153 if (infosz <= 0)
154 return 0;
155
156 infoaddr = L4_PAGESIZE;
157 err = L4Re::Env::env()->rm()->attach(&infoaddr, infosz,
159 dirinfofile.get(), 0);
160 if (err < 0)
161 return 0;
162
163 char *p = (char *)infoaddr + _current_dir_pos;
164 char *end = (char *)infoaddr + infosz;
165
166 char *current_dirinfo_entry = p;
167 while (dest && p < end)
168 {
169 // parse lines of dirinfofile
170 long len = 0;
171 for (; p < end && *p >= '0' && *p <= '9'; ++p)
172 {
173 len *= 10;
174 len += *p - '0';
175 }
176
177 if (len == 0)
178 break;
179
180 if (p == end)
181 break;
182
183 if (*p != ':')
184 break;
185 p++; // skip colon
186
187 if (p + len >= end)
188 break;
189
190 unsigned l = len + 1;
191 if (l > sizeof(dest->d_name))
192 l = sizeof(dest->d_name);
193
194 unsigned n = offsetof (struct dirent64, d_name) + l;
195 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
196
197 if (n > dest_sz)
198 break;
199
200 dest->d_ino = 1;
201 dest->d_off = 0;
202 memcpy(dest->d_name, p, l - 1);
203 dest->d_name[l - 1] = 0;
204 dest->d_reclen = n;
205 dest->d_type = DT_REG;
206 ret += n;
207 dest_sz -= n;
208
209 // next entry
210 dest = (struct dirent64 *)((unsigned long)dest + n);
211
212 // next infodirfile line
213 p += len;
214 while (p < end && *p && (*p == '\n' || *p == '\r'))
215 p++;
216
217 current_dirinfo_entry = p;
218 }
219
220 _current_dir_pos = current_dirinfo_entry - (char *)infoaddr;
221
222 if (!ret) // hack since we should only reset this at open times
223 _current_dir_pos = 0;
224
225 L4Re::Env::env()->rm()->detach(infoaddr, 0);
226
227 return ret;
228}
229
230int
231Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) noexcept
232{
233 Vfs::Path p(path);
234 Vfs::Path first = p.strip_first();
235
236 if (first.empty())
237 return -ENOENT;
238
240 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
241
242 if (!c.is_valid())
243 return -ENOENT;
244
245 if (p.empty())
246 {
247 *ds = L4Re::Unique_cap<L4Re::Dataspace>(L4::cap_reinterpret_cast<L4Re::Dataspace>(c));
248 return 0;
249 }
250
251 auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
252
253 if (!file.is_valid())
254 return -ENOMEM;
255
256 int err = c->query(p.path(), p.length(), file.get());
257
258 if (err < 0)
259 return -ENOENT;
260
261 *ds = cxx::move(file);
262 return err;
263}
264
265int
266Env_dir::get_entry(const char *path, int flags, mode_t mode,
267 Ref_ptr<L4Re::Vfs::File> *f) noexcept
268{
269 (void)mode; (void)flags;
270 if (!*path)
271 {
272 *f = cxx::ref_ptr(this);
273 return 0;
274 }
275
277 int err = get_ds(path, &file);
278
279 if (err < 0)
280 return -ENOENT;
281
282 cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
283 if (!fi)
284 return err;
285
286 file.release();
287 *f = cxx::move(fi);
288 return 0;
289}
290
291int
292Env_dir::faccessat(const char *path, int mode, int flags) noexcept
293{
294 (void)flags;
295 Vfs::Path p(path);
296 Vfs::Path first = p.strip_first();
297
298 if (first.empty())
299 return -ENOENT;
300
302 c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
303
304 if (!c.is_valid())
305 return -ENOENT;
306
307 if (p.empty())
308 {
309 if (mode & W_OK)
310 return -EACCES;
311
312 return 0;
313 }
314
315 auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
316
317 if (!tmpcap.is_valid())
318 return -ENOMEM;
319
320 if (c->query(p.path(), p.length(), tmpcap.get()))
321 return -ENOENT;
322
323 if (mode & W_OK)
324 return -EACCES;
325
326 return 0;
327}
328
329bool
330Env_dir::check_type(Env::Cap_entry const *e, long protocol) noexcept
331{
332 L4::Cap<L4::Meta> m(e->cap);
333 return m->supports(protocol).label();
334}
335
336int
337Env_dir::fstat64(struct stat64 *b) const noexcept
338{
339 b->st_dev = 1;
340 b->st_ino = 1;
341 b->st_mode = S_IRWXU | S_IFDIR;
342 b->st_nlink = 0;
343 b->st_uid = 0;
344 b->st_gid = 0;
345 b->st_rdev = 0;
346 b->st_size = 0;
347 b->st_blksize = 0;
348 b->st_blocks = 0;
349 b->st_atime = 0;
350 b->st_mtime = 0;
351 b->st_ctime = 0;
352 return 0;
353}
354
355ssize_t
356Env_dir::getdents(char *buf, size_t sz) noexcept
357{
358 struct dirent64 *d = (struct dirent64 *)buf;
359 ssize_t ret = 0;
360
361 while (d
362 && _current_cap_entry
363 && _current_cap_entry->flags != ~0UL)
364 {
365 unsigned l = strlen(_current_cap_entry->name) + 1;
366 if (l > sizeof(d->d_name))
367 l = sizeof(d->d_name);
368
369 unsigned n = offsetof (struct dirent64, d_name) + l;
370 n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
371
372 if (n <= sz)
373 {
374 d->d_ino = 1;
375 d->d_off = 0;
376 memcpy(d->d_name, _current_cap_entry->name, l);
377 d->d_name[l - 1] = 0;
378 d->d_reclen = n;
379 if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
380 d->d_type = DT_DIR;
381 else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
382 d->d_type = DT_REG;
383 else
384 d->d_type = DT_UNKNOWN;
385 ret += n;
386 sz -= n;
387 d = (struct dirent64 *)((unsigned long)d + n);
388 _current_cap_entry++;
389 }
390 else
391 return ret;
392 }
393
394 // bit of a hack because we should only (re)set this when opening the dir
395 if (!ret)
396 _current_cap_entry = _env->initial_caps();
397
398 return ret;
399}
400
401}}
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:60
C++ interface for capabilities.
Definition capability.h:222
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:636
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:380
L4Re C++ Interfaces.
Definition cmd_control:15
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:134
@ Search_addr
Search for a suitable address range.
Definition rm:118
Unique_cap / Unique_del_cap.