skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

commit 7bfdb8092915753c42f9f06a56fbbc46b11e593e
parent 1cdd5c6f695be300527dace93b8a81c66ceadad8
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Mon, 23 Feb 2015 23:28:33 +0000

 Add hiercopy and hiercopy_tmp

Diffstat:
Mdoc/libstddjb/djbunix.html | 17+++++++++++++++++
Mdoc/upgrade.html | 1+
Mpackage/deps.mak | 2++
Msrc/include/skalibs/djbunix.h | 3+++
Asrc/libstddjb/hiercopy.c | 9+++++++++
Asrc/libstddjb/hiercopy_tmp.c | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/doc/libstddjb/djbunix.html b/doc/libstddjb/djbunix.html @@ -708,6 +708,23 @@ using *<em>tmp</em> as heap-allocated temporary space. Returns 0 if it succeeds or -1 (and sets errno) if it fails. </p> +<h3> Filesystem copy </h3> + +<p> +<code> int hiercopy_tmp (char const *src, char const *dst, stralloc *tmp) </code> <br /> +Recursively copies the filesystem hierarchy at <em>src</em> into +<em>dst</em>, preserving modes, and also preserving the uids/gids if the +process is running as the super-user. +Uses *<em>tmp</em> as heap-allocated temporary space. +Returns 1 if it succeeds or 0 (and sets errno) if it fails. +</p> + +<p> +<code> int hiercopy (char const *src, char const *dst) </code> <br /> +Same as above, using the <tt>satmp</tt> global stralloc as +heap-allocated temporary space. +</p> + <h3> Variable length wrappers around Single Unix calls </h3> <p> diff --git a/doc/upgrade.html b/doc/upgrade.html @@ -22,6 +22,7 @@ <ul> <li> wait_status() now returns 256 + signal number when WIFSIGNALED(). </li> <li> new macro wait_estatus() to get WIFSIGNALED information in an exit code. </li> + <li> new functions in djbunix.h: hiercopy(), hiercopy_tmp() </li> </ul> <h2> in 2.3.0.1 </h2> diff --git a/package/deps.mak b/package/deps.mak @@ -339,6 +339,8 @@ src/libstddjb/genwrite_stdout.o src/libstddjb/genwrite_stdout.lo: src/libstddjb/ src/libstddjb/getlnmax.o src/libstddjb/getlnmax.lo: src/libstddjb/getlnmax.c src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/skamisc.h src/libstddjb/getlnmaxsep.o src/libstddjb/getlnmaxsep.lo: src/libstddjb/getlnmaxsep.c src/include/skalibs/buffer.h src/include/skalibs/bytestr.h src/include/skalibs/skamisc.h src/libstddjb/getpeereid.o src/libstddjb/getpeereid.lo: src/libstddjb/getpeereid.c src/include/skalibs/getpeereid.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h +src/libstddjb/hiercopy.o src/libstddjb/hiercopy.lo: src/libstddjb/hiercopy.c src/include/skalibs/djbunix.h src/include/skalibs/skamisc.h +src/libstddjb/hiercopy_tmp.o src/libstddjb/hiercopy_tmp.lo: src/libstddjb/hiercopy_tmp.c src/include/skalibs/bytestr.h src/include/skalibs/direntry.h src/include/skalibs/djbunix.h src/include/skalibs/stralloc.h src/include/skalibs/strerr2.h src/libstddjb/int_scan.o src/libstddjb/int_scan.lo: src/libstddjb/int_scan.c src/libstddjb/fmtscan-internal.h src/include/skalibs/uint.h src/libstddjb/iobuffer_fill.o src/libstddjb/iobuffer_fill.lo: src/libstddjb/iobuffer_fill.c src/include/skalibs/iobuffer.h src/libstddjb/iobuffer_flush.o src/libstddjb/iobuffer_flush.lo: src/libstddjb/iobuffer_flush.c src/include/skalibs/iobuffer.h diff --git a/src/include/skalibs/djbunix.h b/src/include/skalibs/djbunix.h @@ -142,6 +142,9 @@ extern int rm_rf_in_tmp (stralloc *, unsigned int) ; /* caution ! */ extern int rmstar (char const *) ; extern int rmstar_tmp (char const *, stralloc *) ; +extern int hiercopy (char const *, char const *) ; +extern int hiercopy_tmp (char const *, char const *, stralloc *) ; + /* Simple spawn functions with 0 or 1 communicating fds. */ diff --git a/src/libstddjb/hiercopy.c 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 @@ -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 ; +}