From 920f4d6b249c198863b1935b189ccbfae517228d Mon Sep 17 00:00:00 2001 From: WaLyong Cho Date: Tue, 15 Nov 2016 17:12:06 +0900 Subject: libsystem: introduce do_cp_force() and do_cp_mode_force() The origin do_cp() and do_cp_mode() always overwrite the destination file. It does not make sense. So check the destination file exists, if yes, return -EALREADY. And to support force overwrite, add new do_cp_force() and do_cp_mode_force(). Those does not check the destination file exist. Change-Id: I9b0936f15195b737c4701bf1fa64ce49124873ce Signed-off-by: WaLyong Cho --- src/libsystem/libsystem.c | 45 +++++++++++++++++++++++++++++++++++++++------ src/libsystem/libsystem.h | 33 ++++++++++++++++++++++++++++++--- src/test/test-cp.c | 19 ++++++++++++++----- 3 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/libsystem/libsystem.c b/src/libsystem/libsystem.c index fc704f9..cb74b34 100644 --- a/src/libsystem/libsystem.c +++ b/src/libsystem/libsystem.c @@ -424,22 +424,31 @@ int do_copy(const char *src, const char *dst, const char *option, int64_t timeou return do_fork_exec(argv, NULL, timeout_msec); } -int do_cp_mode(const char *src, const char *dst, mode_t mode) { +static int do_cp_internal(const char *src, const char *dst, mode_t mode, bool force) { _cleanup_close_ int rfd = -1, wfd = -1; - ssize_t red; char buf[1024]; + ssize_t red; + int r; assert(src); assert(dst); - rfd = open(src, O_RDONLY); - if (rfd < 0) - return -errno; + if (!force) { + r = access(dst, F_OK); + if (r == 0) + return -EALREADY; + else if (errno != ENOENT) + return -errno; + } wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode); if (wfd < 0) return -errno; + rfd = open(src, O_RDONLY); + if (rfd < 0) + return -errno; + while ((red = read(rfd, buf, 1024)) > 0) if (write(wfd, buf, red) != red) return -errno; @@ -450,12 +459,36 @@ int do_cp_mode(const char *src, const char *dst, mode_t mode) { return 0; } +int do_cp_mode(const char *src, const char *dst, mode_t mode) { + + assert(src); + assert(dst); + + return do_cp_internal(src, dst, mode, false); +} + +int do_cp_mode_force(const char *src, const char *dst, mode_t mode) { + + assert(src); + assert(dst); + + return do_cp_internal(src, dst, mode, true); +} + int do_cp(const char *src, const char *dst) { assert(src); assert(dst); - return do_cp_mode(src, dst, 0644); + return do_cp_internal(src, dst, 0644, false); +} + +int do_cp_force(const char *src, const char *dst) { + + assert(src); + assert(dst); + + return do_cp_internal(src, dst, 0644, true); } int do_mkdir(const char *path, mode_t mode) { diff --git a/src/libsystem/libsystem.h b/src/libsystem/libsystem.h index 9b0bd1e..a6ed0db 100644 --- a/src/libsystem/libsystem.h +++ b/src/libsystem/libsystem.h @@ -274,26 +274,53 @@ bool is_number(const char *s, int l); int do_copy(const char *src, const char *dst, const char *option, int64_t timeout_msec); /** - * @brief copy a file with mode + * @brief copy a file with mode, if destination file exists, return + * error. * * @param src source file path * @param dst destination file path * @param mode destination file mode * - * @return 0 on success, -errno on failure. + * @return 0 on success, -errno on failure. -EALREADY if destination + * file exist. */ int do_cp_mode(const char *src, const char *dst, mode_t mode); /** - * @brief copy a file, destination file mode is 0644 + * @brief copy a file with mode, if destination file exists, the file + * is overwritten. * * @param src source file path * @param dst destination file path + * @param mode destination file mode * * @return 0 on success, -errno on failure. */ +int do_cp_mode_force(const char *src, const char *dst, mode_t mode); + +/** + * @brief copy a file, destination file mode is 0644, if destination + * file exist, return error. + * + * @param src source file path + * @param dst destination file path + * + * @return 0 on success, -errno on failure. -EALREADY if destination + * file exist. + */ int do_cp(const char *src, const char *dst); +/** + * @brief copy a file, destination file mode is 0644, if destination + * file exist, the file is overwritten. + * + * @param src source file path + * @param dst destination file path + * + * @return 0 on success, -errno on failure. + */ +int do_cp_force(const char *src, const char *dst); + /** * @brief Make a directory. If parent directories are also absent, * make them also. Corresponding with "mkdir -p". diff --git a/src/test/test-cp.c b/src/test/test-cp.c index c875cca..532dee7 100644 --- a/src/test/test-cp.c +++ b/src/test/test-cp.c @@ -106,22 +106,31 @@ static void compare_file(void) { } } -static void test_n_byte_cp(unsigned int n) { +static void test_overwite(void) { assert(unlink(TEST_SRC_FILE) == 0 || errno == ENOENT); + assert(unlink(TEST_DST_FILE) == 0 || errno == ENOENT); - assert(unlink(TEST_SRC_FILE) == 0 || errno == ENOENT); + assert(touch(TEST_SRC_FILE) == 0); + assert(touch(TEST_DST_FILE) == 0); + + assert(do_cp(TEST_SRC_FILE, TEST_DST_FILE) == -EALREADY); + assert(do_cp_force(TEST_SRC_FILE, TEST_DST_FILE) == 0); + compare_file(); +} +static void test_n_byte_cp_force(unsigned int n) { assert(write_src_file(n) == 0); - assert(do_cp(TEST_SRC_FILE, TEST_DST_FILE) == 0); + assert(do_cp_force(TEST_SRC_FILE, TEST_DST_FILE) == 0); compare_file(); } int main(int argc, char *argv[]) { - unsigned int b; + test_overwite(); + for (b = 8; b < (1 << 30); b = b << 1) - test_n_byte_cp(b); + test_n_byte_cp_force(b); unlink(TEST_SRC_FILE); unlink(TEST_DST_FILE); -- cgit v1.2.3