blob: baa11a8e25aaf6db81ce40fa66c7f9146f1eb7a6 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <dirent.h>
#include <errno.h>
#include <irt_syscalls.h>
#include <nacl_dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common/alog.h"
#include "common/irt_wrapper_util.h"
#if defined(__native_client__)
static ssize_t nacl_getdents_wrapper(int fd, char* buf, size_t buf_size);
#else
#include <sys/syscall.h>
#endif
IRT_WRAPPER(getdents, int fd, struct dirent* ent, size_t count,
size_t* nread) {
#if defined(__native_client__)
// NaCl's dirent lacks d_type field, so our getdents implementation
// assumes __nacl_irt_getdents is hooked by posix_translation and
// returns Bionic's dirent, not NaCl's. See also
// bionic/libc/arch-nacl/syscalls/__getdents64.c.
//
// Due to this reason, our getdents implementation does not work for
// __nacl_irt_getdents provided by NaCl's supervisor (e.g., sel_ldr)
// for unittests. We convert NaCl's dirent to Bionic's by this
// IRT wrapper.
ssize_t result = nacl_getdents_wrapper(
fd, reinterpret_cast<char*>(ent), count);
#else
// nonsfi_loader does not implement __nacl_irt_getdents, so we call
// it directly.
ssize_t result = syscall(__NR_getdents64, fd, ent, count);
#endif
if (result < 0)
return errno;
*nread = result;
return 0;
}
// NaCl IRT does not support O_DIRECTORY. We emulate it by calling
// fstat for unittests. Production ARC does not have this issue
// because posix_translation does support O_DIRECTORY.
IRT_WRAPPER(open, const char* pathname, int oflags, mode_t cmode, int* newfd) {
// Do not pass O_DIRECTORY bit. nonsfi_loader on ARM does not
// understand ARM's O_DIRECTORY which is different from
// NACL_ABI_O_DIRECTORY.
int result = __nacl_irt_open_real(pathname, oflags & ~O_DIRECTORY,
cmode, newfd);
if (!result && (oflags & O_DIRECTORY)) {
struct stat st;
if (fstat(*newfd, &st))
LOG_ALWAYS_FATAL("fstat unexpectedly failed");
if (!S_ISDIR(st.st_mode)) {
if (close(*newfd))
LOG_ALWAYS_FATAL("close unexpectedly failed");
return ENOTDIR;
}
}
return result;
}
#if defined(__native_client__)
// This should be defined after IRT_WRAPPER(getdents) because
// nacl_getdents_wrapper.h uses __nacl_irt_getdents_real.
#define DIRENT_TYPE struct dirent
#include "nacl_getdents_wrapper.h" // NOLINT
#endif
void InjectIrtHooks() {
DO_WRAP(getdents);
DO_WRAP(open);
}