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 
20 #include "ro_file.h"
21 
22 #include <sys/ioctl.h>
23 
24 #include <l4/re/env>
25 
26 namespace L4Re { namespace Core {
27 
~Ro_file()28 Ro_file::~Ro_file() throw()
29 {
30   if (_addr)
31     L4Re::Env::env()->rm()->detach(l4_addr_t(_addr), 0);
32 
33   L4Re::virt_cap_alloc->release(_ds);
34 }
35 
36 int
fstat64(struct stat64 * buf)37 Ro_file::fstat64(struct stat64 *buf) const throw()
38 {
39   static int fake = 0;
40 
41   memset(buf, 0, sizeof(*buf));
42   buf->st_size = _size;
43   buf->st_mode = S_IFREG | 0644;
44   buf->st_dev = _ds.cap();
45   buf->st_ino = ++fake;
46   buf->st_blksize = L4_PAGESIZE;
47   buf->st_blocks = l4_round_page(_size);
48   return 0;
49 }
50 
51 ssize_t
read_single(const struct iovec * vec,off64_t pos)52 Ro_file::read_single(const struct iovec *vec, off64_t pos) throw()
53 {
54   off64_t l = vec->iov_len;
55   if (_size - pos < l)
56     l = _size - pos;
57 
58   if (l > 0)
59     {
60       Vfs_config::memcpy(vec->iov_base, _addr + pos, l);
61       return l;
62     }
63 
64   return 0;
65 }
66 
67 ssize_t
preadv(const struct iovec * vec,int cnt,off64_t offset)68 Ro_file::preadv(const struct iovec *vec, int cnt, off64_t offset) throw()
69 {
70   if (!_addr)
71     {
72       void const *file = (void*)L4_PAGESIZE;
73       long err = L4Re::Env::env()->rm()->attach(&file, _size,
74                                                 Rm::F::Search_addr | Rm::F::R,
75                                                 _ds, 0);
76 
77       if (err < 0)
78 	return err;
79 
80       _addr = (char const *)file;
81     }
82 
83   ssize_t l = 0;
84 
85   while (cnt > 0)
86     {
87       ssize_t r = read_single(vec, offset);
88       offset += r;
89       l += r;
90 
91       if ((size_t)r < vec->iov_len)
92 	return l;
93 
94       ++vec;
95       --cnt;
96     }
97   return l;
98 }
99 
100 ssize_t
pwritev(const struct iovec *,int,off64_t)101 Ro_file::pwritev(const struct iovec *, int, off64_t) throw()
102 {
103   return -EROFS;
104 }
105 
106 int
ioctl(unsigned long v,va_list args)107 Ro_file::ioctl(unsigned long v, va_list args) throw()
108 {
109   switch (v)
110     {
111     case FIONREAD: // return amount of data still available
112       int *available = va_arg(args, int *);
113       *available = _size - pos();
114       return 0;
115     };
116   return -EINVAL;
117 }
118 
119 }}
120