L4Re - L4 Runtime Environment
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 #include "vfs_api.h"
21 
22 #include <l4/re/dataspace>
23 #include <l4/re/util/env_ns>
24 #include <l4/re/unique_cap>
25 #include <dirent.h>
26 
27 namespace L4Re { namespace Core {
28 
29 static
30 Ref_ptr<L4Re::Vfs::File>
31 cap_to_vfs_object(L4::Cap<void> o, int *err)
32 {
34  long proto = 0;
35  char name_buf[256];
36  L4::Ipc::String<char> name(sizeof(name_buf), name_buf);
37  int r = l4_error(m->interface(0, &proto, &name));
38  *err = -ENOPROTOOPT;
39  if (r < 0)
40  // could not get type of object so bail out
41  return Ref_ptr<L4Re::Vfs::File>();
42 
43  *err = -EPROTO;
44  Ref_ptr<L4Re::Vfs::File_factory> factory;
45 
46  if (proto != 0)
47  factory = L4Re::Vfs::vfs_ops->get_file_factory(proto);
48 
49  if (!factory)
50  factory = L4Re::Vfs::vfs_ops->get_file_factory(name.data);
51 
52  if (!factory)
53  return Ref_ptr<L4Re::Vfs::File>();
54 
55  *err = -ENOMEM;
56  return factory->create(o);
57 }
58 
59 
60 int
61 Ns_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) throw()
62 {
63  auto file = L4Re::make_unique_cap<L4Re::Dataspace>(cap_alloc());
64 
65  if (!file.is_valid())
66  return -ENOMEM;
67 
68  int err = _ns->query(path, file.get());
69 
70  if (err < 0)
71  return -ENOENT;
72 
73  *ds = cxx::move(file);
74  return err;
75 }
76 
77 int
78 Ns_dir::get_entry(const char *path, int flags, mode_t mode,
79  Ref_ptr<L4Re::Vfs::File> *f) throw()
80 {
81  (void)mode; (void)flags;
82  if (!*path)
83  {
84  *f = cxx::ref_ptr(this);
85  return 0;
86  }
87 
88  L4Re::Unique_cap<Dataspace> file;
89  int err = get_ds(path, &file);
90 
91  if (err < 0)
92  return -ENOENT;
93 
94  cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
95  if (!fi)
96  return err;
97 
98  file.release();
99  *f = cxx::move(fi);
100  return 0;
101 }
102 
103 int
104 Ns_dir::faccessat(const char *path, int mode, int flags) throw()
105 {
106  (void)flags;
107  auto tmpcap = L4Re::make_unique_cap<void>(cap_alloc());
108 
109  if (!tmpcap.is_valid())
110  return -ENOMEM;
111 
112  if (_ns->query(path, tmpcap.get()))
113  return -ENOENT;
114 
115  if (mode & W_OK)
116  return -EACCES;
117 
118  return 0;
119 }
120 
121 int
122 Ns_dir::fstat64(struct stat64 *b) const throw()
123 {
124  b->st_dev = 1;
125  b->st_ino = 1;
126  b->st_mode = S_IRWXU | S_IFDIR;
127  b->st_nlink = 0;
128  b->st_uid = 0;
129  b->st_gid = 0;
130  b->st_rdev = 0;
131  b->st_size = 0;
132  b->st_blksize = 0;
133  b->st_blocks = 0;
134  b->st_atime = 0;
135  b->st_mtime = 0;
136  b->st_ctime = 0;
137  return 0;
138 }
139 
140 ssize_t
141 Ns_dir::getdents(char *buf, size_t sz) throw()
142 {
143  struct dirent64 *d = (struct dirent64 *)buf;
144  ssize_t ret = 0;
145  l4_addr_t infoaddr;
146  size_t infosz;
147 
148  L4Re::Unique_cap<Dataspace> dirinfofile;
149  int err = get_ds(".dirinfo", &dirinfofile);
150  if (err)
151  return 0;
152 
153  infosz = dirinfofile->size();
154  if (infosz <= 0)
155  return 0;
156 
157  infoaddr = L4_PAGESIZE;
158  err = L4Re::Env::env()->rm()->attach(&infoaddr, infosz,
160  dirinfofile.get(), 0);
161  char *p = (char *)infoaddr + _current_dir_pos;
162  char *end = (char *)infoaddr + infosz;
163 
164  while (d && p < end)
165  {
166  // parse lines of dirinfofile
167  long len;
168  for (len = 0; p < end && *p >= '0' && *p <= '9'; ++p)
169  {
170  len *= 10;
171  len += *p - '0';
172  }
173  if (len)
174  {
175  // skip colon
176  p++;
177  if (p + len >= end)
178  return 0; // error in dirinfofile
179 
180  unsigned l = len + 1;
181  if (l > sizeof(d->d_name))
182  l = sizeof(d->d_name);
183 
184  unsigned n = offsetof (struct dirent64, d_name) + l;
185  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
186 
187  if (n > sz)
188  break;
189 
190  d->d_ino = 1;
191  d->d_off = 0;
192  memcpy(d->d_name, p, len);
193  d->d_name[l - 1] = 0;
194  d->d_reclen = n;
195  d->d_type = DT_REG;
196  ret += n;
197  sz -= n;
198  d = (struct dirent64 *)((unsigned long)d + n);
199  }
200 
201  // next infodirfile line
202  while (p < end && *p && *p != '\n' && *p != '\r')
203  p++;
204  while (p < end && *p && (*p == '\n' || *p == '\r'))
205  p++;
206  }
207 
208  _current_dir_pos += p - (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 
218 int
219 Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) throw()
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>(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 
253 int
254 Env_dir::get_entry(const char *path, int flags, mode_t mode,
255  Ref_ptr<L4Re::Vfs::File> *f) throw()
256 {
257  (void)mode; (void)flags;
258  if (!*path)
259  {
260  *f = cxx::ref_ptr(this);
261  return 0;
262  }
263 
264  L4Re::Unique_cap<Dataspace> file;
265  int err = get_ds(path, &file);
266 
267  if (err < 0)
268  return -ENOENT;
269 
270  cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
271  if (!fi)
272  return err;
273 
274  file.release();
275  *f = cxx::move(fi);
276  return 0;
277 }
278 
279 int
280 Env_dir::faccessat(const char *path, int mode, int flags) throw()
281 {
282  (void)flags;
283  Vfs::Path p(path);
284  Vfs::Path first = p.strip_first();
285 
286  if (first.empty())
287  return -ENOENT;
288 
290  c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
291 
292  if (!c.is_valid())
293  return -ENOENT;
294 
295  if (p.empty())
296  {
297  if (mode & W_OK)
298  return -EACCES;
299 
300  return 0;
301  }
302 
303  auto tmpcap = L4Re::make_unique_cap<void>(cap_alloc());
304 
305  if (!tmpcap.is_valid())
306  return -ENOMEM;
307 
308  if (c->query(p.path(), p.length(), tmpcap.get()))
309  return -ENOENT;
310 
311  if (mode & W_OK)
312  return -EACCES;
313 
314  return 0;
315 }
316 
317 bool
318 Env_dir::check_type(Env::Cap_entry const *e, long protocol) throw()
319 {
320  L4::Cap<L4::Meta> m(e->cap);
321  return m->supports(protocol).label();
322 }
323 
324 int
325 Env_dir::fstat64(struct stat64 *b) const throw()
326 {
327  b->st_dev = 1;
328  b->st_ino = 1;
329  b->st_mode = S_IRWXU | S_IFDIR;
330  b->st_nlink = 0;
331  b->st_uid = 0;
332  b->st_gid = 0;
333  b->st_rdev = 0;
334  b->st_size = 0;
335  b->st_blksize = 0;
336  b->st_blocks = 0;
337  b->st_atime = 0;
338  b->st_mtime = 0;
339  b->st_ctime = 0;
340  return 0;
341 }
342 
343 ssize_t
344 Env_dir::getdents(char *buf, size_t sz) throw()
345 {
346  struct dirent64 *d = (struct dirent64 *)buf;
347  ssize_t ret = 0;
348 
349  while (d
350  && _current_cap_entry
351  && _current_cap_entry->flags != ~0UL)
352  {
353  unsigned l = strlen(_current_cap_entry->name) + 1;
354  if (l > sizeof(d->d_name))
355  l = sizeof(d->d_name);
356 
357  unsigned n = offsetof (struct dirent64, d_name) + l;
358  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
359 
360  if (n <= sz)
361  {
362  d->d_ino = 1;
363  d->d_off = 0;
364  memcpy(d->d_name, _current_cap_entry->name, l);
365  d->d_name[l - 1] = 0;
366  d->d_reclen = n;
367  if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
368  d->d_type = DT_DIR;
369  else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
370  d->d_type = DT_REG;
371  else
372  d->d_type = DT_UNKNOWN;
373  ret += n;
374  sz -= n;
375  d = (struct dirent64 *)((unsigned long)d + n);
376  _current_cap_entry++;
377  }
378  else
379  return ret;
380  }
381 
382  // bit of a hack because we should only (re)set this when opening the dir
383  if (!ret)
384  _current_cap_entry = _env->initial_caps();
385 
386  return ret;
387 }
388 
389 }}
l4re_env_cap_entry_t Cap_entry
C++ type for an entry in the initial objects array.
Definition: env:91
long query(char const *name, L4::Cap< void > const &cap, int timeout=To_default, l4_umword_t *local_id=0, bool iterate=true) const
Query the name space for a named object.
l4_msgtag_t supports(l4_mword_t protocol)
Figure out if the object supports the given protocol (number).
Name-space interface.
Definition: namespace:60
L4Re C++ Interfaces.
Definition: cmd_control:15
Search for a suitable address range.
Definition: rm:113
long label() const
Get the protocol value.
Definition: types.h:163
Interface for memory-like objects.
Definition: dataspace:59
Meta interface that shall be implemented by each L4Re object and gives access to the dynamic type inf...
Definition: meta:37
Cap< T > cap_reinterpret_cast(Cap< F > const &c)
reinterpret_cast for capabilities.
Definition: capability.h:407
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition: consts.h:277
static Env const * env()
Returns the initial environment for the current task.
Definition: env:100
_Cap_alloc & cap_alloc
Capability allocator.
l4_msgtag_t interface(l4_umword_t idx, long *proto, L4::Ipc::String< char > *name)
Get the protocol number that must be used for the interface with the number idx.
bool is_valid() const
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
Definition: capability.h:59
long l4_error(l4_msgtag_t tag) L4_NOTHROW
Return error code of a system call return message tag.
Definition: ipc.h:517
Region is read-only.
Definition: rm:88
Dataspace interface.
C++ interface for capabilities.
Definition: capability.h:13
unsigned long l4_addr_t
Address type.
Definition: l4int.h:45
L4::Cap< Rm > rm() const
Object-capability to the region map.
Definition: env:124