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 2f51f47fab9fe0ce0823e6d61672a807b2d31532..536719ac4b88c9889d815d55fa84f381a42dd0b0 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,50 @@ int _real_close(int fd) { |
| } |
| int _real_fstat(int fd, struct stat* buf) { |
| + return fstat(fd, buf); |
| +} |
| + |
| +int _real_getdents(int fd, struct dirent* out_buf, size_t in_count, |
| + size_t* nread) { |
| +#ifdef __linux__ |
| +#define ROUND_UP(X, SIZE) ( ((X) + (SIZE)-1) & (~((SIZE)-1)) ) |
| + |
| + 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 |
|
binji
2015/09/08 19:18:57
where is the single pad byte?
Sam Clegg
2015/09/09 10:11:54
At the end. See 'man getdents'.
|
| + // 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); |
|
binji
2015/09/08 19:18:57
shouldn't this clamp to the max size of out_d->d_n
Sam Clegg
2015/09/09 10:11:54
Its variable size. The max size should be 256 in
|
| + |
| + // Calculate size of output dirent, rounding up for alignment |
| + out_d->d_reclen = ROUND_UP(offsetof(dirent, d_name) + name_len, |
| + sizeof(ino_t)); |
|
binji
2015/09/08 19:18:57
why round to sizeof(ino_t)? Is this to align the s
|
| + |
| + offset += d->d_reclen; |
| + out_offset += out_d->d_reclen; |
| + } |
| + |
| + *nread = out_offset; |
| return 0; |
| -} |
| - |
| -int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t* nread) { |
| +#else |
| return ENOSYS; |
| +#endif |
| } |
| int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) { |
| @@ -49,7 +103,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 +116,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 +131,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; |