summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am9
-rw-r--r--src/libsystem/libsystem.c35
-rw-r--r--src/libsystem/libsystem.h21
-rw-r--r--src/test/test-cp.c130
4 files changed, 195 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 9378c18..48ad051 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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
diff --git a/src/libsystem/libsystem.c b/src/libsystem/libsystem.c
index f87dfa0..fc704f9 100644
--- a/src/libsystem/libsystem.c
+++ b/src/libsystem/libsystem.c
@@ -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;
diff --git a/src/libsystem/libsystem.h b/src/libsystem/libsystem.h
index 631a216..9b0bd1e 100644
--- a/src/libsystem/libsystem.h
+++ b/src/libsystem/libsystem.h
@@ -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
index 0000000..c875cca
--- /dev/null
+++ b/src/test/test-cp.c
@@ -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;
+}