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 {
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 
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,
158  Rm::F::Search_addr | Rm::F::R,
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  while (d && p < end)
167  {
168  // parse lines of dirinfofile
169  long len;
170  for (len = 0; p < end && *p >= '0' && *p <= '9'; ++p)
171  {
172  len *= 10;
173  len += *p - '0';
174  }
175  if (len)
176  {
177  // skip colon
178  p++;
179  if (p + len >= end)
180  return 0; // error in dirinfofile
181 
182  unsigned l = len + 1;
183  if (l > sizeof(d->d_name))
184  l = sizeof(d->d_name);
185 
186  unsigned n = offsetof (struct dirent64, d_name) + l;
187  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
188 
189  if (n > sz)
190  break;
191 
192  d->d_ino = 1;
193  d->d_off = 0;
194  memcpy(d->d_name, p, len);
195  d->d_name[l - 1] = 0;
196  d->d_reclen = n;
197  d->d_type = DT_REG;
198  ret += n;
199  sz -= n;
200  d = (struct dirent64 *)((unsigned long)d + n);
201  }
202 
203  // next infodirfile line
204  while (p < end && *p && *p != '\n' && *p != '\r')
205  p++;
206  while (p < end && *p && (*p == '\n' || *p == '\r'))
207  p++;
208  }
209 
210  _current_dir_pos += p - (char *)infoaddr;
211 
212  if (!ret) // hack since we should only reset this at open times
213  _current_dir_pos = 0;
214 
215  L4Re::Env::env()->rm()->detach(infoaddr, 0);
216 
217  return ret;
218 }
219 
220 int
221 Env_dir::get_ds(const char *path, L4Re::Unique_cap<L4Re::Dataspace> *ds) throw()
222 {
223  Vfs::Path p(path);
224  Vfs::Path first = p.strip_first();
225 
226  if (first.empty())
227  return -ENOENT;
228 
230  c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
231 
232  if (!c.is_valid())
233  return -ENOENT;
234 
235  if (p.empty())
236  {
237  *ds = L4Re::Unique_cap<L4Re::Dataspace>(L4::cap_reinterpret_cast<L4Re::Dataspace>(c));
238  return 0;
239  }
240 
241  auto file = L4Re::make_unique_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
242 
243  if (!file.is_valid())
244  return -ENOMEM;
245 
246  int err = c->query(p.path(), p.length(), file.get());
247 
248  if (err < 0)
249  return -ENOENT;
250 
251  *ds = cxx::move(file);
252  return err;
253 }
254 
255 int
256 Env_dir::get_entry(const char *path, int flags, mode_t mode,
257  Ref_ptr<L4Re::Vfs::File> *f) throw()
258 {
259  (void)mode; (void)flags;
260  if (!*path)
261  {
262  *f = cxx::ref_ptr(this);
263  return 0;
264  }
265 
267  int err = get_ds(path, &file);
268 
269  if (err < 0)
270  return -ENOENT;
271 
272  cxx::Ref_ptr<L4Re::Vfs::File> fi = cap_to_vfs_object(file.get(), &err);
273  if (!fi)
274  return err;
275 
276  file.release();
277  *f = cxx::move(fi);
278  return 0;
279 }
280 
281 int
282 Env_dir::faccessat(const char *path, int mode, int flags) throw()
283 {
284  (void)flags;
285  Vfs::Path p(path);
286  Vfs::Path first = p.strip_first();
287 
288  if (first.empty())
289  return -ENOENT;
290 
292  c = _env->get_cap<L4Re::Namespace>(first.path(), first.length());
293 
294  if (!c.is_valid())
295  return -ENOENT;
296 
297  if (p.empty())
298  {
299  if (mode & W_OK)
300  return -EACCES;
301 
302  return 0;
303  }
304 
305  auto tmpcap = L4Re::make_unique_cap<void>(L4Re::virt_cap_alloc);
306 
307  if (!tmpcap.is_valid())
308  return -ENOMEM;
309 
310  if (c->query(p.path(), p.length(), tmpcap.get()))
311  return -ENOENT;
312 
313  if (mode & W_OK)
314  return -EACCES;
315 
316  return 0;
317 }
318 
319 bool
320 Env_dir::check_type(Env::Cap_entry const *e, long protocol) throw()
321 {
322  L4::Cap<L4::Meta> m(e->cap);
323  return m->supports(protocol).label();
324 }
325 
326 int
327 Env_dir::fstat64(struct stat64 *b) const throw()
328 {
329  b->st_dev = 1;
330  b->st_ino = 1;
331  b->st_mode = S_IRWXU | S_IFDIR;
332  b->st_nlink = 0;
333  b->st_uid = 0;
334  b->st_gid = 0;
335  b->st_rdev = 0;
336  b->st_size = 0;
337  b->st_blksize = 0;
338  b->st_blocks = 0;
339  b->st_atime = 0;
340  b->st_mtime = 0;
341  b->st_ctime = 0;
342  return 0;
343 }
344 
345 ssize_t
346 Env_dir::getdents(char *buf, size_t sz) throw()
347 {
348  struct dirent64 *d = (struct dirent64 *)buf;
349  ssize_t ret = 0;
350 
351  while (d
352  && _current_cap_entry
353  && _current_cap_entry->flags != ~0UL)
354  {
355  unsigned l = strlen(_current_cap_entry->name) + 1;
356  if (l > sizeof(d->d_name))
357  l = sizeof(d->d_name);
358 
359  unsigned n = offsetof (struct dirent64, d_name) + l;
360  n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
361 
362  if (n <= sz)
363  {
364  d->d_ino = 1;
365  d->d_off = 0;
366  memcpy(d->d_name, _current_cap_entry->name, l);
367  d->d_name[l - 1] = 0;
368  d->d_reclen = n;
369  if (check_type(_current_cap_entry, L4Re::Namespace::Protocol))
370  d->d_type = DT_DIR;
371  else if (check_type(_current_cap_entry, L4Re::Dataspace::Protocol))
372  d->d_type = DT_REG;
373  else
374  d->d_type = DT_UNKNOWN;
375  ret += n;
376  sz -= n;
377  d = (struct dirent64 *)((unsigned long)d + n);
378  _current_cap_entry++;
379  }
380  else
381  return ret;
382  }
383 
384  // bit of a hack because we should only (re)set this when opening the dir
385  if (!ret)
386  _current_cap_entry = _env->initial_caps();
387 
388  return ret;
389 }
390 
391 }}
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
long query(char const *name, L4::Cap< void > const &cap, int timeout=To_default, l4_umword_t *local_id=0, bool iterate=true) const noexcept
Query the name space for a named object.
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:219
Dataspace interface.
unsigned long l4_addr_t
Address type.
Definition: l4int.h:45
long l4_error(l4_msgtag_t tag) L4_NOTHROW
Return error code of a system call return message tag or the tag label.
Definition: ipc.h:535
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition: consts.h:307
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
@ Search_addr
Search for a suitable address range.
Definition: rm:105
Unique_cap / Unique_del_cap.