Chromium Code Reviews| Index: native_client_sdk/src/libraries/nacl_io/kernel_wrap_dummy.cc |
| diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_dummy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_dummy.cc |
| index c4d0df8607039cbc471947fc99f975357a8372d9..dcba47a9b49e50096e9f40a76057338b230fff9a 100644 |
| --- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_dummy.cc |
| +++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_dummy.cc |
| @@ -8,8 +8,23 @@ |
| #include <errno.h> |
| +#ifdef __linux__ |
| +#include <dirent.h> |
| +#include <stddef.h> |
| +#include <string.h> |
| +#include <sys/syscall.h> |
| +#include <unistd.h> |
| +struct linux_dirent { |
| + unsigned long d_ino; /* Inode number */ |
| + unsigned long d_off; /* Offset to next linux_dirent */ |
| + unsigned short d_reclen; /* Length of this linux_dirent */ |
| + char d_name[]; /* Filename (null-terminated) */ |
| +}; |
| +#endif |
| + |
| #include "nacl_io/kernel_wrap.h" |
| #include "nacl_io/kernel_wrap_real.h" |
| +#include "nacl_io/log.h" |
| // "real" functions, i.e. the unwrapped original functions. For Windows/Linux |
| // host builds we don't wrap, so the real functions aren't accessible. In most |
| @@ -20,11 +35,49 @@ int _real_close(int fd) { |
| } |
| int _real_fstat(int fd, struct stat* buf) { |
| - return 0; |
| + return fstat(fd, buf); |
| } |
| -int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t* nread) { |
| +int _real_getdents(int fd, void* out_buf, size_t in_count, size_t* nread) { |
| +#ifdef __linux__ |
| +#define ROUND_UP(X, SIZE) ( (X + SIZE-1) & (~(SIZE-1)) ) |
|
binji
2015/01/09 21:11:45
parens around X and SIZE
|
| + |
| + int out_offset = 0; |
| + // 'out_buf' is to be filled with the native (glibc) 'dirent' whereas the |
| + // syscall reads 'linux_dirent' into 'buf'. |
| + // Since the linux_dirent is larger (by a single pad byte) we know that we |
| + // will not read too many of them. |
| + char* buf = (char*)alloca(in_count); |
| + int offset = 0; |
| + int count; |
| + |
| + count = syscall(SYS_getdents, fd, buf, in_count); |
| + if (count < 0) |
| + return errno; |
| + |
| + while (offset < count) { |
| + struct linux_dirent* d = (struct linux_dirent*)(buf + offset); |
| + struct dirent* out_d = (struct dirent*)((char*)out_buf + out_offset); |
| + |
| + // Copy fields |
| + out_d->d_ino = d->d_ino; |
| + out_d->d_off = d->d_off; |
| + size_t name_len = strlen(d->d_name) + 1; |
| + memcpy(out_d->d_name, d->d_name, name_len); |
| + |
| + // Calculate size of output dirent, rounding up for alignment |
| + out_d->d_reclen = ROUND_UP(offsetof(dirent, d_name) + name_len, |
| + sizeof(ino_t)); |
| + |
| + offset += d->d_reclen; |
| + out_offset += out_d->d_reclen; |
| + } |
| + |
| + *nread = out_offset; |
| + return 0; |
| +#else |
| return ENOSYS; |
| +#endif |
| } |
| int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) { |
| @@ -49,7 +102,12 @@ int _real_munmap(void* addr, size_t length) { |
| } |
| int _real_open(const char* pathname, int oflag, mode_t mode, int* newfd) { |
| - return ENOSYS; |
| + int fd = open(pathname, oflag, mode); |
| + if (fd < 0) |
| + return errno; |
| + |
| + *newfd = fd; |
| + return 0; |
| } |
| int _real_open_resource(const char* file, int* fd) { |
| @@ -57,7 +115,11 @@ int _real_open_resource(const char* file, int* fd) { |
| } |
| int _real_read(int fd, void* buf, size_t count, size_t* nread) { |
| - *nread = count; |
| + int rtn = read(fd, buf, count); |
| + if (rtn < 0) |
| + return errno; |
| + |
| + *nread = rtn; |
| return 0; |
| } |
| @@ -68,7 +130,7 @@ int _real_rmdir(const char* pathname) { |
| int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) { |
| int rtn = write(fd, buf, count); |
| if (rtn < 0) |
| - return -1; |
| + return errno; |
| *nwrote = rtn; |
| return 0; |