@@ -89,6 +89,24 @@ constexpr char kPathSeparator = '/';
8989const char * const kPathSeparator = " \\ /" ;
9090#endif
9191
92+ // The access modes can be any of F_OK, R_OK, W_OK or X_OK. Some might not be
93+ // available on specific systems. They can be used in combination as well
94+ // (F_OK | R_OK | W_OK | X_OK).
95+ constexpr int kMaximumAccessMode = F_OK | W_OK | R_OK | X_OK;
96+ constexpr int kMinimumAccessMode = std::min({F_OK, W_OK, R_OK, X_OK});
97+
98+ constexpr int kDefaultCopyMode = 0 ;
99+ // The copy modes can be any of UV_FS_COPYFILE_EXCL, UV_FS_COPYFILE_FICLONE or
100+ // UV_FS_COPYFILE_FICLONE_FORCE. They can be used in combination as well
101+ // (US_FS_COPYFILE_EXCL | US_FS_COPYFILE_FICLONE |
102+ // US_FS_COPYFILE_FICLONE_FORCE).
103+ constexpr int kMinimumCopyMode = std::min({kDefaultCopyMode ,
104+ UV_FS_COPYFILE_EXCL,
105+ UV_FS_COPYFILE_FICLONE,
106+ UV_FS_COPYFILE_FICLONE_FORCE});
107+ constexpr int kMaximumCopyMode =
108+ UV_FS_COPYFILE_EXCL | UV_FS_COPYFILE_FICLONE | UV_FS_COPYFILE_FICLONE_FORCE;
109+
92110std::string Basename (const std::string& str, const std::string& extension) {
93111 // Remove everything leading up to and including the final path separator.
94112 std::string::size_type pos = str.find_last_of (kPathSeparator );
@@ -854,6 +872,43 @@ void FromNamespacedPath(std::string* path) {
854872#endif
855873}
856874
875+ static inline int GetValidMode (Environment* env,
876+ Local<Value> mode_v,
877+ std::string_view type) {
878+ if (!mode_v->IsInt32 () && !mode_v->IsNullOrUndefined ()) {
879+ THROW_ERR_INVALID_ARG_TYPE (env, " mode must be int32 or null/undefined" );
880+ return -1 ;
881+ }
882+
883+ int min = kMinimumAccessMode ;
884+ int max = kMaximumAccessMode ;
885+ int def = F_OK;
886+
887+ if (type == " copyFile" ) {
888+ min = kMinimumCopyMode ;
889+ max = kMaximumCopyMode ;
890+ def = mode_v->IsNullOrUndefined () ? kDefaultCopyMode
891+ : mode_v.As <Int32>()->Value ();
892+ } else if (type != " access" ) {
893+ THROW_ERR_INVALID_ARG_TYPE (
894+ env, " type must be equal to \" copyFile\" or \" access\" " );
895+ return -1 ;
896+ }
897+
898+ if (mode_v->IsNullOrUndefined ()) {
899+ return def;
900+ }
901+
902+ const int mode = mode_v.As <Int32>()->Value ();
903+ if (mode < min || mode > max) {
904+ THROW_ERR_OUT_OF_RANGE (
905+ env, " mode is out of range: >= %d && <= %d" , min, max);
906+ return -1 ;
907+ }
908+
909+ return mode;
910+ }
911+
857912void AfterMkdirp (uv_fs_t * req) {
858913 FSReqBase* req_wrap = FSReqBase::from_req (req);
859914 FSReqAfterScope after (req_wrap, req);
@@ -973,8 +1028,8 @@ void Access(const FunctionCallbackInfo<Value>& args) {
9731028 const int argc = args.Length ();
9741029 CHECK_GE (argc, 2 );
9751030
976- CHECK ( args[1 ]-> IsInt32 () );
977- int mode = args[ 1 ]. As <Int32>()-> Value () ;
1031+ int mode = GetValidMode (env, args[1 ], " access " );
1032+ if ( mode == - 1 ) return ;
9781033
9791034 BufferValue path (isolate, args[0 ]);
9801035 CHECK_NOT_NULL (*path);
@@ -2086,6 +2141,9 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
20862141 const int argc = args.Length ();
20872142 CHECK_GE (argc, 3 );
20882143
2144+ const int flags = GetValidMode (env, args[2 ], " copyFile" );
2145+ if (flags == -1 ) return ;
2146+
20892147 BufferValue src (isolate, args[0 ]);
20902148 CHECK_NOT_NULL (*src);
20912149 THROW_IF_INSUFFICIENT_PERMISSIONS (
@@ -2096,9 +2154,6 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
20962154 THROW_IF_INSUFFICIENT_PERMISSIONS (
20972155 env, permission::PermissionScope::kFileSystemWrite , dest.ToStringView ());
20982156
2099- CHECK (args[2 ]->IsInt32 ());
2100- const int flags = args[2 ].As <Int32>()->Value ();
2101-
21022157 if (argc > 3 ) { // copyFile(src, dest, flags, req)
21032158 FSReqBase* req_wrap_async = GetReqWrap (args, 3 );
21042159 FS_ASYNC_TRACE_BEGIN2 (UV_FS_COPYFILE,
0 commit comments