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