static ERL_NIF_TERM dup_nif()

in src/couch/priv/couch_cfile/couch_cfile.c [234:300]


static ERL_NIF_TERM dup_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef COUCH_CFILE_SUPPORTED
   int fd, newfd;
   handle_t* hdl;
   ErlNifRWLock *lock;
   ErlNifPid pid;
   ERL_NIF_TERM res;


   if (argc != 1 || !enif_is_number(env, argv[0])) {
       return badarg(env);
   }
   if (!enif_get_int(env, argv[0], &fd) || fd < 0) {
       return err_tup(env, EINVAL);
   }

   if(!enif_self(env, &pid)){
       // Calling from not a process-bound environment? (highly unlikely)
       return err_tup(env, EINVAL);
   }
   newfd = dup(fd);

   if (newfd < 0) {
       return err_tup(env, errno);
   }
   // From here on close the new dup-ed file descriptors on any failure.

   lock = enif_rwlock_create("couch_cfile:rwlock");
   if(!lock) {
       close(newfd);
       return err_tup(env, ENOMEM);
   }

   hdl = (handle_t*) enif_alloc_resource(HANDLE_T, sizeof(handle_t));
   if (!hdl) {
       close(newfd);
       enif_rwlock_destroy(lock);
       return err_tup(env, ENOMEM);
   }
   // From here on, once we release our resource the destructor will be called.
   // On failures below, we'll let the destructor deallocate the lock, but
   // we'll close the new handle here manually. The descriptors will be set to
   // -1 so the state in the handle will be "closed" until we know everything
   // is good to go

   hdl->lock = lock;
   hdl->fd = -1;
   hdl->old_fd = -1;

   if (enif_monitor_process(env, hdl, &pid, &hdl->monitor) != 0) {
       close(newfd);
       enif_release_resource(hdl);
       return err_tup(env, EINVAL);
   }

   // Everything is good to go. Return the new handle
   hdl->fd = newfd;
   hdl->old_fd = fd;

   res = enif_make_resource(env, hdl);
   enif_release_resource(hdl);
   return ok_tup(env, res);
#else
   return err_tup(env, EINVAL);
#endif
}