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 
21 #include <l4/re/dataspace>
22 #include <l4/re/util/env_ns>
23 #include <l4/re/unique_cap>
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  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 
59 int
60 Ns_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) throw()
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 
76 int
77 Ns_dir::get_entry(const char *path, int flags, mode_t mode,
78  Ref_ptr<L4Re::Vfs::File> *f) throw()
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 
102 int
103 Ns_dir::faccessat(const char *path, int mode, int flags) throw()
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 
120 int
121 Ns_dir::fstat64(struct stat64 *b) const throw()
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 
139 ssize_t
140 Ns_dir::getdents(char *buf, size_t sz) throw()
141 {
142  struct dirent64 *d = (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  char *p = (char *)infoaddr + _current_dir_pos;
161  char *end = (char *)infoaddr + infosz;
162 
163  while (d && p < end)
164  {
165  // parse lines of dirinfofile
166  long len;
167  for (len = 0; p < end && *p >= '0' && *p <= '9'; ++p)
168  {
169  len *= 10;
170  len += *p - '0';
171  }
172  if (len)
173  {
174  // skip colon
175  p++;
176  if (p + len >= end)
177  return 0; // error in dirinfofile
178 
179  unsigned l = len + 1;
180  if (l > sizeof(d->d_name))
181  l = sizeof(d->d_name);
182 
183  unsigned n = offsetof (struct dirent64, d_name) + l;
184  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
185 
186  if (n > sz)
187  break;
188 
189  d->d_ino = 1;
190  d->d_off = 0;
191  memcpy(d->d_name, p, len);
192  d->d_name[l - 1] = 0;
193  d->d_reclen = n;
194  d->d_type = DT_REG;
195  ret += n;
196  sz -= n;
197  d = (struct dirent64 *)((unsigned long)d + n);
198  }
199 
200  // next infodirfile line
201  while (p < end && *p && *p != '\n' && *p != '\r')
202  p++;
203  while (p < end && *p && (*p == '\n' || *p == '\r'))
204  p++;
205  }
206 
207  _current_dir_pos += p - (char *)infoaddr;
208 
209  if (!ret) // hack since we should only reset this at open times
210  _current_dir_pos = 0;
211 
212  L4Re::Env::env()->rm()->detach(infoaddr, 0);
213 
214  return ret;
215 }
216 
217 int
218 Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) throw()
219 {
220  Vfs::Path p(path);
221  Vfs::Path first = p.strip_first();
222 
223  if (first.empty())
224  return -ENOENT;
225 
227  c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
228 
229  if (!c.is_valid())
230  return -ENOENT;
231 
232  if (p.empty())
233  {
235  return 0;
236  }
237 
238  auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
239 
240  if (!file.is_valid())
241  return -ENOMEM;
242 
243  int err = c->query(p.path(), p.length(), file.get());
244 
245  if (err < 0)
246  return -ENOENT;
247 
248  *ds = cxx::move(file);
249  return err;
250 }
251 
252 int
253 Env_dir::get_entry(const char *path, int flags, mode_t mode,
254  Ref_ptr<L4Re::Vfs::File> *f) throw()
255 {
256  (void)mode; (void)flags;
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 
278 int
279 Env_dir::faccessat(const char *path, int mode, int flags) throw()
280 {
281  (void)flags;
282  Vfs::Path p(path);
283  Vfs::Path first = p.strip_first();
284 
285  if (first.empty())
286  return -ENOENT;
287 
289  c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
290 
291  if (!c.is_valid())
292  return -ENOENT;
293 
294  if (p.empty())
295  {
296  if (mode & W_OK)
297  return -EACCES;
298 
299  return 0;
300  }
301 
302  auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
303 
304  if (!tmpcap.is_valid())
305  return -ENOMEM;
306 
307  if (c->query(p.path(), p.length(), tmpcap.get()))
308  return -ENOENT;
309 
310  if (mode & W_OK)
311  return -EACCES;
312 
313  return 0;
314 }
315 
316 bool
317 Env_dir::check_type(Env::Cap_entry const *e, long protocol) throw()
318 {
319  L4::Cap<L4::Meta> m(e->cap);
320  return m->supports(protocol).label();
321 }
322 
323 int
324 Env_dir::fstat64(struct stat64 *b) const throw()
325 {
326  b->st_dev = 1;
327  b->st_ino = 1;
328  b->st_mode = S_IRWXU | S_IFDIR;
329  b->st_nlink = 0;
330  b->st_uid = 0;
331  b->st_gid = 0;
332  b->st_rdev = 0;
333  b->st_size = 0;
334  b->st_blksize = 0;
335  b->st_blocks = 0;
336  b->st_atime = 0;
337  b->st_mtime = 0;
338  b->st_ctime = 0;
339  return 0;
340 }
341 
342 ssize_t
343 Env_dir::getdents(char *buf, size_t sz) throw()
344 {
345  struct dirent64 *d = (struct dirent64 *)buf;
346  ssize_t ret = 0;
347 
348  while (d
349  && _current_cap_entry
350  && _current_cap_entry->flags != ~0UL)
351  {
352  unsigned l = strlen(_current_cap_entry->name) + 1;
353  if (l > sizeof(d->d_name))
354  l = sizeof(d->d_name);
355 
356  unsigned n = offsetof (struct dirent64, d_name) + l;
357  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
358 
359  if (n <= sz)
360  {
361  d->d_ino = 1;
362  d->d_off = 0;
363  memcpy(d->d_name, _current_cap_entry->name, l);
364  d->d_name[l - 1] = 0;
365  d->d_reclen = n;
366  if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
367  d->d_type = DT_DIR;
368  else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
369  d->d_type = DT_REG;
370  else
371  d->d_type = DT_UNKNOWN;
372  ret += n;
373  sz -= n;
374  d = (struct dirent64 *)((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 }}
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:408
#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
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
Unique_cap / Unique_del_cap.
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:60
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