fix: close workspace ownership and API escapes
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include <node_api.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
@@ -108,7 +109,32 @@ static napi_value fsyncFn(napi_env env,napi_callback_info info){size_t n=1;napi_
|
||||
if(rc<0)return fail(env,"fsync",errno);return nullptr;}
|
||||
static napi_value closeFn(napi_env env,napi_callback_info info){size_t n=1;napi_value a[1];napi_get_cb_info(env,info,&n,a,nullptr,nullptr);Handle*h;if(n!=1||!getHandle(env,a[0],&h))return fail(env,"close",EBADF);if(h->borrows)return fail(env,"close",EBUSY);h->closed=true;handles.erase(h);int rc=::close(h->fd);if(rc<0){int e=errno;if(e==EINTR)return fail(env,"close",e,"ERR_WORKSPACE_FS_AT_CLOSE_UNCERTAIN");return fail(env,"close",e);}return nullptr;}
|
||||
static napi_value withFdFn(napi_env env,napi_callback_info info){size_t n=2;napi_value a[2];napi_get_cb_info(env,info,&n,a,nullptr,nullptr);Handle*h; napi_valuetype t;if(n!=2||!getHandle(env,a[0],&h)||napi_typeof(env,a[1],&t)!=napi_ok||t!=napi_function)return fail(env,"borrow",EINVAL);h->borrows++;napi_value argv; napi_create_int32(env,h->fd,&argv); napi_value out; napi_value global; napi_get_global(env, &global); napi_status rc=napi_call_function(env, global,a[1],1,&argv,&out);h->borrows--;if(rc!=napi_ok)return nullptr;return out;}
|
||||
static napi_value fdNumberForSynchronousBorrowFn(napi_env env,napi_callback_info info){ size_t n=1; napi_value a[1]; napi_get_cb_info(env,info,&n,a,nullptr,nullptr); Handle*h; if(n!=1||!getHandle(env,a[0],&h)) return fail(env,"fcntl",EBADF); napi_value out; napi_create_int32(env,h->fd,&out); return out; }
|
||||
static napi_value fcntlFn(napi_env env,napi_callback_info info){
|
||||
size_t n=2; napi_value a[2]; napi_get_cb_info(env,info,&n,a,nullptr,nullptr); Handle*h; std::string op;
|
||||
if(n!=2||!getHandle(env,a[0],&h)||!str(env,a[1],op)||h->directory) return fail(env,"fcntl",EINVAL);
|
||||
if(op=="unlock") {
|
||||
#ifdef F_OFD_SETLK
|
||||
struct flock lk{}; lk.l_type=F_UNLCK; lk.l_whence=SEEK_SET; if(::fcntl(h->fd,F_OFD_SETLK,&lk)<0) return fail(env,"fcntl",errno);
|
||||
#else
|
||||
if(::flock(h->fd,LOCK_UN)<0) return fail(env,"fcntl",errno);
|
||||
#endif
|
||||
napi_value out; napi_create_string_utf8(env,"available",NAPI_AUTO_LENGTH,&out); return out;
|
||||
}
|
||||
if(op=="probe-exclusive-nonblocking" || op=="hold-exclusive") {
|
||||
#ifdef F_OFD_SETLK
|
||||
struct flock lk{}; lk.l_type=F_WRLCK; lk.l_whence=SEEK_SET; int rc=::fcntl(h->fd,F_OFD_SETLK,&lk);
|
||||
if(rc==0) { if(op=="probe-exclusive-nonblocking") { lk.l_type=F_UNLCK; ::fcntl(h->fd,F_OFD_SETLK,&lk); } napi_value out; napi_create_string_utf8(env,op=="hold-exclusive"?"held":"available",NAPI_AUTO_LENGTH,&out); return out; }
|
||||
#else
|
||||
int rc=::flock(h->fd,LOCK_EX|LOCK_NB);
|
||||
if(rc==0) { if(op=="probe-exclusive-nonblocking") ::flock(h->fd,LOCK_UN); napi_value out; napi_create_string_utf8(env,op=="hold-exclusive"?"held":"available",NAPI_AUTO_LENGTH,&out); return out; }
|
||||
#endif
|
||||
if(errno==EWOULDBLOCK||errno==EAGAIN||errno==EACCES) { napi_value out; napi_create_string_utf8(env,"held",NAPI_AUTO_LENGTH,&out); return out; }
|
||||
return fail(env,"fcntl",errno);
|
||||
}
|
||||
return fail(env,"fcntl",EINVAL);
|
||||
}
|
||||
static napi_value duplicateForChildStdioFn(napi_env env,napi_callback_info info){size_t n=4;napi_value a[4];napi_get_cb_info(env,info,&n,a,nullptr,nullptr);Handle*w,*r;int32_t wf,rf;if(n!=4||!getHandle(env,a[0],&w)||!getHandle(env,a[1],&r)||w->directory||!r->directory||napi_get_value_int32(env,a[2],&wf)!=napi_ok||napi_get_value_int32(env,a[3],&rf)!=napi_ok||wf<0||rf<0)return fail(env,"dup2",EINVAL);if(w->borrows||r->borrows)return fail(env,"dup2",EBUSY);int rc;do{rc=::dup2(w->fd,wf);}while(rc<0&&errno==EINTR);if(rc<0)return fail(env,"dup2",errno);do{rc=::dup2(r->fd,rf);}while(rc<0&&errno==EINTR);if(rc<0)return fail(env,"dup2",errno);return nullptr;}
|
||||
static napi_value init(napi_env env,napi_value exports){napi_property_descriptor pub[]={{"openat",0,openatFn,0,0,0,napi_enumerable,0},{"mkdirat",0,mkdiratFn,0,0,0,napi_enumerable,0},{"fstatat",0,fstatatFn,0,0,0,napi_enumerable,0},{"fsyncDirectory",0,fsyncFn,0,0,0,napi_enumerable,0},{"close",0,closeFn,0,0,0,napi_enumerable,0}};napi_define_properties(env,exports,5,pub);napi_property_descriptor priv[]={{"withFd",0,withFdFn,0,0,0,napi_default,0},{"duplicateForChildStdio",0,duplicateForChildStdioFn,0,0,0,napi_default,0}};napi_define_properties(env,exports,2,priv);return exports;}
|
||||
static napi_value init(napi_env env,napi_value exports){napi_property_descriptor pub[]={{"openat",0,openatFn,0,0,0,napi_enumerable,0},{"mkdirat",0,mkdiratFn,0,0,0,napi_enumerable,0},{"fstatat",0,fstatatFn,0,0,0,napi_enumerable,0},{"fsyncDirectory",0,fsyncFn,0,0,0,napi_enumerable,0},{"close",0,closeFn,0,0,0,napi_enumerable,0}};napi_define_properties(env,exports,5,pub);napi_property_descriptor priv[]={{"withFd",0,withFdFn,0,0,0,napi_default,0},{"duplicateForChildStdio",0,duplicateForChildStdioFn,0,0,0,napi_default,0},{"fdNumberForSynchronousBorrow",0,fdNumberForSynchronousBorrowFn,0,0,0,napi_default,0},{"fcntl",0,fcntlFn,0,0,0,napi_default,0}};napi_define_properties(env,exports,4,priv);return exports;}
|
||||
}
|
||||
NAPI_MODULE(NODE_GYP_MODULE_NAME,init)
|
||||
|
||||
Reference in New Issue
Block a user