libsystem: introduce do_cp() and do_cp_mode()
authorWaLyong Cho <walyong.cho@samsung.com>
Tue, 15 Nov 2016 04:49:53 +0000 (13:49 +0900)
committerWaLyong Cho <walyong.cho@samsung.com>
Tue, 15 Nov 2016 05:12:40 +0000 (14:12 +0900)
(This is the first step to remove do_copy() which is invoking
"/bin/cp" directly.)

Add new two file copy api.
- do_cp_mode(): copy src file to dst file with given mode.
- do_cp(): same with do_cp_mode(), but mode is 0644.

Change-Id: I6a1bada8de677b64886ed0c6b0b16cf80d57459c
Signed-off-by: WaLyong Cho <walyong.cho@samsung.com>
src/Makefile.am
src/libsystem/libsystem.c
src/libsystem/libsystem.h
src/test/test-cp.c [new file with mode: 0644]

index 9378c18..48ad051 100644 (file)
@@ -104,6 +104,15 @@ test_exec_LDADD = \
 tests += test-exec
 
 # ------------------------------------------------------------------------------
+test_cp_SOURCES = \
+       test/test-cp.c
+
+test_cp_LDADD = \
+       libsystem.la
+
+tests += test-cp
+
+# ------------------------------------------------------------------------------
 pkgconfiglib_DATA += \
        libsystem-sd/libsystem-sd.pc
 
index f87dfa0..fc704f9 100644 (file)
@@ -26,6 +26,7 @@
 #include <ctype.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <mntent.h>
 
 #include "libsystem.h"
@@ -423,6 +424,40 @@ 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) {
+        _cleanup_close_ int rfd = -1, wfd = -1;
+        ssize_t red;
+        char buf[1024];
+
+        assert(src);
+        assert(dst);
+
+        rfd = open(src, O_RDONLY);
+        if (rfd < 0)
+                return -errno;
+
+        wfd = open(dst, O_CREAT | O_WRONLY | O_TRUNC, mode);
+        if (wfd < 0)
+                return -errno;
+
+        while ((red = read(rfd, buf, 1024)) > 0)
+                if (write(wfd, buf, red) != red)
+                        return -errno;
+
+        if (red < 0)
+                return -errno;
+
+        return 0;
+}
+
+int do_cp(const char *src, const char *dst) {
+
+        assert(src);
+        assert(dst);
+
+        return do_cp_mode(src, dst, 0644);
+}
+
 int do_mkdir(const char *path, mode_t mode) {
         char d[PATH_MAX];
         size_t s, l;
index 631a216..9b0bd1e 100644 (file)
@@ -274,6 +274,27 @@ 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
+ *
+ * @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(const char *src, const char *dst, mode_t mode);
+
+/**
+ * @brief copy a file, destination file mode is 0644
+ *
+ * @param src source file path
+ * @param dst destination file path
+ *
+ * @return 0 on success, -errno on failure.
+ */
+int do_cp(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
new file mode 100644 (file)
index 0000000..c875cca
--- /dev/null
@@ -0,0 +1,130 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+
+#include "libsystem/libsystem.h"
+
+#define TEST_SRC_FILE "/tmp/test-cp-src"
+#define TEST_DST_FILE "/tmp/test-cp-dst"
+
+static int random_char(char **buf, size_t len) {
+        static int rand_init = 0;
+        char *b;
+        int rnd;
+        size_t s;
+
+        if (!rand_init) {
+                srand(time(NULL));
+                rand_init = 1;
+        }
+
+        b = new0(char, len);
+        if (!b)
+                return -ENOMEM;
+
+        for (s = 0; s < len; s++) {
+
+                /* 98 = number_of_chars((sp) ~ (DEL) + \t + \n + \r) */
+                rnd = rand() % 98;
+
+                assert(rnd < 98);
+
+                switch (rnd) {
+                case 95:
+                        b[s] = '\t';
+                        break;
+                case 96:
+                        b[s] = '\n';
+                        break;
+                case 97:
+                        b[s] = '\r';
+                        break;
+                default:
+                        b[s] = ' ' + rnd;
+                        break;
+                }
+        }
+
+        *buf = b;
+
+        return 0;
+}
+
+static int write_src_file(unsigned int n_byte) {
+        _cleanup_free_ char *buf = NULL;
+        _cleanup_close_ int fd = -1;
+
+        assert(random_char(&buf, n_byte) == 0);
+
+        fd = open(TEST_SRC_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
+        assert(fd >= 0);
+        assert(write(fd, buf, n_byte) == n_byte);
+
+        return 0;
+}
+
+static void compare_file(void) {
+        _cleanup_close_ int src_fd = -1, dst_fd = -1;
+        char src_buf[1024], dst_buf[1024];
+        ssize_t src_red, dst_red;
+
+        src_fd = open(TEST_SRC_FILE, O_RDONLY);
+        assert(src_fd >= 0);
+
+        dst_fd = open(TEST_DST_FILE, O_RDONLY);
+        assert(dst_fd >= 0);
+
+        while(src_red = read(src_fd, src_buf, 1024) > 0,
+              dst_red = read(dst_fd, dst_buf, 1024) > 0) {
+                assert(src_red == dst_red);
+                assert(memcmp(src_buf, dst_buf, src_red) == 0);
+        }
+}
+
+static void test_n_byte_cp(unsigned int n) {
+        assert(unlink(TEST_SRC_FILE) == 0 || errno == ENOENT);
+
+        assert(unlink(TEST_SRC_FILE) == 0 || errno == ENOENT);
+
+        assert(write_src_file(n) == 0);
+        assert(do_cp(TEST_SRC_FILE, TEST_DST_FILE) == 0);
+        compare_file();
+}
+
+int main(int argc, char *argv[]) {
+
+        unsigned int b;
+
+        for (b = 8; b < (1 << 30); b = b << 1)
+                test_n_byte_cp(b);
+
+        unlink(TEST_SRC_FILE);
+        unlink(TEST_DST_FILE);
+
+        return 0;
+}