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