]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/lxfuxlibc/lib/libc_be/ux.cc
update
[l4.git] / l4 / pkg / lxfuxlibc / lib / libc_be / ux.cc
1 /*!
2  * \file   ux.c
3  * \brief  open/read/seek/close for UX
4  *
5  * \date   2008-02-27
6  * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
7  *
8  */
9 /*
10  * (c) 2008-2009 Author(s)
11  *     economic rights: Technische Universität Dresden (Germany)
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU Lesser General Public License 2.1.
14  * Please see the COPYING-LGPL-2.1 file for details.
15  */
16
17 #include <l4/lxfuxlibc/lxfuxlc.h>
18 #include <l4/l4re_vfs/backend>
19 #include <l4/util/util.h>
20
21 #include <cstdlib>
22 #include <cstring>
23 #include <cassert>
24
25 //#include <cstdio> // for debug printf
26
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <dirent.h>
30
31 #include <l4/sys/thread.h>
32 #include <l4/re/env.h>
33 namespace {
34
35 using namespace L4Re::Vfs;
36 using cxx::Ref_ptr;
37
38 class Ux_dir : public Be_file
39 {
40 public:
41   explicit Ux_dir(int fd = -1) throw() : Be_file(), _fd(fd) {}
42   int get_entry(const char *, int, mode_t, Ref_ptr<File> *) throw();
43   int fstat64(struct stat64 *buf) const throw();
44   int mkdir(const char *, mode_t) throw();
45   int unlink(const char *) throw();
46   int rename(const char *, const char *) throw();
47   int faccessat(const char *path, int mode, int flags) throw();
48   ssize_t getdents(char *buf, size_t nbytes) throw();
49   ~Ux_dir() throw() { if (_fd >= 0) lx_close(_fd); }
50
51 private:
52   int _fd;
53 };
54
55
56 class Ux_file : public Be_file
57 {
58 public:
59   explicit Ux_file(int fd = -1) throw() : Be_file(), _fd(fd) {}
60
61   ssize_t readv(const struct iovec*, int iovcnt) throw();
62   ssize_t writev(const struct iovec*, int iovcnt) throw();
63   ssize_t preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw();
64   ssize_t pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw();
65
66   off64_t lseek64(off64_t, int) throw();
67   int fstat64(struct stat64 *buf) const throw();
68
69   //int fcntl64(int cmd, unsigned long arg);
70   //int ioctl(unsigned long request, void *argp);
71   //int close();
72
73   ~Ux_file() throw() { if (_fd >= 0) lx_close(_fd); }
74
75   //void fd(int f) { _fd = f; }
76
77 private:
78   int _fd;
79 };
80
81
82 int
83 Ux_dir::get_entry(const char *name, int flags, mode_t mode,
84                   Ref_ptr<File> *file) throw()
85 {
86   //printf("get_entry: '%s'\n", name);
87   if (!*name)
88     name = ".";
89   l4_touch_ro(name, strlen(name));
90   int fd = lx_openat(_fd, name, flags, mode);
91   if (fd < 0)
92     return fd;
93
94   struct stat64 sb;
95
96   int res = lx_fstat64(fd, (struct lx_stat64 *)&sb);
97   if (res < 0)
98     return res;
99
100   if (S_ISDIR(sb.st_mode))
101     {
102       //printf("open '%s' as directory\n", name);
103       *file = new Ux_dir(fd);
104     }
105   else
106     {
107       //printf("open '%s' as file\n", name);
108       *file = new Ux_file(fd);
109     }
110
111   if (!*file)
112     return -ENOMEM;
113
114   return 0;
115 }
116
117 int
118 Ux_dir::fstat64(struct stat64 *buf) const throw()
119 {
120   return lx_fstat64(_fd, (struct lx_stat64*)buf);
121 }
122
123 int
124 Ux_dir::faccessat(const char *path, int mode, int flags) throw()
125 {
126   (void)flags;
127   if (*path == 0)
128     path = ".";
129   l4_touch_ro(path, strlen(path));
130   return lx_faccessat(_fd, path, mode);
131 }
132
133 int
134 Ux_dir::mkdir(const char *name, mode_t mode) throw()
135 {
136   l4_touch_ro(name, strlen(name));
137   return lx_mkdirat(_fd, name, mode);
138 }
139
140 int
141 Ux_dir::unlink(const char *name) throw()
142 {
143   l4_touch_ro(name, strlen(name));
144   return lx_unlinkat(_fd, name, 0);
145 }
146
147 int
148 Ux_dir::rename(const char *old, const char *newn) throw()
149 {
150   l4_touch_ro(old, strlen(old));
151   l4_touch_ro(newn, strlen(newn));
152   return lx_renameat(_fd, old, _fd, newn);
153 }
154
155 ssize_t
156 Ux_dir::getdents(char *buf, size_t nbytes) throw()
157 {
158 #define kernel_dirent64 lx_linux_dirent64
159 #define     MIN(a,b) (((a)<(b))?(a):(b))
160   // taken from uclibc/ARCH-all/libc/sysdeps/linux/common/getdents64.c
161     struct dirent64 *dp;
162     off64_t last_offset = -1;
163     ssize_t retval;
164     size_t red_nbytes;
165     struct kernel_dirent64 *skdp, *kdp;
166     const size_t size_diff = (offsetof (struct dirent64, d_name)
167             - offsetof (struct kernel_dirent64, d_name));
168
169     red_nbytes = MIN (nbytes - ((nbytes /
170                     (offsetof (struct dirent64, d_name) + 14)) * size_diff),
171             nbytes - size_diff);
172
173     dp = (struct dirent64 *) buf;
174     skdp = kdp = (lx_linux_dirent64*)alloca (red_nbytes);
175
176     l4_touch_rw(kdp, red_nbytes);
177
178     retval = lx_getdents64(_fd, (char *)kdp, red_nbytes);
179     if (retval < 0)
180         return retval;
181
182     while ((char *) kdp < (char *) skdp + retval) {
183         const size_t alignment = __alignof__ (struct dirent64);
184         /* Since kdp->d_reclen is already aligned for the kernel structure
185            this may compute a value that is bigger than necessary.  */
186         size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1)
187                 & ~(alignment - 1));
188         if ((char *) dp + new_reclen > buf + nbytes) {
189             /* Our heuristic failed.  We read too many entries.  Reset
190                the stream.  */
191             assert (last_offset != -1);
192
193             //lx_lseek64(_fd, last_offset, SEEK_SET);
194             lx_lseek(_fd, last_offset, SEEK_SET);
195
196             if ((char *) dp == buf) {
197                 /* The buffer the user passed in is too small to hold even
198                    one entry.  */
199                 __set_errno (EINVAL);
200                 return -1;
201             }
202             break;
203         }
204
205         last_offset = kdp->d_off;
206         dp->d_ino = kdp->d_ino;
207         dp->d_off = kdp->d_off;
208         dp->d_reclen = new_reclen;
209         dp->d_type = kdp->d_type;
210         memcpy (dp->d_name, kdp->d_name,
211                 kdp->d_reclen - offsetof (struct kernel_dirent64, d_name));
212         dp = (struct dirent64 *) ((char *) dp + new_reclen);
213         kdp = (struct kernel_dirent64 *) (((char *) kdp) + kdp->d_reclen);
214     }
215     return (char *) dp - buf;
216 #undef MIN
217 #undef kernel_dirent64
218 }
219
220 /* Files */
221
222 ssize_t
223 Ux_file::readv(const struct iovec *iov, int cnt) throw()
224 {
225   for (int i = 0; i < cnt; ++i)
226     l4_touch_rw(iov[i].iov_base, iov[i].iov_len);
227
228   return lx_readv(_fd, (struct lx_iovec*)iov, cnt);
229 }
230
231 ssize_t
232 Ux_file::writev(const struct iovec *iov, int cnt) throw()
233 {
234   for (int i = 0; i < cnt; ++i)
235     l4_touch_ro(iov[i].iov_base, iov[i].iov_len);
236
237   return lx_writev(_fd, (struct lx_iovec*)iov, cnt);
238 }
239
240 ssize_t
241 Ux_file::preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw()
242 {
243   for (int i = 0; i < iovcnt; ++i)
244     l4_touch_rw(iov[i].iov_base, iov[i].iov_len);
245
246   return lx_preadv(_fd, (struct lx_iovec*)iov, iovcnt, offset, offset << 32);
247 }
248
249 ssize_t
250 Ux_file::pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw()
251 {
252   for (int i = 0; i < iovcnt; ++i)
253     l4_touch_ro(iov[i].iov_base, iov[i].iov_len);
254
255   return lx_pwritev(_fd, (struct lx_iovec*)iov, iovcnt, offset, offset << 32);
256 }
257
258 off64_t
259 Ux_file::lseek64(off64_t offset, int whence) L4_NOTHROW
260 {
261   //printf("lseek: fd=%d offset=%lld\n", _fd, offset);
262   return lx_lseek(_fd, offset, whence);
263 }
264
265 #if 0
266 int
267 ux_file_ops::fcntl64(int cmd, unsigned long arg)
268 {
269   return lx_fcntl64(_fd, cmd, arg);
270 }
271 #endif
272
273 int
274 Ux_file::fstat64(struct stat64 *buf) const throw()
275 {
276   l4_touch_rw(buf, sizeof(*buf));
277   return lx_fstat64(_fd, (struct lx_stat64 *)buf);
278 }
279
280 #if 0
281 int
282 ux_file_ops::ioctl(unsigned long cmd, void *argp)
283 {
284   return lx_ioctl(_fd, cmd, (unsigned long)argp);
285 }
286 #endif
287
288 class Ux_fs : public Be_file_system
289 {
290 public:
291   Ux_fs() : Be_file_system("fuxfs")
292   {
293     l4_thread_control_start();
294     l4_thread_control_ux_host_syscall(1);
295     l4_thread_control_commit(l4re_env()->main_thread);
296   }
297
298   int mount(char const *source, unsigned long mountflags,
299             void const *data, cxx::Ref_ptr<File> *dir) throw()
300   {
301     (void)mountflags;
302     (void)data;
303
304     l4_touch_ro(source, strlen(source));
305     int fd = lx_open(source, O_DIRECTORY, 0);
306     if (fd < 0)
307       return fd;
308
309     *dir = new Ux_dir(fd);
310     if (!*dir)
311       return -ENOMEM;
312     return 0;
313   }
314 };
315
316 static Ux_fs _ux_fs L4RE_VFS_FILE_SYSTEM_ATTRIBUTE;
317
318 }