int NaClHostDescFdatasync(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFdatasync", d);
  /* fdatasync does not exist for osx. */
#if NACL_OSX
  if (-1 == fsync(d->d)) {
#else
  if (-1 == fdatasync(d->d)) {
#endif
    return -NaClXlateErrno(errno);
  }
  return 0;
}

int NaClHostDescFtruncate(struct NaClHostDesc *d, nacl_off64_t length) {
  NaClHostDescCheckValidity("NaClHostDescFtruncate", d);
#if NACL_LINUX
  if (-1 == ftruncate64(d->d, length)) {
#elif NACL_OSX
  if (-1 == ftruncate(d->d, length)) {
#else
# error Unsupported platform
#endif
    return -NaClXlateErrno(errno);
  }
  return 0;
}
int NaClHostDescFsync(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFsync", d);
  if (-1 == fsync(d->d)) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
int NaClHostDescFchdir(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFchdir", d);
  if (-1 == fchdir(d->d)) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
int NaClHostDescFchmod(struct NaClHostDesc *d, nacl_abi_mode_t mode) {
  NaClHostDescCheckValidity("NaClHostDescFchmod", d);
  if (-1 == fchmod(d->d, NaClMapMode(mode))) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
                          void const          *buf,
                          size_t              len) {
  /*
   * See NaClHostDescPWrite for details for why need_lock is required.
   */
  int need_lock;
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescWrite", d);
  if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    NaClLog(3, "NaClHostDescWrite: RDONLY file\n");
    return -NACL_ABI_EBADF;
  }

  need_lock = NACL_LINUX && (0 != (d->flags & NACL_ABI_O_APPEND));
  /*
   * Grab O_APPEND attribute lock, in case pwrite occurs in another
   * thread.
   */
  if (need_lock) {
    NaClHostDescExclusiveLock(d->d);
  }
  retval = write(d->d, buf, len);
  if (need_lock) {
    NaClHostDescExclusiveUnlock(d->d);
  }
  if (-1 == retval) {
    retval = -NaClXlateErrno(errno);
  }
  return retval;
}
int NaClHostDescIsatty(struct NaClHostDesc *d) {
  int retval;

  NaClHostDescCheckValidity("NaClHostDescIsatty", d);
  retval = isatty(d->d);
  /* When isatty fails it returns zero and sets errno. */
  return (0 == retval) ? -NaClXlateErrno(errno) : retval;
}
/*
 * See NaClHostDescStat below.
 */
int NaClHostDescFstat(struct NaClHostDesc  *d,
                      nacl_host_stat_t     *nhsp) {
  NaClHostDescCheckValidity("NaClHostDescFstat", d);
  if (NACL_HOST_FSTAT64(d->d, nhsp) == -1) {
    return -NaClXlateErrno(errno);
  }

  return 0;
}
int NaClHostDescIoctl(struct NaClHostDesc *d,
                      int                 request,
                      void                *arg) {
  UNREFERENCED_PARAMETER(request);
  UNREFERENCED_PARAMETER(arg);

  NaClHostDescCheckValidity("NaClHostDescIoctl", d);
  return -NACL_ABI_ENOSYS;
}
ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
                          void const          *buf,
                          size_t              len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescWrite", d);
  return ((-1 == (retval = write(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
                         void                 *buf,
                         size_t               len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescRead", d);
  return ((-1 == (retval = read(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
int NaClHostDescClose(struct NaClHostDesc *d) {
  int retval;

  NaClHostDescCheckValidity("NaClHostDescClose", d);
  retval = close(d->d);
  if (-1 != retval) {
    d->d = -1;
  }
  return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
}
ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
                         void                 *buf,
                         size_t               len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescRead", d);
  if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    NaClLog(3, "NaClHostDescRead: WRONLY file\n");
    return -NACL_ABI_EBADF;
  }
  return ((-1 == (retval = read(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
nacl_off64_t NaClHostDescSeek(struct NaClHostDesc  *d,
                              nacl_off64_t         offset,
                              int                  whence) {
  nacl_off64_t retval;

  NaClHostDescCheckValidity("NaClHostDescSeek", d);
#if NACL_LINUX
  return ((-1 == (retval = lseek64(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#elif NACL_OSX
  return ((-1 == (retval = lseek(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#else
# error "What Unix-like OS is this?"
#endif
}
/*
 * See NaClHostDescStat below.
 */
int NaClHostDescFstat(struct NaClHostDesc  *d,
                      nacl_host_stat_t     *nhsp) {
  NaClHostDescCheckValidity("NaClHostDescFstat", d);
#if NACL_LINUX
  if (fstat64(d->d, nhsp) == -1) {
    return -errno;
  }
#elif NACL_OSX
  if (fstat(d->d, nhsp) == -1) {
    return -errno;
  }
#else
# error "What OS?"
#endif

  return 0;
}
ssize_t NaClHostDescPWrite(struct NaClHostDesc *d,
                           void const *buf,
                           size_t len,
                           nacl_off64_t offset) {
  int need_lock;
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescPWrite", d);
  if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    NaClLog(3, "NaClHostDescPWrite: RDONLY file\n");
    return -NACL_ABI_EBADF;
  }
  /*
   * Linux's interpretation of what the POSIX standard requires
   * differs from OSX.  On Linux, pwrite using a descriptor that was
   * opened with O_APPEND will ignore the supplied offset parameter
   * and append.  On OSX, the supplied offset parameter wins.
   *
   * The POSIX specification at
   *
   *  http://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
   *
   * says that pwrite should always pay attention to the supplied offset.
   *
   * We standardize on POSIX behavior.
   */
  need_lock = NACL_LINUX && (0 != (d->flags & NACL_ABI_O_APPEND));
  if (need_lock) {
    int orig_flags;
    /*
     * Grab lock that all NaCl platform library using applications
     * will use.  NB: if the descriptor is shared with a non-NaCl
     * platform library-using application, there is a race.
     */
    NaClHostDescExclusiveLock(d->d);
    /*
     * Temporarily disable O_APPEND and issue the pwrite.
     */
    orig_flags = fcntl(d->d, F_GETFL, 0);
    CHECK(orig_flags & O_APPEND);
    if (-1 == fcntl(d->d, F_SETFL, orig_flags & ~O_APPEND)) {
      NaClLog(LOG_FATAL,
              "NaClHostDescPWrite: could not fcntl F_SETFL (~O_APPEND)\n");
    }
    retval = PWRITE(d->d, buf, len, offset);
    /*
     * Always re-enable O_APPEND regardless of pwrite success or
     * failure.
     */
    if (-1 == fcntl(d->d, F_SETFL, orig_flags)) {
      NaClLog(LOG_FATAL,
              "NaClHostDescPWrite: could not fcntl F_SETFL (restore)\n");
    }
    NaClHostDescExclusiveUnlock(d->d);
    if (-1 == retval) {
      retval = -NaClXlateErrno(errno);
    }
    return retval;
  }

  return ((-1 == (retval = PWRITE(d->d, buf, len, offset)))
          ? -NaClXlateErrno(errno) : retval);
}