/** * SPDX-License-Identifier: Apache-2.0 * * @file libredundancyfileop.c * @brief The redundancy file operation library */ #include "fileop.h" #include "librefop.h" #include #include #include #include #include #include const char c_bk1_suffix[] = ".bk1"; const char c_new_suffix[] = ".tmp"; /** * The refop handle create function. * When you use refop, you shall call this function initially. * The refop handle need to create per one file. * * @param [out] handle Created refop handle * @param [in] directry Terget directry * @param [in] filename Target file name. * * @return refop_error_t * @retval REFOP_SUCCESS This operation was succeeded. * @retval REFOP_NOENT The target file/directroy was nothing. * @retval REFOP_ARGERROR Argument error. * @retval REFOP_SYSERROR Internal operation was failed such as no memory, no disk space and etc. */ refop_error_t refop_create_redundancy_handle(refop_handle_t *handle, const char *directry, const char *filename) { struct stat sb; struct refop_halndle *hndl = NULL; int ret = -1; size_t dirlen = 0, filelen = 0; refop_error_t refop_error = REFOP_SYSERROR; if ((handle == NULL) || (directry == NULL) || (filename == NULL)) return REFOP_ARGERROR; // Check a directry ret = stat(directry, &sb); if (ret < 0) { if ((errno == EACCES) || (errno == ELOOP) || (errno == ENOENT) || (errno == ENOTDIR)) return REFOP_NOENT; else if (errno == ENAMETOOLONG) return REFOP_ARGERROR; else return REFOP_SYSERROR; } // Handle memory allocate hndl = (struct refop_halndle *) malloc(sizeof(struct refop_halndle)); if (hndl == NULL) return REFOP_SYSERROR; memset(hndl, 0, sizeof(struct refop_halndle)); // Create file path dirlen = strnlen(directry, PATH_MAX); filelen = strnlen(filename, PATH_MAX); if ((dirlen + filelen + 10 + 1) > PATH_MAX || (dirlen == 0) || (filelen == 0)) { // file suffix = max 10 byte, / = max 1 byte // Path error free(hndl); return REFOP_ARGERROR; } // string length was checked, safe. (void) strncpy(hndl->latestfile, directry, PATH_MAX); if (hndl->latestfile[dirlen - 1] != '/') (void) strcat(hndl->latestfile, "/"); (void) strncpy(hndl->basedir, hndl->latestfile, PATH_MAX); (void) strcat(hndl->latestfile, filename); (void) strncpy(hndl->backupfile1, hndl->latestfile, PATH_MAX); (void) strcat(hndl->backupfile1, c_bk1_suffix); (void) strncpy(hndl->newfile, hndl->latestfile, PATH_MAX); (void) strcat(hndl->newfile, c_new_suffix); (*handle) = hndl; return REFOP_SUCCESS; } /** * The refop handle release function. * When you completed refop operation, you shall call this release function to release allocated memory. * * @param [in] handle Refop handle * * @return refop_error_t * @retval REFOP_SUCCESS This operation was succeeded. * @retval REFOP_ARGERROR Argument error. */ refop_error_t refop_release_redundancy_handle(refop_handle_t handle) { if (handle == NULL) return REFOP_ARGERROR; free(handle); return REFOP_SUCCESS; } /** * The data set function of refop. * When you want to write file, you call this function. * This function is not support partial and append write,only to support all overwrite for file. * If you write new data smaller than existing data, new data file truncated to new data file size. * This function is not support multi threaded set and get with same handle. * In case of multi threaded set and get using separate handle, these operation is support. * * @param [in] handle Refop handle * @param [in] data Write data for set data. * @param [in] datasize Write data size (byte). * * @return refop_error_t * @retval REFOP_SUCCESS This operation was succeeded. * @retval REFOP_ARGERROR Argument error. * @retval REFOP_SYSERROR Internal operation was failed such as no memory, no disk space and etc. */ refop_error_t refop_set_redundancy_data(refop_handle_t handle, uint8_t *data, int64_t datasize) { struct refop_halndle *hndl = (struct refop_halndle *) handle; int ret = -1; if (handle == NULL || data == NULL || datasize < 0) return REFOP_ARGERROR; ret = refop_new_file_write(handle, data, datasize); if (ret < 0) { if (ret == -1) return REFOP_SYSERROR; else return REFOP_ARGERROR; } ret = refop_file_rotation(handle); if (ret < 0) { (void) unlink(hndl->newfile); return REFOP_SYSERROR; } return REFOP_SUCCESS; } /** * The data get function of refop. * When you want to read file, you call this function. * When you set data size that smaller than existing file, this function read requested data size. * When you set data size that larger than existing file, this function read existing file data size. * How many data was reading, this function set to getsize. * This function is not support multi threaded set and get with same handle. * In case of multi threaded set and get using separate handle, these operation is support. * * @param [in] handle Refop handle * @param [in] data Read buffer for get data. * @param [in] datasize Read buffer size (byte). * @param [out] getsize Readed size (byte). * * @return refop_error_t * @retval REFOP_SUCCESS This operation was succeeded. * @retval REFOP_RECOVER This operation was succeeded within recovery. * @retval REFOP_NOENT The target file/directroy was nothing. * @retval REFOP_BROAKEN This operation was failed. Because all recovery method was failed. * @retval REFOP_ARGERROR Argument error. * @retval REFOP_SYSERROR Internal operation was failed such as no memory, no disk space and etc. */ refop_error_t refop_get_redundancy_data(refop_handle_t handle, uint8_t *data, int64_t datasize, int64_t *getsize) { refop_error_t result = REFOP_SYSERROR; int ret = -1; if (handle == NULL || data == NULL || datasize < 0 || getsize == NULL) return REFOP_ARGERROR; ret = refop_file_pickup(handle, data, datasize, getsize); if (ret == 0) result = REFOP_SUCCESS; else if (ret == 1) result = REFOP_RECOVER; else if (ret == -2) result = REFOP_NOENT; else if (ret == -3) result = REFOP_BROAKEN; else result = REFOP_SYSERROR; return result; } /** * The function of refop all file clean. * * @param [in] handle refop handle * * @return refop_error_t * @retval REFOP_SUCCESS This operation was succeeded. * @retval REFOP_ARGERROR Argument error. * @retval REFOP_SYSERROR Internal operation was failed such as no memory, no disk space and etc. */ refop_error_t refop_remove_redundancy_data(refop_handle_t handle) { struct refop_halndle *hndl = (struct refop_halndle *) handle; refop_error_t errorret = REFOP_SUCCESS; int ret = -1; if (handle == NULL) return REFOP_ARGERROR; ret = unlink(hndl->newfile); if (ret < 0) { if (errno != ENOENT) errorret = REFOP_SYSERROR; } ret = unlink(hndl->latestfile); if (ret < 0) { if (errno != ENOENT) errorret = REFOP_SYSERROR; } ret = unlink(hndl->backupfile1); if (ret < 0) { if (errno != ENOENT) errorret = REFOP_SYSERROR; } return errorret; }