]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libc_backends/lib/l4re_file/file.cc
update
[l4.git] / l4 / pkg / libc_backends / lib / l4re_file / file.cc
1 /*
2  * (c) 2008-2009 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  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU Lesser General Public License 2.1.
7  * Please see the COPYING-LGPL-2.1 file for details.
8  */
9
10
11 #include <features.h>
12
13 #ifndef  __USE_ATFILE
14 # define __USE_ATFILE 1
15 #endif
16
17 #include <l4/util/atomic.h>
18 #include <l4/re/log>
19 #include <l4/re/env>
20
21 #include <stdarg.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <sys/uio.h>
30 #include <l4/l4re_vfs/backend>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include "redirect.h"
35
36 using namespace L4Re::Vfs;
37 using cxx::Ref_ptr;
38
39 ssize_t read(int fd, void *buf, size_t count)
40 {
41   struct iovec iov;
42   iov.iov_base = buf;
43   iov.iov_len = count;
44   return readv(fd, &iov, 1);
45 }
46
47 ssize_t write(int fd, const void *buf, size_t count)
48 {
49   struct iovec iov;
50   iov.iov_base = const_cast<void*>(buf);
51   iov.iov_len = count;
52   return writev(fd, &iov, 1);
53 }
54
55
56 static void copy_stat64_to_stat(struct stat *buf, struct stat64 *sb64)
57 {
58   memset(buf, 0, sizeof(*buf));
59
60   buf->st_dev = sb64->st_dev;
61   buf->st_ino = sb64->st_ino;
62   buf->st_mode = sb64->st_mode;
63   buf->st_nlink = sb64->st_nlink;
64   buf->st_uid = sb64->st_uid;
65   buf->st_gid = sb64->st_gid;
66   buf->st_rdev = sb64->st_rdev;
67   buf->st_size = sb64->st_size;
68   buf->st_blksize = sb64->st_blksize;
69   buf->st_blocks = sb64->st_blocks;
70   buf->st_atime = sb64->st_atime;
71   buf->st_mtime = sb64->st_mtime;
72   buf->st_ctime = sb64->st_ctime;
73 }
74
75 int fstat(int fd, struct stat *buf) L4_NOTHROW
76 {
77   struct stat64 sb64;
78   int r = fstat64(fd, &sb64);
79   if (r < 0)
80     return r;
81
82   copy_stat64_to_stat(buf, &sb64);
83   return r;
84 }
85
86 #define ERRNO_RET(r) do { \
87   if ((r) < 0) \
88     {          \
89       errno = -(r); \
90       return -1; \
91     } } while (0)
92
93
94 namespace {
95
96 static Ref_ptr<File> __internal_get_dir(int dirfd, char const **path) L4_NOTHROW
97 {
98   Ops *vfs_ops = L4Re::Vfs::vfs_ops;
99   if (**path == '/')
100     {
101       while (**path == '/')
102         ++*path;
103
104       return vfs_ops->get_root();
105     }
106   else if (dirfd == AT_FDCWD)
107     return vfs_ops->get_cwd();
108   else
109     return vfs_ops->get_file(dirfd);
110 }
111
112 static char const *
113 __internal_resolvedir(int dirfd, const char *path, int flags, mode_t mode,
114                       Ref_ptr<File> *f) L4_NOTHROW
115 {
116   (void)flags;
117   (void)mode;
118   Ref_ptr<File> dir = __internal_get_dir(dirfd, &path);
119   if (!dir)
120     return 0;
121
122   return dir->get_mount(path, f);
123 }
124
125 static int
126 __internal_resolve(int dirfd, const char *path, int flags, mode_t mode,
127                    Ref_ptr<File> *f) L4_NOTHROW
128 {
129   Ref_ptr<File> dir = __internal_get_dir(dirfd, &path);
130   if (!dir)
131     return -EBADF;
132
133   return dir->openat(path, flags, mode, f);
134 }
135
136 static int
137 __internal_open(const char *path, int flags, mode_t mode) L4_NOTHROW
138 {
139   Ref_ptr<File> f;
140   int res = __internal_resolve(AT_FDCWD, path, flags, mode, &f);
141
142   ERRNO_RET(res);
143
144   int fd = L4Re::Vfs::vfs_ops->alloc_fd(f);
145
146   ERRNO_RET(fd);
147   return fd;
148 }
149 }
150
151 int open(const char *name, int flags, ...)
152 {
153   mode_t mode = 0;
154
155   if (flags & O_CREAT)
156     {
157       va_list v;
158       va_start(v, flags);
159       mode = va_arg(v, mode_t);
160       va_end(v);
161     }
162
163   return __internal_open(name, flags, mode);
164
165 }
166
167 int open64(const char *name, int flags, ...)
168 {
169   mode_t mode = 0;
170
171   if (flags & O_CREAT)
172     {
173       va_list v;
174       va_start(v, flags);
175       mode = va_arg(v, mode_t);
176       va_end(v);
177     }
178
179   return __internal_open(name, flags, mode);
180 }
181
182 extern "C" int ioctl(int fd, unsigned long request, ...) L4_NOTHROW
183 {
184   va_list v;
185   va_start(v, request);
186
187   L4B_FD;
188
189   int r = file->ioctl(request, v);
190   va_end(v);
191   POST();
192 }
193
194 extern "C" int fcntl64(int fd, int cmd, ...)
195 {
196   switch (cmd)
197     {
198     case F_DUPFD:
199     case F_DUPFD_CLOEXEC:
200       // 'arg' has the lowest fd ... so dup isn't the correct thing
201       return dup(fd);
202
203     case F_GETFD:
204       return 0;
205     case F_SETFD:
206       return 0;
207
208     case F_GETFL:
209       return 0;
210     case F_SETFL:
211       return 0;
212
213     case F_GETLK:
214     case F_SETLK:
215     case F_SETLKW:
216       errno = EINVAL;
217       return -1;
218
219     case F_GETOWN:
220       return 0;
221     case F_SETOWN:
222       errno = EINVAL;
223       return -1;
224
225     case F_GETSIG:
226       return 0;
227     case F_SETSIG:
228       errno = EINVAL;
229       return -1;
230
231     default:
232       errno = EINVAL;
233       return -1;
234     }
235 }
236
237 extern "C" int fcntl(int fd, int cmd, ...)
238 {
239   unsigned long arg;
240   va_list v;
241
242   va_start(v, cmd);
243   arg = va_arg(v, unsigned long);
244   va_end(v);
245
246   return fcntl64(fd, cmd, arg);
247 }
248
249
250 off_t lseek(int fd, off_t offset, int whence) L4_NOTHROW
251 {
252   return lseek64(fd, offset, whence);
253 }
254
255 int ftruncate(int fd, off_t length) L4_NOTHROW
256 {
257   return ftruncate64(fd, length);
258 }
259
260 int lockf(int fd, int cmd, off_t len)
261 {
262   (void)fd;
263   (void)cmd;
264   (void)len;
265   errno = EINVAL;
266   return -1;
267 }
268
269
270
271 extern "C" int dup2(int oldfd, int newfd) L4_NOTHROW
272 {
273   Ops *o = L4Re::Vfs::vfs_ops;
274   Ref_ptr<File> oldf = o->get_file(oldfd);
275   if (!oldf)
276     {
277       errno = EBADF;
278       return -1;
279     }
280
281   Ref_ptr<File> newf = o->set_fd(newfd, oldf);
282   if (!newf || newf == oldf)
283     return newfd;
284
285   // do the stuff for close;
286   newf->unlock_all_locks();
287
288   return newfd;
289 }
290
291 extern "C" int dup(int oldfd) L4_NOTHROW
292 {
293   Ops *o = L4Re::Vfs::vfs_ops;
294   Ref_ptr<File> f = o->get_file(oldfd);
295   if (!f)
296     {
297       errno = EBADF;
298       return -1;
299     }
300
301   int r = o->alloc_fd(f);
302   ERRNO_RET(r);
303   return r;
304 }
305
306
307 int stat(const char *path, struct stat *buf) L4_NOTHROW
308 {
309   struct stat64 sb64;
310   int r = stat64(path, &sb64);
311   if (r < 0)
312     return r;
313
314   copy_stat64_to_stat(buf, &sb64);
315   return r;
316 }
317
318 int lstat(const char *path, struct stat *buf) L4_NOTHROW
319 {
320   struct stat64 sb64;
321   int r = lstat64(path, &sb64);
322
323   if (r < 0)
324     return r;
325
326   copy_stat64_to_stat(buf, &sb64);
327   return r;
328 }
329
330 int close(int fd) L4_NOTHROW
331 {
332   Ops *o = L4Re::Vfs::vfs_ops;
333   Ref_ptr<File> f = o->free_fd(fd);
334   if (!f)
335     return -EBADF;
336
337   f->unlock_all_locks();
338   return 0;
339 }
340
341 int access(const char *path, int mode) L4_NOTHROW
342 { return faccessat(AT_FDCWD, path, mode, 0); }
343
344 extern "C" ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
345 {
346   Ops *o = L4Re::Vfs::vfs_ops;
347   Ref_ptr<File> fdo = o->get_file(fd);
348   if (!fdo)
349     {
350       errno = EBADF;
351       return -1;
352     }
353
354   ssize_t r = fdo->getdents(buf, nbytes);
355   if (r < 0)
356     {
357       errno = -r;
358       return -1;
359     }
360
361   return r;
362 }
363
364 #if __WORDSIZE == 64
365 extern "C" ssize_t __getdents(int, char *, size_t);
366 L4_STRONG_ALIAS(__getdents64,__getdents)
367 #endif
368
369
370 #define L4B_REDIRECT(ret, func, ptlist, plist) \
371   extern "C" ret func ptlist L4_NOTHROW                                    \
372   {                                                             \
373     cxx::Ref_ptr<L4Re::Vfs::File> file;                   \
374     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
375     ERRNO_RET(res);                                             \
376     ret r = file->L4B_REDIRECT_FUNC(func)(L4B_STRIP_FIRST(plist));  \
377     POST();                                                     \
378   }
379
380 #define L4B_REDIRECT_FUNC(func) func
381 L4B_REDIRECT_3(ssize_t, readlink, const char *, char *, size_t)
382 L4B_REDIRECT_2(int,     utime,    const char *, const struct utimbuf *)
383 L4B_REDIRECT_2(int,     utimes,   const char *, const struct utimbuf *)
384 #undef L4B_REDIRECT_FUNC
385
386 #define L4B_REDIRECT_FUNC(func) f##func
387 L4B_REDIRECT_2(int,       stat64,      const char *, struct stat64 *)
388 L4B_REDIRECT_2(int,       chmod,       const char *, mode_t)
389 #undef L4B_REDIRECT_FUNC
390
391 #define L4B_REDIRECT_FUNC(func) fstat64
392 L4B_REDIRECT_2(int,       lstat64,     const char *, struct stat64 *)
393 #undef L4B_REDIRECT_FUNC
394 #undef L4B_REDIRECT
395
396 #define L4B_REDIRECT(ret, func, ptlist, plist) \
397   extern "C" ret func ptlist L4_NOTHROW                         \
398   {                                                             \
399     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
400     _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir);     \
401     ret r = dir->func plist;     \
402     POST();                                                     \
403   }
404
405 L4B_REDIRECT_1(int, unlink,  const char *)
406 L4B_REDIRECT_2(int, rename,  const char *, const char *)
407 L4B_REDIRECT_2(int, mkdir,   const char *, mode_t)
408 L4B_REDIRECT_1(int, rmdir,   const char *)
409 L4B_REDIRECT_2(int, link,    const char *, const char *)
410 L4B_REDIRECT_2(int, symlink, const char *, const char *)
411 #undef L4B_REDIRECT
412
413 #define L4B_REDIRECT(ret, func, ptlist, plist) \
414   extern "C" ret func ptlist L4_NOTHROW                         \
415   {                                                             \
416     cxx::Ref_ptr<L4Re::Vfs::File> file;                         \
417     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
418     ERRNO_RET(res);                                             \
419     ret r = file->ftruncate64(L4B_STRIP_FIRST(plist));  \
420     POST();                                                     \
421   }
422
423 L4B_REDIRECT_2(int, truncate, const char *, off_t)
424 L4B_REDIRECT_2(int, truncate64, const char *, off64_t)
425
426 #undef L4B_REDIRECT
427
428 #define L4B_REDIRECT(ret, func, ptlist, plist) \
429   extern "C" ret func ptlist L4_NOTHROW                         \
430   {                                                             \
431     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
432     _a2 = __internal_resolvedir(_a1, _a2, 0, 0, &dir);          \
433     if (!_a2) \
434       { \
435         errno = EBADF; \
436         return -1; \
437       } \
438     ret r = dir->func(L4B_STRIP_FIRST(plist));                  \
439     POST();                                                     \
440   }
441
442 //L4B_REDIRECT_3(int, unlinkat,  int, const char *, int)
443 L4B_REDIRECT_4(int,       faccessat,   int, const char *, int, int)
444
445
446 // ------------------------------------------------------
447
448 //#include <stdio.h>
449 #include <l4/util/util.h>
450
451 int select(int nfds, fd_set *readfds, fd_set *writefds,
452            fd_set *exceptfds, struct timeval *timeout)
453 {
454   (void)nfds; (void)readfds; (void)writefds; (void)exceptfds;
455   //printf("Call: %s(%d, %p, %p, %p, %p[%ld])\n", __func__, nfds, readfds, writefds, exceptfds, timeout, timeout->tv_usec + timeout->tv_sec * 1000000);
456
457   int us = timeout->tv_usec + timeout->tv_sec * 1000000;
458   l4_timeout_t to = l4_timeout(L4_IPC_TIMEOUT_NEVER,
459                                l4util_micros2l4to(us));
460
461   // only the timeout for now
462   if (timeout)
463     l4_usleep(timeout->tv_usec + timeout->tv_sec * 1000000);
464   else
465     l4_sleep_forever();
466
467   return 0;
468 }
469
470 #undef L4B_REDIRECT
471
472 #define L4B_REDIRECT(ret, func, ptlist, plist) \
473   ret func ptlist L4_NOTHROW \
474   {               \
475     L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops; \
476     cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(_a1); \
477     if (!f) \
478       { \
479         errno = EBADF; \
480         return -1; \
481       } \
482     ret r = f->func(L4B_STRIP_FIRST(plist)); \
483     POST(); \
484   }
485
486
487 L4B_REDIRECT_2(int,       fstat64,     int, struct stat64 *)
488 L4B_REDIRECT_3(ssize_t,   readv,       int, const struct iovec *, int)
489 L4B_REDIRECT_3(ssize_t,   writev,      int, const struct iovec *, int)
490 L4B_REDIRECT_3(__off64_t, lseek64,     int, __off64_t, int)
491 L4B_REDIRECT_2(int,       ftruncate64, int, off64_t)
492 L4B_REDIRECT_1(int,       fsync,       int)
493 L4B_REDIRECT_1(int,       fdatasync,   int)
494 L4B_REDIRECT_2(int,       fchmod,      int, mode_t)
495
496 static char const * const _default_current_working_dir = "/";
497 static char *_current_working_dir = const_cast<char *>(_default_current_working_dir);
498
499 static void free_cwd()
500 {
501   if (_current_working_dir != _default_current_working_dir)
502     free(_current_working_dir);
503 }
504
505 extern "C" int chdir(const char *path) L4_NOTHROW
506 {
507   Ref_ptr<File> f;
508   int res = __internal_resolve(AT_FDCWD, path, 0, 0, &f);
509   ERRNO_RET(res);
510
511   if (*path == '/')
512     {
513       free_cwd();
514       _current_working_dir = strdup(path);
515     }
516   else
517     {
518       unsigned len_cwd = strlen(_current_working_dir);
519       unsigned len_path = strlen(path);
520       char *tmp = (char *)malloc(len_cwd + len_path + 2);
521       memcpy(tmp, _current_working_dir, len_cwd);
522       if (tmp[len_cwd - 1] != '/')
523         tmp[len_cwd++] = '/';
524       memcpy(tmp + len_cwd, path, len_path + 1);
525
526       free_cwd();
527       _current_working_dir = tmp;
528     }
529
530   // would need to check whether 'f' is a directory
531   L4Re::Vfs::vfs_ops->set_cwd(f);
532
533   return 0;
534 }
535
536 extern "C" int fchdir(int fd) L4_NOTHROW
537 {
538   L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops;
539   cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(fd);
540   if (!f)
541     {
542       errno = EBADF;
543       return -1;
544     }
545
546   // would need to check whether 'f' is a directory
547   o->set_cwd(f);
548   return -1;
549 }
550
551 extern "C" char *getcwd(char *buf, size_t size) L4_NOTHROW
552 {
553   unsigned len_cwd = strlen(_current_working_dir) + 1;
554
555   if (buf == 0 && size == 0)
556     size = len_cwd;
557
558   if (buf == 0)
559     buf = (char *)malloc(size);
560
561   if (buf == 0)
562     {
563       errno = ENOMEM;
564       return 0;
565     }
566
567   if (len_cwd > size)
568     {
569       errno = ERANGE;
570       return 0;
571     }
572
573   memcpy(buf, _current_working_dir, len_cwd);
574   return buf;
575 }
576
577 extern "C" int chroot(const char *) L4_NOTHROW
578 {
579   errno = EINVAL;
580   return -1;
581 }
582
583 extern "C" int mkfifo(const char *, mode_t) L4_NOTHROW
584 {
585   errno = EINVAL;
586   return -1;
587 }
588
589 extern "C" int mknod(const char *, mode_t, dev_t) L4_NOTHROW
590 {
591   errno = EINVAL;
592   return -1;
593 }
594
595 extern "C" int lchown(const char *, uid_t, gid_t) L4_NOTHROW
596 {
597   errno = EINVAL;
598   return -1;
599 }