]> 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 <sys/time.h>
31 #include <l4/l4re_vfs/backend>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include "redirect.h"
36
37 using namespace L4Re::Vfs;
38 using cxx::Ref_ptr;
39
40 ssize_t read(int fd, void *buf, size_t count)
41 {
42   struct iovec iov;
43   iov.iov_base = buf;
44   iov.iov_len = count;
45   return readv(fd, &iov, 1);
46 }
47
48 ssize_t write(int fd, const void *buf, size_t count)
49 {
50   struct iovec iov;
51   iov.iov_base = const_cast<void*>(buf);
52   iov.iov_len = count;
53   return writev(fd, &iov, 1);
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   Ops *o = L4Re::Vfs::vfs_ops;
197   Ref_ptr<File> f = o->get_file(fd);
198   switch (cmd)
199     {
200     case F_DUPFD:
201     case F_DUPFD_CLOEXEC:
202       // 'arg' has the lowest fd ... so dup isn't the correct thing
203       return dup(fd);
204
205     case F_GETFD:
206       return 0;
207     case F_SETFD:
208       return 0;
209
210     case F_GETFL:
211       return f->get_status_flags();
212     case F_SETFL:
213       return 0;
214
215     case F_GETLK:
216     case F_SETLK:
217     case F_SETLKW:
218       errno = EINVAL;
219       return -1;
220
221     case F_GETOWN:
222       return 0;
223     case F_SETOWN:
224       errno = EINVAL;
225       return -1;
226
227     case F_GETSIG:
228       return 0;
229     case F_SETSIG:
230       errno = EINVAL;
231       return -1;
232
233     default:
234       errno = EINVAL;
235       return -1;
236     }
237 }
238
239 extern "C" int fcntl(int fd, int cmd, ...)
240 {
241   unsigned long arg;
242   va_list v;
243
244   va_start(v, cmd);
245   arg = va_arg(v, unsigned long);
246   va_end(v);
247
248   return fcntl64(fd, cmd, arg);
249 }
250
251
252 off_t lseek(int fd, off_t offset, int whence) L4_NOTHROW
253 {
254   return lseek64(fd, offset, whence);
255 }
256
257 int ftruncate(int fd, off_t length) L4_NOTHROW
258 {
259   return ftruncate64(fd, length);
260 }
261
262 int lockf(int fd, int cmd, off_t len)
263 {
264   (void)fd;
265   (void)cmd;
266   (void)len;
267   errno = EINVAL;
268   return -1;
269 }
270
271
272
273 extern "C" int dup2(int oldfd, int newfd) L4_NOTHROW
274 {
275   Ops *o = L4Re::Vfs::vfs_ops;
276   Ref_ptr<File> oldf = o->get_file(oldfd);
277   if (!oldf)
278     {
279       errno = EBADF;
280       return -1;
281     }
282
283   Ref_ptr<File> newf = o->set_fd(newfd, oldf);
284   if (!newf || newf == oldf)
285     return newfd;
286
287   // do the stuff for close;
288   newf->unlock_all_locks();
289
290   return newfd;
291 }
292
293 extern "C" int dup(int oldfd) L4_NOTHROW
294 {
295   Ops *o = L4Re::Vfs::vfs_ops;
296   Ref_ptr<File> f = o->get_file(oldfd);
297   if (!f)
298     {
299       errno = EBADF;
300       return -1;
301     }
302
303   int r = o->alloc_fd(f);
304   ERRNO_RET(r);
305   return r;
306 }
307
308
309 int stat(const char *path, struct stat *buf) L4_NOTHROW
310 {
311   struct stat64 sb64;
312   int r = stat64(path, &sb64);
313   if (r < 0)
314     return r;
315
316   copy_stat64_to_stat(buf, &sb64);
317   return r;
318 }
319
320 int lstat(const char *path, struct stat *buf) L4_NOTHROW
321 {
322   struct stat64 sb64;
323   int r = lstat64(path, &sb64);
324
325   if (r < 0)
326     return r;
327
328   copy_stat64_to_stat(buf, &sb64);
329   return r;
330 }
331
332 int close(int fd) L4_NOTHROW
333 {
334   Ops *o = L4Re::Vfs::vfs_ops;
335   Ref_ptr<File> f = o->free_fd(fd);
336   if (!f)
337     return -EBADF;
338
339   f->unlock_all_locks();
340   return 0;
341 }
342
343 int access(const char *path, int mode) L4_NOTHROW
344 { return faccessat(AT_FDCWD, path, mode, 0); }
345
346 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes);
347 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes)
348 {
349   Ops *o = L4Re::Vfs::vfs_ops;
350   Ref_ptr<File> fdo = o->get_file(fd);
351   if (!fdo)
352     {
353       errno = EBADF;
354       return -1;
355     }
356
357   ssize_t r = fdo->getdents(buf, nbytes);
358   if (r < 0)
359     {
360       errno = -r;
361       return -1;
362     }
363
364   return r;
365 }
366
367 #if __WORDSIZE == 64
368 extern "C" ssize_t __getdents(int, char *, size_t);
369 L4_STRONG_ALIAS(__getdents64,__getdents)
370 #endif
371
372
373 #define L4B_REDIRECT(ret, func, ptlist, plist) \
374   extern "C" ret func ptlist L4_NOTHROW                                    \
375   {                                                             \
376     cxx::Ref_ptr<L4Re::Vfs::File> file;                   \
377     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
378     ERRNO_RET(res);                                             \
379     ret r = file->L4B_REDIRECT_FUNC(func)(L4B_STRIP_FIRST(plist));  \
380     POST();                                                     \
381   }
382
383 #define L4B_REDIRECT_FUNC(func) func
384 L4B_REDIRECT_3(ssize_t, readlink, const char *, char *, size_t)
385 L4B_REDIRECT_2(int,     utime,    const char *, const struct utimbuf *)
386 L4B_REDIRECT_2(int,     utimes,   const char *, const struct timeval *)
387 #undef L4B_REDIRECT_FUNC
388
389 #define L4B_REDIRECT_FUNC(func) f##func
390 L4B_REDIRECT_2(int,       stat64,      const char *, struct stat64 *)
391 L4B_REDIRECT_2(int,       chmod,       const char *, mode_t)
392 #undef L4B_REDIRECT_FUNC
393
394 #define L4B_REDIRECT_FUNC(func) fstat64
395 L4B_REDIRECT_2(int,       lstat64,     const char *, struct stat64 *)
396 #undef L4B_REDIRECT_FUNC
397 #undef L4B_REDIRECT
398
399 #define L4B_REDIRECT(ret, func, ptlist, plist) \
400   extern "C" ret func ptlist L4_NOTHROW                         \
401   {                                                             \
402     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
403     _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir);     \
404     ret r = dir->func plist;     \
405     POST();                                                     \
406   }
407
408 L4B_REDIRECT_1(int, unlink,  const char *)
409 L4B_REDIRECT_2(int, mkdir,   const char *, mode_t)
410 L4B_REDIRECT_1(int, rmdir,   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> dir1;                         \
417     cxx::Ref_ptr<L4Re::Vfs::File> dir2;                         \
418     _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir1);    \
419     _a2 = __internal_resolvedir(AT_FDCWD, _a2, 0, 0, &dir2);    \
420     ret r = dir1->func plist;     \
421     POST();                                                     \
422   }
423
424 L4B_REDIRECT_2(int, rename,  const char *, const char *)
425 L4B_REDIRECT_2(int, link,    const char *, const char *)
426 L4B_REDIRECT_2(int, symlink, const char *, const char *)
427 #undef L4B_REDIRECT
428
429 #define L4B_REDIRECT(ret, func, ptlist, plist) \
430   extern "C" ret func ptlist L4_NOTHROW                         \
431   {                                                             \
432     cxx::Ref_ptr<L4Re::Vfs::File> file;                         \
433     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
434     ERRNO_RET(res);                                             \
435     ret r = file->ftruncate64(L4B_STRIP_FIRST(plist));  \
436     POST();                                                     \
437   }
438
439 L4B_REDIRECT_2(int, truncate, const char *, off_t)
440 L4B_REDIRECT_2(int, truncate64, const char *, off64_t)
441
442 #undef L4B_REDIRECT
443
444 #define L4B_REDIRECT(ret, func, ptlist, plist) \
445   extern "C" ret func ptlist L4_NOTHROW                         \
446   {                                                             \
447     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
448     _a2 = __internal_resolvedir(_a1, _a2, 0, 0, &dir);          \
449     if (!_a2) \
450       { \
451         errno = EBADF; \
452         return -1; \
453       } \
454     ret r = dir->func(L4B_STRIP_FIRST(plist));                  \
455     POST();                                                     \
456   }
457
458 //L4B_REDIRECT_3(int, unlinkat,  int, const char *, int)
459 L4B_REDIRECT_4(int,       faccessat,   int, const char *, int, int)
460
461
462 // ------------------------------------------------------
463
464 //#include <stdio.h>
465 #include <l4/util/util.h>
466
467 int select(int nfds, fd_set *readfds, fd_set *writefds,
468            fd_set *exceptfds, struct timeval *timeout)
469 {
470   (void)nfds; (void)readfds; (void)writefds; (void)exceptfds;
471   //printf("Call: %s(%d, %p, %p, %p, %p[%ld])\n", __func__, nfds, readfds, writefds, exceptfds, timeout, timeout->tv_usec + timeout->tv_sec * 1000000);
472
473 #if 0
474   int us = timeout->tv_usec + timeout->tv_sec * 1000000;
475   l4_timeout_t to = l4_timeout(L4_IPC_TIMEOUT_NEVER,
476                                l4util_micros2l4to(us));
477 #endif
478
479   // only the timeout for now
480   if (timeout)
481     l4_usleep(timeout->tv_usec + timeout->tv_sec * 1000000);
482   else
483     l4_sleep_forever();
484
485   return 0;
486 }
487
488 #undef L4B_REDIRECT
489
490 #define L4B_REDIRECT(ret, func, ptlist, plist) \
491   ret func ptlist L4_NOTHROW \
492   {               \
493     L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops; \
494     cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(_a1); \
495     if (!f) \
496       { \
497         errno = EBADF; \
498         return -1; \
499       } \
500     ret r = f->func(L4B_STRIP_FIRST(plist)); \
501     POST(); \
502   }
503
504 ssize_t preadv(int, const struct iovec *, int, off_t);
505 ssize_t pwritev(int, const struct iovec *, int, off_t);
506
507 L4B_REDIRECT_2(int,       fstat64,     int, struct stat64 *)
508 L4B_REDIRECT_3(ssize_t,   readv,       int, const struct iovec *, int)
509 L4B_REDIRECT_3(ssize_t,   writev,      int, const struct iovec *, int)
510 L4B_REDIRECT_4(ssize_t,   preadv,      int, const struct iovec *, int, off_t)
511 L4B_REDIRECT_4(ssize_t,   pwritev,     int, const struct iovec *, int, off_t)
512 L4B_REDIRECT_3(__off64_t, lseek64,     int, __off64_t, int)
513 L4B_REDIRECT_2(int,       ftruncate64, int, off64_t)
514 L4B_REDIRECT_1(int,       fsync,       int)
515 L4B_REDIRECT_1(int,       fdatasync,   int)
516 L4B_REDIRECT_2(int,       fchmod,      int, mode_t)
517
518 static char const * const _default_current_working_dir = "/";
519 static char *_current_working_dir = const_cast<char *>(_default_current_working_dir);
520
521 static void free_cwd()
522 {
523   if (_current_working_dir != _default_current_working_dir)
524     free(_current_working_dir);
525 }
526
527 extern "C" int chdir(const char *path) L4_NOTHROW
528 {
529   Ref_ptr<File> f;
530   int res = __internal_resolve(AT_FDCWD, path, 0, 0, &f);
531   ERRNO_RET(res);
532
533   if (*path == '/')
534     {
535       free_cwd();
536       _current_working_dir = strdup(path);
537     }
538   else
539     {
540       unsigned len_cwd = strlen(_current_working_dir);
541       unsigned len_path = strlen(path);
542       char *tmp = (char *)malloc(len_cwd + len_path + 2);
543       memcpy(tmp, _current_working_dir, len_cwd);
544       if (tmp[len_cwd - 1] != '/')
545         tmp[len_cwd++] = '/';
546       memcpy(tmp + len_cwd, path, len_path + 1);
547
548       free_cwd();
549       _current_working_dir = tmp;
550     }
551
552   // would need to check whether 'f' is a directory
553   L4Re::Vfs::vfs_ops->set_cwd(f);
554
555   return 0;
556 }
557
558 extern "C" int fchdir(int fd) L4_NOTHROW
559 {
560   L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops;
561   cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(fd);
562   if (!f)
563     {
564       errno = EBADF;
565       return -1;
566     }
567
568   // would need to check whether 'f' is a directory
569   o->set_cwd(f);
570   return -1;
571 }
572
573 extern "C"
574 ssize_t pread64(int fd, void *buf, size_t count, off64_t offset)
575 {
576   struct iovec iov;
577   iov.iov_base = buf;
578   iov.iov_len = count;
579   return preadv(fd, &iov, 1, offset);
580 }
581
582 extern "C"
583 ssize_t pwrite64(int fd, const void *buf, size_t count, off64_t offset)
584 {
585   struct iovec iov;
586   iov.iov_base = const_cast<void*>(buf);
587   iov.iov_len = count;
588   return pwritev(fd, &iov, 1, offset);
589 }
590
591 extern "C" char *getcwd(char *buf, size_t size) L4_NOTHROW
592 {
593   unsigned len_cwd = strlen(_current_working_dir) + 1;
594
595   if (buf == 0 && size == 0)
596     size = len_cwd;
597
598   if (buf == 0)
599     buf = (char *)malloc(size);
600
601   if (buf == 0)
602     {
603       errno = ENOMEM;
604       return 0;
605     }
606
607   if (len_cwd > size)
608     {
609       errno = ERANGE;
610       return 0;
611     }
612
613   memcpy(buf, _current_working_dir, len_cwd);
614   return buf;
615 }
616
617 extern "C" int chroot(const char *) L4_NOTHROW
618 {
619   errno = EINVAL;
620   return -1;
621 }
622
623 extern "C" int mkfifo(const char *, mode_t) L4_NOTHROW
624 {
625   errno = EINVAL;
626   return -1;
627 }
628
629 extern "C" int mknod(const char *, mode_t, dev_t) L4_NOTHROW
630 {
631   errno = EINVAL;
632   return -1;
633 }
634
635 int chown(const char *, __uid_t, __gid_t)
636 {
637   errno = EINVAL;
638   return -1;
639 }
640
641 int fchown(int, __uid_t, __gid_t)
642 {
643   errno = EINVAL;
644   return -1;
645 }
646
647
648 extern "C" int lchown(const char *, uid_t, gid_t) L4_NOTHROW
649 {
650   errno = EINVAL;
651   return -1;
652 }