From 5afb5cd8432c01d0e2ba5875b6efcd9b23272706 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Thu, 21 May 2026 20:18:56 +0200 Subject: [PATCH] feat(fs): make and delete temp directories --- pkg/common/CMakeLists.txt | 7 ++-- pkg/common/include/onus/err.h | 11 ++++++ pkg/common/include/onus/int.h | 6 +++ pkg/common/include/onus/str.h | 19 +++++++++ pkg/common/src/str.c | 11 ++++++ pkg/fs/CMakeLists.txt | 10 ++--- pkg/fs/include/onus/fs.h | 40 ++++++++++++++++++- pkg/fs/src/copymove.c | 2 - pkg/fs/src/tmp.c | 74 +++++++++++++++++++++++++++++++++++ 9 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 pkg/common/include/onus/int.h create mode 100644 pkg/common/include/onus/str.h create mode 100644 pkg/common/src/str.c delete mode 100644 pkg/fs/src/copymove.c create mode 100644 pkg/fs/src/tmp.c diff --git a/pkg/common/CMakeLists.txt b/pkg/common/CMakeLists.txt index 2f9d1df..17bc957 100644 --- a/pkg/common/CMakeLists.txt +++ b/pkg/common/CMakeLists.txt @@ -1,3 +1,4 @@ -add_library(onus_common INTERFACE) -add_library(onus::common ALIAS onus_common) -target_include_directories(onus_common INTERFACE include) \ No newline at end of file +add_library(onuscommon) +add_library(onus::common ALIAS onuscommon) +target_sources(onuscommon PRIVATE src/str.c) +target_include_directories(onuscommon PUBLIC include) \ No newline at end of file diff --git a/pkg/common/include/onus/err.h b/pkg/common/include/onus/err.h index 752b6ee..2918b05 100644 --- a/pkg/common/include/onus/err.h +++ b/pkg/common/include/onus/err.h @@ -17,5 +17,16 @@ #define ONUS_E_PERMISSION_ERROR -3 /* Cannot access the specified file because it does not exist */ #define ONUS_E_FILE_NOT_FOUND -4 +/* Cannot copy the string to the buffer because the buffer is too short. Often + * this will still partially copy the data, do not rely on the buffer being + * unmodified in this state */ +#define ONUS_E_BUFFER_TOO_SMALL -5 +/* Generic file system error */ +#define ONUS_E_FS_ERROR -7 + +/* Miscellaneous */ + +/* This function is not supported on the running platform */ +#define ONUS_E_PLATFORM_UNSUPPORTED -6 #endif /* __LIBONUS_ERR_H */ \ No newline at end of file diff --git a/pkg/common/include/onus/int.h b/pkg/common/include/onus/int.h new file mode 100644 index 0000000..80adae0 --- /dev/null +++ b/pkg/common/include/onus/int.h @@ -0,0 +1,6 @@ +#ifndef __LIBONUS_INT_H +#define __LIBONUS_INT_H + +typedef unsigned long onus_size_t; + +#endif /* __LIBONUS_INT_H */ \ No newline at end of file diff --git a/pkg/common/include/onus/str.h b/pkg/common/include/onus/str.h new file mode 100644 index 0000000..e944aaa --- /dev/null +++ b/pkg/common/include/onus/str.h @@ -0,0 +1,19 @@ +#ifndef __LIBONUS_STR_H +#define __LIBONUS_STR_H + +#include "onus/int.h" + +/** + * Copies buffer src into dst with a maximum num characters. If the buffer is + * too small, it is automatically NULL-terminated + * + * @param dst: Destination string buffer + * @param src: Source string buffer + * @param num: Maximum number of characters to copy from src into dst, including + * NULL character + * @returns Size of src, excluding NULL character. This can be compared with num + * to determine whether copying was sucessful + */ +onus_size_t onus_nstrcpy(char *dst, const char *src, onus_size_t num); + +#endif /* __LIBONUS_STR_H */ \ No newline at end of file diff --git a/pkg/common/src/str.c b/pkg/common/src/str.c new file mode 100644 index 0000000..0a3d256 --- /dev/null +++ b/pkg/common/src/str.c @@ -0,0 +1,11 @@ +#include +#include "onus/str.h" + +onus_size_t onus_nstrcpy(char *dst, const char *src, onus_size_t num) { + onus_size_t i = 0; + while (*src != '\0' && i < num) + *dst++ = *src++, i++; + *dst = '\0'; + while(*src++ != '\0') i++; + return i; +} \ No newline at end of file diff --git a/pkg/fs/CMakeLists.txt b/pkg/fs/CMakeLists.txt index 0f89bba..94d6288 100644 --- a/pkg/fs/CMakeLists.txt +++ b/pkg/fs/CMakeLists.txt @@ -1,5 +1,5 @@ -add_library(onus_fs) -add_library(onus::fs ALIAS onus_fs) -target_sources(onus_fs PRIVATE src/copymove.c) -target_include_directories(onus_fs PUBLIC include) -target_link_libraries(onus_fs PRIVATE onus::common) \ No newline at end of file +add_library(onusfs) +add_library(onus::fs ALIAS onusfs) +target_sources(onusfs PRIVATE src/tmp.c) +target_include_directories(onusfs PUBLIC include) +target_link_libraries(onusfs PRIVATE onus::common) \ No newline at end of file diff --git a/pkg/fs/include/onus/fs.h b/pkg/fs/include/onus/fs.h index 2c406d7..a8d9d33 100644 --- a/pkg/fs/include/onus/fs.h +++ b/pkg/fs/include/onus/fs.h @@ -1,6 +1,8 @@ #ifndef __LIBONUS_FS_H #define __LIBONUS_FS_H +#include "onus/int.h" + /** * Copies a file from one location to another, overwriting if necessary * @param src: Path to original file @@ -8,7 +10,7 @@ * @throws ONUS_E_FILE_NOT_FOUND if src does not point to an existing file, or * if dst does not point to a path within an existing directory * @throws ONUS_E_PERMISSION_ERROR if the user does not have permission to read - * src or to write to dst + * src or to write to dst, ONUS_E_FS_ERR for unspecified file system errors * @returns ONUS_SUCCESS on success */ int onus_fs_copy_file(const char *src, const char *dst); @@ -20,9 +22,43 @@ int onus_fs_copy_file(const char *src, const char *dst); * @throws ONUS_E_FILE_NOT_FOUND if src does not point to an existing file, or * if dst does not point to a path within an existing directory * @throws ONUS_E_PERMISSION_ERROR if the user does not have permission to move - * src or to write to dst + * src or to write to dst, ONUS_E_FS_ERR for unspecified file system errors * @returns ONUS_SUCCESS on success */ int onus_fs_move_file(const char *src, const char *dst); +/** + * Creates a temporary file directory for storing user files. Directory name is + * randomly chosen, but may be suffixed to indicate its source + * + * Not all platforms automatically clean temporary directories, so you should + * delete it using onus_fs_del_tmp + * @param path: Output buffer to store temporary file path + * @param path_sz: Size of output path buffer (including NULL character) + * @param suffix: Suffix to add to temporary directory's name. If NULL, no + * suffix will be used + * @returns ONUS_SUCCESS on success, ONUS_E_PERMISSION_ERROR if failed to create + * temporary directory, ONUS_E_FS_ERR for unspecified file system errors, + * ONUS_E_BUFFER_TOO_SMALL if path is not large enough to store the temporary + * file path (May overwrite path anyway), ONUS_E_PLATFORM_UNSUPPORTED if + * creating temporary directories is not supported on this platform + */ +int onus_fs_make_tmp(char *path, onus_size_t path_sz, const char *suffix); + +/** + * Deletes a temporary directory created using onus_fs_make_tmp. Does not + * perform any checks to guarantee it was created using said function. Be + * careful when using as it could erase non-temporary directories if misused. + * (Will not delete files mounted in subdirectories, and will return + * ONUS_E_FS_ERR instead) + * + * Will still return success if the directory is missing, as the user may + * choose to delete it while the program is running + * @param path: Path to temporary directory to delete + * @returns ONUS_SUCCESS if directory was deleted successfully, or no longer + * exists, ONUS_E_PERMISSION_ERROR if failed to delete the requested path, + * ONUS_E_FS_ERR for unspecified file system errors + */ +int onus_fs_del_tmp(const char *path); + #endif /* __LIBONUS_FS_H */ \ No newline at end of file diff --git a/pkg/fs/src/copymove.c b/pkg/fs/src/copymove.c deleted file mode 100644 index e201c72..0000000 --- a/pkg/fs/src/copymove.c +++ /dev/null @@ -1,2 +0,0 @@ -#include "onus/err.h" -#include "onus/fs.h" \ No newline at end of file diff --git a/pkg/fs/src/tmp.c b/pkg/fs/src/tmp.c new file mode 100644 index 0000000..27dfa60 --- /dev/null +++ b/pkg/fs/src/tmp.c @@ -0,0 +1,74 @@ +#define _XOPEN_SOURCE 2008 +#include "onus/err.h" +#include "onus/fs.h" +#include "onus/str.h" +#include +#include +#include +#include +#include + +int onus_fs_make_tmp(char *path, onus_size_t path_sz, const char *suffix) { + char *npath = NULL; + char *tmpname = NULL; + int ret; + + tmpname = malloc(strlen(suffix) + 1 + 6); + sprintf(tmpname, "%sXXXXXX", suffix); + npath = mkdtemp(tmpname); + + if (errno == EACCES) { + ret = ONUS_E_PERMISSION_ERROR; + goto clean; + } else if (errno != 0) { + ret = ONUS_E_FS_ERROR; + goto clean; + } + + if (onus_nstrcpy(path, npath, path_sz) + 1 > path_sz) { + ret = ONUS_E_BUFFER_TOO_SMALL; + goto clean; + } + + ret = ONUS_SUCCESS; +clean: + if (npath) + free(npath); + if (tmpname) + free(tmpname); + return ret; +} + +static int unlink_cb(const char *filename, const struct stat *status, int flag, + struct FTW *info) { + if (!remove(filename)) + return ONUS_E_FS_ERROR; + return 0; +} + +/** + * Deletes a temporary directory created using onus_fs_make_tmp. Does not + * perform any checks to guarantee it was created using said function. Be + * careful when using as it could erase non-temporary directories if misused. + * (Will not delete files mounted in subdirectories, and will return + * ONUS_E_FS_ERR instead) + * + * Will stilll return success if the directory is missing, as the user may + * choose to delete it while the program is running + * @param path: Path to temporary directory to delete + * @returns ONUS_SUCCESS if directory was deleted successfully, or no longer + * exists, ONUS_E_PERMISSION_ERROR if failed to delete the requested path, + * ONUS_E_FS_ERR for unspecified file system errors + */ +int onus_fs_del_tmp(const char *path) { + int err; + + err = nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS | FTW_MOUNT); + + if (!err || err == ENOENT) + return ONUS_SUCCESS; + else if (err == EACCES) + return ONUS_E_PERMISSION_ERROR; + else + return ONUS_E_FS_ERROR; +} \ No newline at end of file