summaryrefslogtreecommitdiff
path: root/src/libstddjb
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-02-23 23:28:33 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-02-23 23:28:33 +0000
commit7bfdb8092915753c42f9f06a56fbbc46b11e593e (patch)
treef6b914f3fcaf2c0c8b25edd10424c679f2d52cf4 /src/libstddjb
parent1cdd5c6f695be300527dace93b8a81c66ceadad8 (diff)
downloadskalibs-2.3.1.0.tar.xz
Add hiercopy and hiercopy_tmpv2.3.1.0
Diffstat (limited to 'src/libstddjb')
-rw-r--r--src/libstddjb/hiercopy.c9
-rw-r--r--src/libstddjb/hiercopy_tmp.c145
2 files changed, 154 insertions, 0 deletions
diff --git a/src/libstddjb/hiercopy.c b/src/libstddjb/hiercopy.c
new file mode 100644
index 0000000..34f027e
--- /dev/null
+++ b/src/libstddjb/hiercopy.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+
+int hiercopy (char const *src, char const *dst)
+{
+ return hiercopy_tmp(src, dst, &satmp) ;
+}
diff --git a/src/libstddjb/hiercopy_tmp.c b/src/libstddjb/hiercopy_tmp.c
new file mode 100644
index 0000000..ce2282f
--- /dev/null
+++ b/src/libstddjb/hiercopy_tmp.c
@@ -0,0 +1,145 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/direntry.h>
+#include <skalibs/djbunix.h>
+
+static int filecopy (char const *src, char const *dst, mode_t mode)
+{
+ int d ;
+ int s = open_readb(src) ;
+ if (s < 0) return 0 ;
+ d = open3(dst, O_WRONLY | O_CREAT | O_TRUNC, mode) ;
+ if (d < 0)
+ {
+ fd_close(s) ;
+ return 0 ;
+ }
+ if (fd_cat(s, d) < 0) goto err ;
+ fd_close(s) ;
+ fd_close(d) ;
+ return 1 ;
+
+err:
+ {
+ register int e = errno ;
+ fd_close(s) ;
+ fd_close(d) ;
+ errno = e ;
+ }
+ return 0 ;
+}
+
+static int dircopy (char const *src, char const *dst, mode_t mode, stralloc *tmp)
+{
+ unsigned int tmpbase = tmp->len ;
+ unsigned int maxlen = 0 ;
+ {
+ DIR *dir = opendir(src) ;
+ if (!dir) return 0 ;
+ for (;;)
+ {
+ direntry *d ;
+ register unsigned int n ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.')
+ if (((d->d_name[1] == '.') && !d->d_name[2]) || !d->d_name[1])
+ continue ;
+ n = str_len(d->d_name) ;
+ if (n > maxlen) maxlen = n ;
+ if (!stralloc_catb(tmp, d->d_name, n+1)) break ;
+ }
+ if (errno)
+ {
+ int e = errno ;
+ dir_close(dir) ;
+ errno = e ;
+ goto err ;
+ }
+ dir_close(dir) ;
+ }
+
+ if (mkdir(dst, S_IRWXU) < 0)
+ {
+ struct stat st ;
+ if (errno != EEXIST) goto err ;
+ if (stat(dst, &st) < 0) goto err ;
+ if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR ; goto err ; }
+ }
+ {
+ unsigned int srclen = str_len(src) ;
+ unsigned int dstlen = str_len(dst) ;
+ unsigned int i = tmpbase ;
+ char srcbuf[srclen + maxlen + 2] ;
+ char dstbuf[dstlen + maxlen + 2] ;
+ byte_copy(srcbuf, srclen, src) ;
+ byte_copy(dstbuf, dstlen, dst) ;
+ srcbuf[srclen] = '/' ;
+ dstbuf[dstlen] = '/' ;
+ while (i < tmp->len)
+ {
+ register unsigned int n = str_len(tmp->s + i) + 1 ;
+ byte_copy(srcbuf + srclen + 1, n, tmp->s + i) ;
+ byte_copy(dstbuf + dstlen + 1, n, tmp->s + i) ;
+ i += n ;
+ hiercopy_tmp(srcbuf, dstbuf, tmp) ;
+ }
+ }
+ if (chmod(dst, mode) < 0) goto err ;
+ tmp->len = tmpbase ;
+ return 1 ;
+err:
+ tmp->len = tmpbase ;
+ return 0 ;
+}
+
+int hiercopy_tmp (char const *src, char const *dst, stralloc *tmp)
+{
+ struct stat st ;
+ if (lstat(src, &st) < 0) return 0 ;
+ if (S_ISREG(st.st_mode))
+ {
+ if (!filecopy(src, dst, st.st_mode)) return 0 ;
+ }
+ else if (S_ISDIR(st.st_mode))
+ {
+ if (!dircopy(src, dst, st.st_mode, tmp)) return 0 ;
+ }
+ else if (S_ISFIFO(st.st_mode))
+ {
+ if (mkfifo(dst, st.st_mode) < 0) return 0 ;
+ }
+ else if (S_ISLNK(st.st_mode))
+ {
+ unsigned int tmpbase = tmp->len ;
+ if (sareadlink(tmp, src) < 0) return 0 ;
+ if (!stralloc_0(tmp))
+ {
+ tmp->len = tmpbase ;
+ return 0 ;
+ }
+ if (symlink(tmp->s + tmpbase, dst) < 0)
+ {
+ tmp->len = tmpbase ;
+ return 0 ;
+ }
+ tmp->len = tmpbase ;
+ }
+ else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISSOCK(st.st_mode))
+ {
+ if (mknod(dst, st.st_mode, st.st_rdev) < 0) return 0 ;
+ }
+ else return (errno = ENOTSUP, 0) ;
+ lchown(dst, st.st_uid, st.st_gid) ;
+ if (!S_ISLNK(st.st_mode)) chmod(dst, st.st_mode) ;
+ return 1 ;
+}