diff --git a/src/run.c b/src/run.c index 623c8997..e75dc409 100644 --- a/src/run.c +++ b/src/run.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "hvm.c" // Readback: λ-Encoded Ctr @@ -724,7 +724,7 @@ Port io_dl_close(Net* net, Book* book, Port argm) { // This function attempts to remove both files and empty directories without // first checking the type of the path. // Returns: Result<*, IOError> -Port io_delete_file(Net* net, Book* book, Port argm) { +Port io_remove(Net* net, Book* book, Port argm) { Str path = readback_str(net, book, argm); int result = remove(path.buf); @@ -737,76 +737,32 @@ Port io_delete_file(Net* net, Book* book, Port argm) { } } -int delete_directory_recursive(const char* path) { - DIR *d = opendir(path); - size_t path_len = strlen(path); - int r = -1; - - if (d) { - struct dirent *p; - r = 0; - - while (!r && (p = readdir(d))) { - int r2 = -1; - char *buf; - size_t len; - - if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { - continue; - } - - len = path_len + strlen(p->d_name) + 2; - buf = malloc(len); - - if (buf) { - struct stat statbuf; - snprintf(buf, len, "%s/%s", path, p->d_name); - - if (!stat(buf, &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) { - r2 = delete_directory_recursive(buf); - } else { - r2 = remove(buf); - } - } - - free(buf); - } - - r = r2; - } +int remove_all_aux(const char* path, const struct stat* stat, int flags, struct FTW* ftw) { + return remove(path); +} - closedir(d); +int remove_all(const char* path) { + struct stat st; + if (stat(path, &st) != 0) { + return remove(path); } - - if (!r) { - r = rmdir(path); + if (S_ISDIR(st.st_mode)) { + return nftw(path, remove_all_aux, 32, FTW_DEPTH | FTW_PHYS); + } else { + return remove(path); } - - return r; } -// Deletes a directory at the specified path. If recursive is True, +// Removes any file or directory recursively at the specified path. // it will delete the directory and all its contents. // Returns Ok(None) if successful, or Err(reason) if an error occurs. // Note: For non-recursive deletion of an empty directory, // this function behaves the same as delete_file(path). // Returns: Result<*, IOError> -Port io_delete_directory(Net* net, Book* book, Port argm) { - Tup tup = readback_tup(net, book, argm, 2); - if (2 != tup.elem_len) { - return inject_io_err_type(net); - } - - Str path = readback_str(net, book, tup.elem_buf[0]); - u32 rec = get_u24(get_val(tup.elem_buf[1])); +Port io_remove_all(Net* net, Book* book, Port argm) { + Str path = readback_str(net, book, argm); - int res; - if (rec) { - res = delete_directory_recursive(path.buf); - } else { - res = rmdir(path.buf); - } + int res = remove_all(path.buf); free(path.buf); if (0 == res) { @@ -848,8 +804,8 @@ void book_init(Book* book) { book->ffns_buf[book->ffns_len++] = (FFn){"DL_OPEN", io_dl_open}; book->ffns_buf[book->ffns_len++] = (FFn){"DL_CALL", io_dl_call}; book->ffns_buf[book->ffns_len++] = (FFn){"DL_CLOSE", io_dl_open}; - book->ffns_buf[book->ffns_len++] = (FFn){"DELETE_FILE", io_delete_file}; - book->ffns_buf[book->ffns_len++] = (FFn){"DELETE_DIRECTORY", io_delete_directory}; + book->ffns_buf[book->ffns_len++] = (FFn){"RM", io_remove}; + book->ffns_buf[book->ffns_len++] = (FFn){"RM_ALL", io_remove_all}; book->ffns_buf[book->ffns_len++] = (FFn){"MKDIR", io_mkdir}; } diff --git a/src/run.cu b/src/run.cu index 5fae3ddd..2ebf4930 100644 --- a/src/run.cu +++ b/src/run.cu @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "hvm.cu" // Readback: λ-Encoded Ctr @@ -838,12 +838,12 @@ Port io_dl_close(GNet* gnet, Book* book, Port argm) { return gnet_inject_ok(gnet, new_port(ERA, 0)); } -// Deletes a single file or an empty directory at the specified path. +// Removes a single file or an empty directory at the specified path. // Returns Ok(None) if successful, or Err(reason) if an error occurs. // This function attempts to remove both files and empty directories without // first checking the type of the path. // Returns: Result<*, IOError> -Port io_delete_file(GNet* gnet, Port argm) { +Port io_remove(GNet* gnet, Port argm) { Str s = gnet_readback_str(gnet, argm); int result = remove(s.buf); @@ -856,80 +856,35 @@ Port io_delete_file(GNet* gnet, Port argm) { } } -int delete_directory_recursive(const char* path) { - DIR* d = opendir(path); - size_t path_len = strlen(path); - int r = -1; - - if (d) { - struct dirent *p; - r = 0; - - while (!r && (p = readdir(d))) { - int r2 = -1; - char* buf; - size_t len; - - if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { - continue; - } - - len = path_len + strlen(p->d_name) + 2; - buf = (char*) malloc(len); - - if (buf) { - struct stat statbuf; - snprintf(buf, len, "%s/%s", path, p->d_name); - - if (!stat(buf, &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) { - r2 = delete_directory_recursive(buf); - } else { - r2 = remove(buf); - } - } - - free(buf); - } - - r = r2; - } +int remove_all_aux(const char* path, const struct stat* stat, int flags, struct FTW* ftw) { + return remove(path); +} - closedir(d); +int remove_all(const char* path) { + struct stat st; + if (stat(path, &st) != 0) { + return remove(path); } - - if (!r) { - r = rmdir(path); + if (S_ISDIR(st.st_mode)) { + return nftw(path, remove_all_aux, 32, FTW_DEPTH | FTW_PHYS); + } else { + return remove(path); } - - return r; } -// Deletes a directory at the specified path. If recursive is True, +// Removes any file or directory recursively at the specified path. // it will delete the directory and all its contents. // Returns Ok(None) if successful, or Err(reason) if an error occurs. // Note: For non-recursive deletion of an empty directory, // this function behaves the same as delete_file(path). // Returns: Result<*, IOError> -Port io_delete_directory(GNet* gnet, Port argm) { - Tup tup = gnet_readback_tup(gnet, argm, 2); - if (tup.elem_len != 2) { - fprintf(stderr, "io_delete_directory: expected tuple\n"); - - return gnet_inject_io_err_type(gnet); - } - - Str path = gnet_readback_str(gnet, tup.elem_buf[0]); - u32 rec = get_u24(get_val(tup.elem_buf[1])); - int res; - if (rec) { - res = delete_directory_recursive(path.buf); - } else { - res = rmdir(path.buf); - } +Port io_remove_all(GNet* gnet, Port argm) { + Str path = gnet_readback_str(gnet, argm); + + int res = remove_all(path.buf); free(path.buf); - if (res == 0) { + if (0 == res) { return gnet_inject_ok(gnet, new_port(ERA, 0)); } else { return gnet_inject_io_err_inner(gnet, new_port(NUM, new_i24(errno))); @@ -943,10 +898,10 @@ Port io_mkdir(GNet* gnet, Port argm) { Str name = gnet_readback_str(gnet, argm); const mode_t mode = 0777; - int result = mkdir(name.buf, mode); + int status = mkdir(name.buf, mode); free(name.buf); - if (result) { + if (status) { return gnet_inject_io_err_inner(gnet, new_port(NUM, new_i24(errno))); } else { return gnet_inject_ok(gnet, new_port(ERA, 0)); @@ -965,8 +920,8 @@ void book_init(Book* book) { book->ffns_buf[book->ffns_len++] = (FFn){"DL_OPEN", io_dl_open}; book->ffns_buf[book->ffns_len++] = (FFn){"DL_CALL", io_dl_call}; book->ffns_buf[book->ffns_len++] = (FFn){"DL_CLOSE", io_dl_open}; - book->ffns_buf[book->ffns_len++] = (FFn){"DELETE_FILE", io_delete_file}; - book->ffns_buf[book->ffns_len++] = (FFn){"DELETE_DIRECTORY", io_delete_directory}; + book->ffns_buf[book->ffns_len++] = (FFn){"RM", io_remove}; + book->ffns_buf[book->ffns_len++] = (FFn){"RM_ALL", io_remove_all}; book->ffns_buf[book->ffns_len++] = (FFn){"MKDIR", io_mkdir}; cudaMemcpyToSymbol(BOOK, book, sizeof(Book)); diff --git a/tests/programs/io/create_directory.bend b/tests/programs/io/create_directory.bend deleted file mode 100644 index e88b4ee9..00000000 --- a/tests/programs/io/create_directory.bend +++ /dev/null @@ -1,21 +0,0 @@ -#{ - Creates the batata directory and then deletes it. -#} - -test-io = 1 - -IO/FS/mkdir path = - (call "MKDIR" path) - -IO/FS/delete_directory path recursive = - (call "DELETE_DIRECTORY" (path, recursive)) - -False = 0 - -main = - let path = "./batata" - with IO { - ask * = (IO/FS/mkdir path) - ask s = (IO/FS/delete_directory path False) - (wrap s) - } diff --git a/tests/programs/io/delete_dir_file.bend b/tests/programs/io/delete_dir_file.bend deleted file mode 100644 index 537e95c6..00000000 --- a/tests/programs/io/delete_dir_file.bend +++ /dev/null @@ -1,16 +0,0 @@ -#{ - Calls the delete_directory function with a file path as argument. -#} - -test-io = 1 - -IO/FS/delete_directory path recursive = - (call "DELETE_DIRECTORY" (path, recursive)) - -False = 0 - -main = - with IO { - ask s = (IO/FS/delete_directory "./delete_dir_file.bend" False) - (wrap s) - } diff --git a/tests/programs/io/delete_empty_dir.bend b/tests/programs/io/delete_empty_dir.bend deleted file mode 100644 index 9e50d2d1..00000000 --- a/tests/programs/io/delete_empty_dir.bend +++ /dev/null @@ -1,18 +0,0 @@ -#{ - Uses the delete_file function to delete an empty directory. -#} - -test-io = 1 - -IO/FS/mkdir path = - (call "MKDIR" path) - -IO/FS/delete_file path = - (call "DELETE_FILE" path) - -main = - with IO { - ask * = (IO/FS/mkdir "temp") - ask s = (IO/FS/delete_file "temp") - (wrap s) - } diff --git a/tests/programs/io/delete_non_existing_file.bend b/tests/programs/io/delete_non_existing_file.bend deleted file mode 100644 index 219d5972..00000000 --- a/tests/programs/io/delete_non_existing_file.bend +++ /dev/null @@ -1,15 +0,0 @@ -#{ - Tries to delete a non existing file. -#} - -test-io = 1 - -IO/FS/delete_file path = - (call "DELETE_FILE" path) - -main = - use path = "./non_existing.txt" - with IO { - ask s = (IO/FS/delete_file path) - (wrap s) - } diff --git a/tests/programs/io/mkdir.bend b/tests/programs/io/mkdir.bend new file mode 100644 index 00000000..38f2ba7b --- /dev/null +++ b/tests/programs/io/mkdir.bend @@ -0,0 +1,19 @@ +#{ + Creates the batata directory and then removes it. +#} + +test-io = 1 + +mkdir path = + (call "MKDIR" path) + +rm_all path = + (call "RM_ALL" path) + +main = + let path = "./batata" + with IO { + ask * = (mkdir path) + ask s = (rm_all path) + (wrap s) + } diff --git a/tests/programs/io/remove_all_file.bend b/tests/programs/io/remove_all_file.bend new file mode 100644 index 00000000..ca2d96bf --- /dev/null +++ b/tests/programs/io/remove_all_file.bend @@ -0,0 +1,16 @@ +#{ + Calls the rm_all function with a file path as argument. +#} + +test-io = 1 + +rm_all path = + (call "RM_ALL" path) + +main = + let temp = "./temp.txt" + with IO { + ask * = (IO/FS/write_file temp (String/encode_utf8 "Contents")) + ask s = (rm_all temp) + (wrap s) + } diff --git a/tests/programs/io/delete_dir_recursive.bend b/tests/programs/io/remove_all_recursive.bend similarity index 53% rename from tests/programs/io/delete_dir_recursive.bend rename to tests/programs/io/remove_all_recursive.bend index 6e9a859a..17c3a709 100644 --- a/tests/programs/io/delete_dir_recursive.bend +++ b/tests/programs/io/remove_all_recursive.bend @@ -1,5 +1,5 @@ #{ - Creates the following tree structure and then deletes A and its children. + Creates the following tree structure and then removes A and its children. A |-- a.txt |-- AA @@ -10,23 +10,26 @@ test-io = 1 -IO/FS/mkdir path = +mkdir path = (call "MKDIR" path) -IO/FS/delete_directory path recursive = - (call "DELETE_DIRECTORY" (path, recursive)) +rm_all path = + (call "RM_ALL" path) -True = 1 - -main = +test = with IO { - ask * = (IO/FS/mkdir "A") - ask * = (IO/FS/mkdir "A/AA") - ask * = (IO/FS/mkdir "A/AB") + ask * = (mkdir "A") + ask * = (mkdir "A/AA") + ask * = (mkdir "A/AB") ask * = (IO/FS/write_file "A/a.txt" (String/encode_utf8 "a")) ask * = (IO/FS/write_file "A/AA/aa.txt" (String/encode_utf8 "aa")) ask * = (IO/FS/write_file "A/AB/ab.txt" (String/encode_utf8 "ab")) - - ask s = (IO/FS/delete_directory "A" True) + ask s = (rm_all "./A") (wrap s) } + +main = + with IO { + ask res = (test) + (wrap res) + } diff --git a/tests/programs/io/remove_empty_dir.bend b/tests/programs/io/remove_empty_dir.bend new file mode 100644 index 00000000..94f9507e --- /dev/null +++ b/tests/programs/io/remove_empty_dir.bend @@ -0,0 +1,18 @@ +#{ + Uses the rm function to remove an empty directory. +#} + +test-io = 1 + +mkdir path = + (call "MKDIR" path) + +rm path = + (call "RM" path) + +main = + with IO { + ask * = (mkdir "temp") + ask s = (rm "temp") + (wrap s) + } diff --git a/tests/programs/io/delete_file.bend b/tests/programs/io/remove_file.bend similarity index 52% rename from tests/programs/io/delete_file.bend rename to tests/programs/io/remove_file.bend index 6f47ed29..e36fe6f5 100644 --- a/tests/programs/io/delete_file.bend +++ b/tests/programs/io/remove_file.bend @@ -1,16 +1,16 @@ #{ - Creates a temporary file and then deletes it. + Creates a temporary file and then removes it. #} test-io = 1 -IO/FS/delete_file path = - (call "DELETE_FILE" path) +rm path = + (call "RM" path) main = let path = "./temp.txt" with IO { ask * = (IO/FS/write_file path (String/encode_utf8 "Contents")) - ask s = (IO/FS/delete_file path) + ask s = (rm path) (wrap s) } diff --git a/tests/programs/io/remove_non_existing_file.bend b/tests/programs/io/remove_non_existing_file.bend new file mode 100644 index 00000000..5072b091 --- /dev/null +++ b/tests/programs/io/remove_non_existing_file.bend @@ -0,0 +1,15 @@ +#{ + Tries to remove a non existing file. +#} + +test-io = 1 + +rm path = + (call "RM" path) + +main = + use path = "./non_existing.txt" + with IO { + ask s = (rm path) + (wrap s) + }