]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/libc_backends/lib/l4re_file/file.cc
Update
[l4.git] / l4 / pkg / l4re-core / 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     {
338       errno = EBADF;
339       return -1;
340     }
341
342   f->unlock_all_locks();
343   return 0;
344 }
345
346 int access(const char *path, int mode) L4_NOTHROW
347 { return faccessat(AT_FDCWD, path, mode, 0); }
348
349 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes);
350 extern "C" ssize_t __getdents64(int fd, char *buf, size_t nbytes)
351 {
352   Ops *o = L4Re::Vfs::vfs_ops;
353   Ref_ptr<File> fdo = o->get_file(fd);
354   if (!fdo)
355     {
356       errno = EBADF;
357       return -1;
358     }
359
360   ssize_t r = fdo->getdents(buf, nbytes);
361   if (r < 0)
362     {
363       errno = -r;
364       return -1;
365     }
366
367   return r;
368 }
369
370 #if __WORDSIZE == 64
371 extern "C" ssize_t __getdents(int, char *, size_t);
372 L4_STRONG_ALIAS(__getdents64,__getdents)
373 #endif
374
375
376 #define L4B_REDIRECT(ret, func, ptlist, plist) \
377   extern "C" ret func ptlist L4_NOTHROW                                    \
378   {                                                             \
379     cxx::Ref_ptr<L4Re::Vfs::File> file;                   \
380     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
381     ERRNO_RET(res);                                             \
382     ret r = file->L4B_REDIRECT_FUNC(func)(L4B_STRIP_FIRST(plist));  \
383     POST();                                                     \
384   }
385
386 #define L4B_REDIRECT_FUNC(func) func
387 L4B_REDIRECT_3(ssize_t, readlink, const char *, char *, size_t)
388 L4B_REDIRECT_2(int,     utime,    const char *, const struct utimbuf *)
389 L4B_REDIRECT_2(int,     utimes,   const char *, const struct timeval *)
390 #undef L4B_REDIRECT_FUNC
391
392 #define L4B_REDIRECT_FUNC(func) f##func
393 L4B_REDIRECT_2(int,       stat64,      const char *, struct stat64 *)
394 L4B_REDIRECT_2(int,       chmod,       const char *, mode_t)
395 #undef L4B_REDIRECT_FUNC
396
397 #define L4B_REDIRECT_FUNC(func) fstat64
398 L4B_REDIRECT_2(int,       lstat64,     const char *, struct stat64 *)
399 #undef L4B_REDIRECT_FUNC
400 #undef L4B_REDIRECT
401
402 #define L4B_REDIRECT(ret, func, ptlist, plist) \
403   extern "C" ret func ptlist L4_NOTHROW                         \
404   {                                                             \
405     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
406     _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir);     \
407     ret r = dir->func plist;     \
408     POST();                                                     \
409   }
410
411 L4B_REDIRECT_1(int, unlink,  const char *)
412 L4B_REDIRECT_2(int, mkdir,   const char *, mode_t)
413 L4B_REDIRECT_1(int, rmdir,   const char *)
414 #undef L4B_REDIRECT
415
416 #define L4B_REDIRECT(ret, func, ptlist, plist) \
417   extern "C" ret func ptlist L4_NOTHROW                         \
418   {                                                             \
419     cxx::Ref_ptr<L4Re::Vfs::File> dir1;                         \
420     cxx::Ref_ptr<L4Re::Vfs::File> dir2;                         \
421     _a1 = __internal_resolvedir(AT_FDCWD, _a1, 0, 0, &dir1);    \
422     _a2 = __internal_resolvedir(AT_FDCWD, _a2, 0, 0, &dir2);    \
423     ret r = dir1->func plist;     \
424     POST();                                                     \
425   }
426
427 L4B_REDIRECT_2(int, rename,  const char *, const char *)
428 L4B_REDIRECT_2(int, link,    const char *, const char *)
429 L4B_REDIRECT_2(int, symlink, const char *, const char *)
430 #undef L4B_REDIRECT
431
432 #define L4B_REDIRECT(ret, func, ptlist, plist) \
433   extern "C" ret func ptlist L4_NOTHROW                         \
434   {                                                             \
435     cxx::Ref_ptr<L4Re::Vfs::File> file;                         \
436     int res = __internal_resolve(AT_FDCWD, _a1, 0, 0, &file);   \
437     ERRNO_RET(res);                                             \
438     ret r = file->ftruncate64(L4B_STRIP_FIRST(plist));  \
439     POST();                                                     \
440   }
441
442 L4B_REDIRECT_2(int, truncate, const char *, off_t)
443 L4B_REDIRECT_2(int, truncate64, const char *, off64_t)
444
445 #undef L4B_REDIRECT
446
447 #define L4B_REDIRECT(ret, func, ptlist, plist) \
448   extern "C" ret func ptlist L4_NOTHROW                         \
449   {                                                             \
450     cxx::Ref_ptr<L4Re::Vfs::File> dir;                          \
451     _a2 = __internal_resolvedir(_a1, _a2, 0, 0, &dir);          \
452     if (!_a2) \
453       { \
454         errno = EBADF; \
455         return -1; \
456       } \
457     ret r = dir->func(L4B_STRIP_FIRST(plist));                  \
458     POST();                                                     \
459   }
460
461 //L4B_REDIRECT_3(int, unlinkat,  int, const char *, int)
462 L4B_REDIRECT_4(int,       faccessat,   int, const char *, int, int)
463
464
465 // ------------------------------------------------------
466
467 //#include <stdio.h>
468 #include <l4/util/util.h>
469
470 int select(int nfds, fd_set *readfds, fd_set *writefds,
471            fd_set *exceptfds, struct timeval *timeout)
472 {
473   (void)nfds; (void)readfds; (void)writefds; (void)exceptfds;
474   //printf("Call: %s(%d, %p, %p, %p, %p[%ld])\n", __func__, nfds, readfds, writefds, exceptfds, timeout, timeout->tv_usec + timeout->tv_sec * 1000000);
475
476 #if 0
477   int us = timeout->tv_usec + timeout->tv_sec * 1000000;
478   l4_timeout_t to = l4_timeout(L4_IPC_TIMEOUT_NEVER,
479                                l4util_micros2l4to(us));
480 #endif
481
482   // only the timeout for now
483   if (timeout)
484     l4_usleep(timeout->tv_usec + timeout->tv_sec * 1000000);
485   else
486     l4_sleep_forever();
487
488   return 0;
489 }
490
491 #undef L4B_REDIRECT
492
493 #define L4B_REDIRECT(ret, func, ptlist, plist) \
494   ret func ptlist L4_NOTHROW \
495   {               \
496     L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops; \
497     cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(_a1); \
498     if (!f) \
499       { \
500         errno = EBADF; \
501         return -1; \
502       } \
503     ret r = f->func(L4B_STRIP_FIRST(plist)); \
504     POST(); \
505   }
506
507 __BEGIN_DECLS
508 ssize_t preadv(int, const struct iovec *, int, off_t);
509 ssize_t pwritev(int, const struct iovec *, int, off_t);
510 __END_DECLS
511
512 L4B_REDIRECT_2(int,       fstat64,     int, struct stat64 *)
513 L4B_REDIRECT_3(ssize_t,   readv,       int, const struct iovec *, int)
514 L4B_REDIRECT_3(ssize_t,   writev,      int, const struct iovec *, int)
515 L4B_REDIRECT_4(ssize_t,   preadv,      int, const struct iovec *, int, off_t)
516 L4B_REDIRECT_4(ssize_t,   pwritev,     int, const struct iovec *, int, off_t)
517 L4B_REDIRECT_3(__off64_t, lseek64,     int, __off64_t, int)
518 L4B_REDIRECT_2(int,       ftruncate64, int, off64_t)
519 L4B_REDIRECT_1(int,       fsync,       int)
520 L4B_REDIRECT_1(int,       fdatasync,   int)
521 L4B_REDIRECT_2(int,       fchmod,      int, mode_t)
522
523 static char const * const _default_current_working_dir = "/";
524 static char *_current_working_dir = const_cast<char *>(_default_current_working_dir);
525
526 static void free_cwd()
527 {
528   if (_current_working_dir != _default_current_working_dir)
529     free(_current_working_dir);
530 }
531
532 extern "C" int chdir(const char *path) L4_NOTHROW
533 {
534   Ref_ptr<File> f;
535   int res = __internal_resolve(AT_FDCWD, path, 0, 0, &f);
536   ERRNO_RET(res);
537
538   if (*path == '/')
539     {
540       free_cwd();
541       _current_working_dir = strdup(path);
542     }
543   else
544     {
545       unsigned len_cwd = strlen(_current_working_dir);
546       unsigned len_path = strlen(path);
547       char *tmp = (char *)malloc(len_cwd + len_path + 2);
548       memcpy(tmp, _current_working_dir, len_cwd);
549       if (tmp[len_cwd - 1] != '/')
550         tmp[len_cwd++] = '/';
551       memcpy(tmp + len_cwd, path, len_path + 1);
552
553       free_cwd();
554       _current_working_dir = tmp;
555     }
556
557   // would need to check whether 'f' is a directory
558   L4Re::Vfs::vfs_ops->set_cwd(f);
559
560   return 0;
561 }
562
563 extern "C" int fchdir(int fd) L4_NOTHROW
564 {
565   L4Re::Vfs::Ops *o = L4Re::Vfs::vfs_ops;
566   cxx::Ref_ptr<L4Re::Vfs::File> f = o->get_file(fd);
567   if (!f)
568     {
569       errno = EBADF;
570       return -1;
571     }
572
573   // would need to check whether 'f' is a directory
574   o->set_cwd(f);
575   return -1;
576 }
577
578 extern "C"
579 ssize_t pread64(int fd, void *buf, size_t count, off64_t offset)
580 {
581   struct iovec iov;
582   iov.iov_base = buf;
583   iov.iov_len = count;
584   return preadv(fd, &iov, 1, offset);
585 }
586
587 extern "C"
588 ssize_t pread(int fd, void *buf, size_t count, off_t offset)
589 {
590   return pread64(fd, buf, count, offset);
591 }
592
593 extern "C"
594 ssize_t pwrite64(int fd, const void *buf, size_t count, off64_t offset)
595 {
596   struct iovec iov;
597   iov.iov_base = const_cast<void*>(buf);
598   iov.iov_len = count;
599   return pwritev(fd, &iov, 1, offset);
600 }
601
602 extern "C"
603 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
604 {
605   return pwrite64(fd, buf, count, offset);
606 }
607
608 extern "C" char *getcwd(char *buf, size_t size) L4_NOTHROW
609 {
610   unsigned len_cwd = strlen(_current_working_dir) + 1;
611
612   if (buf == 0 && size == 0)
613     size = len_cwd;
614
615   if (buf == 0)
616     buf = (char *)malloc(size);
617
618   if (buf == 0)
619     {
620       errno = ENOMEM;
621       return 0;
622     }
623
624   if (len_cwd > size)
625     {
626       errno = ERANGE;
627       return 0;
628     }
629
630   memcpy(buf, _current_working_dir, len_cwd);
631   return buf;
632 }
633
634 extern "C" int chroot(const char *) L4_NOTHROW
635 {
636   errno = EINVAL;
637   return -1;
638 }
639
640 extern "C" int mkfifo(const char *, mode_t) L4_NOTHROW
641 {
642   errno = EINVAL;
643   return -1;
644 }
645
646 extern "C" int mknod(const char *, mode_t, dev_t) L4_NOTHROW
647 {
648   errno = EINVAL;
649   return -1;
650 }
651
652 int chown(const char *, __uid_t, __gid_t)
653 {
654   errno = EINVAL;
655   return -1;
656 }
657
658 int fchown(int, __uid_t, __gid_t)
659 {
660   errno = EINVAL;
661   return -1;
662 }
663
664
665 extern "C" int lchown(const char *, uid_t, gid_t) L4_NOTHROW
666 {
667   errno = EINVAL;
668   return -1;
669 }