@@ -89,6 +89,25 @@ 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({
104+ kDefaultCopyMode ,
105+ UV_FS_COPYFILE_EXCL,
106+ UV_FS_COPYFILE_FICLONE,
107+ UV_FS_COPYFILE_FICLONE_FORCE});
108+ constexpr int kMaximumCopyMode = UV_FS_COPYFILE_EXCL |
109+ UV_FS_COPYFILE_FICLONE | UV_FS_COPYFILE_FICLONE_FORCE;
110+
92111std::string Basename (const std::string& str, const std::string& extension) {
93112 // Remove everything leading up to and including the final path separator.
94113 std::string::size_type pos = str.find_last_of (kPathSeparator );
@@ -854,6 +873,44 @@ void FromNamespacedPath(std::string* path) {
854873#endif
855874}
856875
876+
877+ static inline int GetValidMode (Environment* env,
878+ Local<Value> mode_v, std::string_view type) {
879+ if (!mode_v->IsInt32 () && !mode_v->IsNullOrUndefined ()) {
880+ THROW_ERR_INVALID_ARG_TYPE (env, " mode must be int32 or null/undefined" );
881+ return -1 ;
882+ }
883+
884+ int min = kMinimumAccessMode ;
885+ int max = kMaximumAccessMode ;
886+ int def = F_OK;
887+
888+ if (type == " copyFile" ) {
889+ min = kMinimumCopyMode ;
890+ max = kMaximumCopyMode ;
891+ def = mode_v->IsNullOrUndefined () ?
892+ kDefaultCopyMode :
893+ mode_v.As <Int32>()->Value ();
894+ } else if (type != " access" ) {
895+ THROW_ERR_INVALID_ARG_TYPE (env,
896+ " type must be equal to \" copyFile\" or \" access\" " );
897+ return -1 ;
898+ }
899+
900+ if (mode_v->IsNullOrUndefined ()) {
901+ return def;
902+ }
903+
904+ const int mode = mode_v.As <Int32>()->Value ();
905+ if (mode < min || mode > max) {
906+ THROW_ERR_OUT_OF_RANGE (env,
907+ " mode is out of range: >= %d && <= %d" , min, max);
908+ return -1 ;
909+ }
910+
911+ return mode;
912+ }
913+
857914void AfterMkdirp (uv_fs_t * req) {
858915 FSReqBase* req_wrap = FSReqBase::from_req (req);
859916 FSReqAfterScope after (req_wrap, req);
@@ -973,8 +1030,8 @@ void Access(const FunctionCallbackInfo<Value>& args) {
9731030 const int argc = args.Length ();
9741031 CHECK_GE (argc, 2 );
9751032
976- CHECK ( args[1 ]-> IsInt32 () );
977- int mode = args[ 1 ]. As <Int32>()-> Value () ;
1033+ int mode = GetValidMode (env, args[1 ], " access " );
1034+ if ( mode == - 1 ) return ;
9781035
9791036 BufferValue path (isolate, args[0 ]);
9801037 CHECK_NOT_NULL (*path);
@@ -2086,6 +2143,9 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
20862143 const int argc = args.Length ();
20872144 CHECK_GE (argc, 3 );
20882145
2146+ const int flags = GetValidMode (env, args[2 ], " copyFile" );
2147+ if (flags == -1 ) return ;
2148+
20892149 BufferValue src (isolate, args[0 ]);
20902150 CHECK_NOT_NULL (*src);
20912151 THROW_IF_INSUFFICIENT_PERMISSIONS (
@@ -2096,9 +2156,6 @@ static void CopyFile(const FunctionCallbackInfo<Value>& args) {
20962156 THROW_IF_INSUFFICIENT_PERMISSIONS (
20972157 env, permission::PermissionScope::kFileSystemWrite , dest.ToStringView ());
20982158
2099- CHECK (args[2 ]->IsInt32 ());
2100- const int flags = args[2 ].As <Int32>()->Value ();
2101-
21022159 if (argc > 3 ) { // copyFile(src, dest, flags, req)
21032160 FSReqBase* req_wrap_async = GetReqWrap (args, 3 );
21042161 FS_ASYNC_TRACE_BEGIN2 (UV_FS_COPYFILE,
0 commit comments