static ERL_NIF_TERM pread_nif()

in src/couch/priv/couch_cfile/couch_cfile.c [360:419]


static ERL_NIF_TERM pread_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef COUCH_CFILE_SUPPORTED
   handle_t* hdl;
   long offset, block_size, bytes_read;
   SysIOVec io_vec[1];
   posix_errno_t res_errno = 0;
   ErlNifBinary result;

   if (argc != 3
       || !get_handle(env, argv[0], &hdl)
       || !enif_is_number(env, argv[1])
       || !enif_is_number(env, argv[2])
   ) {
     return badarg(env);
   }

   if (!enif_get_int64(env, argv[1], &offset)
       || !enif_get_int64(env, argv[2], &block_size)
       || offset < 0
       || block_size < 0
   ) {
        return err_tup(env, EINVAL);
   }

   if (!enif_alloc_binary((size_t) block_size, &result)) {
       return err_tup(env, ENOMEM);
   }

   io_vec[0].iov_base = (char *)result.data;
   io_vec[0].iov_len = result.size;

   // ------ Critical section start ------
   READ_LOCK;
   if (hdl->fd < 0) {
       READ_UNLOCK;
       enif_release_binary(&result);
       return err_tup(env, EINVAL);
   }
   bytes_read = efile_preadv(hdl->fd, offset, io_vec, 1, &res_errno);
   READ_UNLOCK;
   // ------ Critical section end ------

   if (bytes_read < 0) {
       enif_release_binary(&result);
       return err_tup(env, res_errno);
   }
   if (bytes_read == 0) {
       enif_release_binary(&result);
       return ATOM_EOF;
   }
   if (bytes_read < block_size && !enif_realloc_binary(&result, bytes_read)) {
       enif_release_binary(&result);
       return err_tup(env, ENOMEM);
   }
   return ok_tup(env, enif_make_binary(env, &result));
#else
   return err_tup(env, EINVAL);
#endif
}