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