CAMLprim value core_kernel_time_ns_gettime_or_zero()
{
  struct timeval tp;
  if (gettimeofday(&tp, NULL) == -1)
    return caml_alloc_int63(0);
  else
    return caml_alloc_int63(NANOS_PER_SECOND * (uint64_t)tp.tv_sec + (uint64_t)tp.tv_usec * 1000);
}
/* Note: this is imported noalloc if (and only if) ARCH_SIXTYFOUR is defined.
 * This is OK because caml_alloc_int63 doesn't actually allocate in that case. */
CAMLprim value core_kernel_time_ns_gettime_or_zero()
{
  struct timespec ts;

  if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
    return caml_alloc_int63(0);
  else
    return caml_alloc_int63(NANOS_PER_SECOND * (uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec);
}
CAMLprim value quota_query (value v_user_or_group, value v_id, value v_path)
{
  int id, cmd;
  struct dqblk quota;
  int64_t bytes_used, bytes_soft, bytes_hard;
  CAMLparam3(v_user_or_group, v_id, v_path);
  CAMLlocal3(v_ret, v_bytes_limit, v_inodes_limit);

  id  = Int_val(v_id);
  cmd = quota_command(v_user_or_group, Q_GETQUOTA);

  memset(&quota, 0, sizeof(quota));
  if (quota_control(String_val(v_path), cmd, id, (caddr_t)&quota))
    unix_error(errno, "Unix.Quota: unable to query quota", v_path);

  bytes_used = QUOTA_BYTES_PER_SPACE_UNIT * (int64_t) QUOTA_SPACE_USED(quota);
  bytes_soft = QUOTA_BYTES_PER_SPACE_UNIT * (int64_t) quota.dqb_bsoftlimit;
  bytes_hard = QUOTA_BYTES_PER_SPACE_UNIT * (int64_t) quota.dqb_bhardlimit;

  v_bytes_limit = caml_alloc_small(3, 0);
  Store_field(v_bytes_limit, 0, caml_alloc_int63(bytes_soft));
  Store_field(v_bytes_limit, 1, caml_alloc_int63(bytes_hard));
  Store_field(v_bytes_limit, 2, caml_copy_double((double)quota.dqb_btime));

  v_inodes_limit = caml_alloc_small(3, 0);
  Store_field(v_inodes_limit, 0, caml_alloc_int63(quota.dqb_isoftlimit));
  Store_field(v_inodes_limit, 1, caml_alloc_int63(quota.dqb_ihardlimit));
  Store_field(v_inodes_limit, 2, caml_copy_double((double)quota.dqb_itime));

  v_ret = caml_alloc_small(4, 0);
  Store_field(v_ret, 0, v_bytes_limit);
  Store_field(v_ret, 1, caml_alloc_int63(bytes_used));
  Store_field(v_ret, 2, v_inodes_limit);
  Store_field(v_ret, 3, caml_alloc_int63(quota.dqb_curinodes));

  CAMLreturn(v_ret);
}