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
}