diff --git a/src/file.js.c b/src/file.js.c index 1236919d..a1dc7a14 100644 --- a/src/file.js.c +++ b/src/file.js.c @@ -15,7 +15,7 @@ #endif static JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); -static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); +static JSValue _file_remove_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _file_rename_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); @@ -39,13 +39,11 @@ void tf_file_register(JSContext* context) JS_SetPropertyStr(context, global, "File", file); JS_SetPropertyStr(context, file, "readFile", JS_NewCFunction(context, _file_read_file, "readFile", 1)); JS_SetPropertyStr(context, file, "writeFile", JS_NewCFunction(context, _file_write_file, "writeFile", 2)); - - /* TODO: async */ JS_SetPropertyStr(context, file, "makeDirectory", JS_NewCFunction(context, _file_make_directory, "makeDirectory", 1)); - JS_SetPropertyStr(context, file, "readDirectory", JS_NewCFunction(context, _file_read_directory, "readDirectory", 1)); + JS_SetPropertyStr(context, file, "removeDirectory", JS_NewCFunction(context, _file_remove_directory, "removeDirectory", 1)); + JS_SetPropertyStr(context, file, "unlinkFile", JS_NewCFunction(context, _file_unlink_file, "unlinkFile", 1)); JS_SetPropertyStr(context, file, "renameFile", JS_NewCFunction(context, _file_rename_file, "renameFile", 2)); JS_SetPropertyStr(context, file, "stat", JS_NewCFunction(context, _file_stat, "stat", 1)); - JS_SetPropertyStr(context, file, "unlinkFile", JS_NewCFunction(context, _file_unlink_file, "unlinkFile", 1)); JS_FreeValue(context, global); } @@ -204,7 +202,7 @@ static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int a JS_FreeCString(context, (const char*)buffer); } - int result = uv_fs_open(tf_task_get_loop(task), req, file_name, UV_FS_O_CREAT | UV_FS_O_WRONLY, 0755, _file_write_open_callback); + int result = uv_fs_open(tf_task_get_loop(task), req, file_name, UV_FS_O_CREAT | UV_FS_O_WRONLY, 0644, _file_write_open_callback); if (result < 0) { tf_task_reject_promise(task, promise, JS_ThrowInternalError(context, uv_strerror(result))); @@ -213,63 +211,63 @@ static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int a return promise_value; } +static void _file_async_callback(uv_fs_t* req) +{ + uv_fs_req_cleanup(req); + tf_task_t* task = req->loop->data; + JSContext* context = tf_task_get_context(task); + promiseid_t promise = (promiseid_t)(intptr_t)req->data; + if (req->result == 0) + { + tf_task_resolve_promise(task, promise, JS_NewInt32(context, req->result)); + } + else + { + tf_task_reject_promise(task, promise, JS_NewInt32(context, req->result)); + } + free(req); +} + static JSValue _file_rename_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { void* task = JS_GetContextOpaque(context); - const char* oldName = JS_ToCString(context, argv[0]); - const char* newName = JS_ToCString(context, argv[1]); - uv_fs_t req; - int result = uv_fs_rename(tf_task_get_loop(task), &req, oldName, newName, 0); - JS_FreeCString(context, oldName); - JS_FreeCString(context, newName); - return JS_NewInt32(context, result); + const char* old_name = JS_ToCString(context, argv[0]); + const char* new_name = JS_ToCString(context, argv[1]); + promiseid_t promise = tf_task_allocate_promise(task); + JSValue promise_value = tf_task_get_promise(task, promise); + uv_fs_t* req = malloc(sizeof(uv_fs_t)); + *req = (uv_fs_t) + { + .data = (void*)(intptr_t)promise, + }; + int result = uv_fs_rename(tf_task_get_loop(task), req, old_name, new_name,_file_async_callback); + JS_FreeCString(context, old_name); + JS_FreeCString(context, new_name); + if (result < 0) + { + tf_task_reject_promise(task, promise, JS_NewInt32(context, result)); + } + return promise_value; } static JSValue _file_unlink_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { void* task = JS_GetContextOpaque(context); - const char* fileName = JS_ToCString(context, argv[0]); - uv_fs_t req; - int result = uv_fs_unlink(tf_task_get_loop(task), &req, fileName, 0); - JS_FreeCString(context, fileName); - return JS_NewInt32(context, result); -} - -static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) -{ - const char* directory = JS_ToCString(context, argv[0]); - JSValue array = JS_NewArray(context); - -#ifdef _WIN32 - WIN32_FIND_DATA find; - std::string pattern = directory; - pattern += "\\*"; - HANDLE handle = FindFirstFile(pattern.c_str(), &find); - if (handle != INVALID_HANDLE_VALUE) + const char* file_name = JS_ToCString(context, argv[0]); + promiseid_t promise = tf_task_allocate_promise(task); + JSValue promise_value = tf_task_get_promise(task, promise); + uv_fs_t* req = malloc(sizeof(uv_fs_t)); + *req = (uv_fs_t) { - int index = 0; - do { - JS_SetPropertyUint32(context, array, index++, JS_NewString(context, find.cFileName)); - } while (FindNextFile(handle, &find) != 0); - FindClose(handle); - } -#else - DIR* dir = opendir(directory); - if (dir) + .data = (void*)(intptr_t)promise, + }; + int result = uv_fs_unlink(tf_task_get_loop(task), req, file_name, _file_async_callback); + JS_FreeCString(context, file_name); + if (result < 0) { - uint32_t index = 0; - struct dirent* entry = readdir(dir); - while (entry) - { - JS_SetPropertyUint32(context, array, index++, JS_NewString(context, entry->d_name)); - entry = readdir(dir); - } - closedir(dir); + tf_task_reject_promise(task, promise, JS_NewInt32(context, result)); } -#endif - - JS_FreeCString(context, directory); - return array; + return promise_value; } JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) @@ -277,10 +275,41 @@ JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc void* task = JS_GetContextOpaque(context); const char* directory = JS_ToCString(context, argv[0]); - uv_fs_t req; - int result = uv_fs_mkdir(tf_task_get_loop(task), &req, directory, 0755, 0); + promiseid_t promise = tf_task_allocate_promise(task); + JSValue promise_value = tf_task_get_promise(task, promise); + uv_fs_t* req = malloc(sizeof(uv_fs_t)); + *req = (uv_fs_t) + { + .data = (void*)(intptr_t)promise, + }; + int result = uv_fs_mkdir(tf_task_get_loop(task), req, directory, 0755, _file_async_callback); JS_FreeCString(context, directory); - return JS_NewInt32(context, result); + if (result < 0) + { + tf_task_reject_promise(task, promise, JS_NewInt32(context, result)); + } + return promise_value; +} + +JSValue _file_remove_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) +{ + void* task = JS_GetContextOpaque(context); + const char* directory = JS_ToCString(context, argv[0]); + + promiseid_t promise = tf_task_allocate_promise(task); + JSValue promise_value = tf_task_get_promise(task, promise); + uv_fs_t* req = malloc(sizeof(uv_fs_t)); + *req = (uv_fs_t) + { + .data = (void*)(intptr_t)promise, + }; + int result = uv_fs_rmdir(tf_task_get_loop(task), req, directory, _file_async_callback); + JS_FreeCString(context, directory); + if (result < 0) + { + tf_task_reject_promise(task, promise, JS_NewInt32(context, result)); + } + return promise_value; } JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) diff --git a/src/tests.c b/src/tests.c index cb8344cb..b5f76717 100644 --- a/src/tests.c +++ b/src/tests.c @@ -496,7 +496,6 @@ static void _test_file(const tf_test_options_t* options) fprintf(file, "'use strict';\n" "File.readFile('out/test.js').then(function(data) {\n" - " print('READ', utf8Decode(data));\n" "}).catch(function(error) {\n" " print('ERROR', error);\n" " exit(1);\n" @@ -507,19 +506,35 @@ static void _test_file(const tf_test_options_t* options) "}).catch(function(error) {\n" " print('expected error', error);\n" "});\n" - "File.writeFile('out/new.txt', 'hello').then(function(result) {\n" - " File.readFile('out/new.txt').then(function(data) {\n" - " print('READ', utf8Decode(data));\n" - " if (utf8Decode(data) != 'hello') {\n" + "File.unlinkFile('out/test/new.txt').finally(function() {\n" + " return File.removeDirectory('out/test');\n" + "}).finally(function() {\n" + " return File.makeDirectory('out/test').then(function() {\n" + " return File.writeFile('out/test/new.txt', 'hello').then(function(result) {\n" + " return File.readFile('out/test/new.txt').then(function(data) {\n" + " if (utf8Decode(data) != 'hello') {\n" + " print('READ', utf8Decode(data));\n" + " exit(1);\n" + " }\n" + " }).catch(function(error) {\n" + " print('unexpected read error', error);\n" + " exit(1);\n" + " });\n" + " }).catch(function(error) {\n" + " print('unexpected write error', error);\n" " exit(1);\n" - " }\n" + " });\n" " }).catch(function(error) {\n" - " print('unexpected read error', error);\n" + " print('unexpected make directory error', error);\n" " exit(1);\n" " });\n" - "}).catch(function(error) {\n" - " print('unexpected write error', error);\n" - " exit(1);\n" + "}).finally(function() {\n" + " return File.renameFile('out/test/new.txt', 'out/test/renamed.txt').catch(x => print(x)).finally(function() {\n" + " return File.unlinkFile('out/test/renamed.txt').catch(x => print(x)).finally(function() {\n" + " print('removing directory');\n" + " return File.removeDirectory('out/test').catch(x => print(x));\n" + " });\n" + " });\n" "});\n"); fclose(file);