X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib_internal%2Funify-copy.c;fp=lib_internal%2Funify-copy.c;h=a7899158fc44600938bc710007731c935f199fbf;hb=3f3cf95f755f3ef1c31ad8e38153deb4ee214c66;hp=0000000000000000000000000000000000000000;hpb=bfa4b37aaa195007a09bc166e8c8563d5a3c2ef1;p=util-vserver.git diff --git a/lib_internal/unify-copy.c b/lib_internal/unify-copy.c new file mode 100644 index 0000000..a789915 --- /dev/null +++ b/lib_internal/unify-copy.c @@ -0,0 +1,239 @@ +// $Id: unify-copy.c,v 1.6 2005/03/24 12:42:16 ensc Exp $ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "unify.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include + +#define ENSC_WRAPPERS_IO 1 +#include + +#define MMAP_BLOCKSIZE (16 * 1024*1024) + +#ifndef TESTSUITE_COPY_CODE +# define TESTSUITE_COPY_CODE do { } while (false) +#endif + +static inline bool +verifySource(int fd, struct stat const *exp_stat) +{ + struct stat st; + + return (fstat(fd, &st)!=-1 && + st.st_dev==exp_stat->st_dev && + st.st_ino==exp_stat->st_ino); +} + +static inline bool +copyLnk(char const *src, char const *dst) +{ + ssize_t len = 1024; + for (;;) { + char buf[len]; + ssize_t l; + l = readlink(src, buf, len-1); + if (l==-1) return false; + if (l>=len-1) { + len *= 2; + continue; + } + buf[l] = '\0'; + + return (symlink(buf, dst)!=-1); + } +} + +static sigjmp_buf bus_error_restore; +static volatile sig_atomic_t bus_error; + +static void +handlerSIGBUS(int UNUSED num) +{ + bus_error = 1; + siglongjmp(bus_error_restore, 1); +} + +static void +copyMem(void *dst_v, void const *src_v, size_t len_v) +{ +#if 1 + int *dst = dst_v; + int const *src = src_v; + size_t len = len_v / sizeof(int); + size_t rest = len_v - sizeof(int)*len; + size_t i=0; + + for (; i0 && + (lseek(out_fd, in_len-1, SEEK_SET)==-1 || + write(out_fd, "\0", 1)!=1)) // create sparse file + return false; + + bus_error = 0; + if (sigsetjmp(bus_error_restore, 1)==0) { + off_t offset = 0; + + while (offset < in_len) { + buf_size = in_len - offset; + if (buf_size > MMAP_BLOCKSIZE) buf_size = MMAP_BLOCKSIZE; + + if ((in_buf = mmap(0, buf_size, PROT_READ, MAP_SHARED, in_fd, offset))==0 || + (out_buf = mmap(0, buf_size, PROT_WRITE, MAP_SHARED, out_fd, offset))==0) { + perror("mmap()"); + goto out; + } + + offset += buf_size; + madvise(const_cast(void *)(in_buf), buf_size, MADV_SEQUENTIAL); + madvise(out_buf, buf_size, MADV_SEQUENTIAL); + + TESTSUITE_COPY_CODE; + copyMem(out_buf, in_buf, buf_size); + + munmap(const_cast(void *)(in_buf), buf_size); in_buf = 0; + munmap(out_buf, buf_size); out_buf = 0; + } + + res = true; + } + + out: + if (in_buf !=0) munmap(const_cast(void *)(in_buf), buf_size); + if (out_buf!=0) munmap(out_buf, buf_size); + + return res; +} + +static inline bool +copyReg(char const *src, struct stat const *src_stat, + char const *dst) +{ + int in_fd = open(src, O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE); + int out_fd = in_fd==-1 ? -1 : open(dst, O_RDWR|O_CREAT|O_EXCL, 0200); + bool res = false; + + if (in_fd==-1 || out_fd==-1 || + !verifySource(in_fd, src_stat)) goto err; + +#if 0 + for (;;) { + char buf[2048]; + ssize_t l = read(in_fd, buf, sizeof buf); + if (l==-1) goto err; + if (l==0) break; + if (!WwriteAll(out_fd, buf, l, 0)) goto err; + } + + res = true; +#else + void (*old_handler)(int) = signal(SIGBUS, handlerSIGBUS); + + res = copyMMap(in_fd, out_fd); + + signal(SIGBUS, old_handler); +#endif + + err: + if (out_fd!=-1 && close(out_fd)==-1) res=false; + if (in_fd!=-1 && close(in_fd)==-1) res=false; + return res; +} + +static inline bool +copyNode(char const UNUSED *src, struct stat const *src_stat, + char const *dst) +{ + return mknod(dst, src_stat->st_mode & (S_IFMT|S_IWUSR), + src_stat->st_rdev)!=-1; +} + +static inline bool +copyDir(char const UNUSED *src, struct stat const UNUSED *src_stat, + char const *dst) +{ + return mkdir(dst, 0700)!=-1; +} + +static inline bool +setModes(char const *path, struct stat const *st) +{ + return (lchown(path, st->st_uid, st->st_gid)!=-1 && + (S_ISLNK(st->st_mode) || chmod(path, st->st_mode)!=-1)); +} + + +bool +Unify_copy(char const *src, struct stat const *src_stat, + char const *dst) +{ + // skip sockets + // TODO: message + if (S_ISSOCK(src_stat->st_mode)) + return true; + + return + (((S_ISLNK (src_stat->st_mode) && copyLnk (src, dst)) || + (S_ISREG (src_stat->st_mode) && copyReg (src, src_stat, dst)) || + (S_ISDIR (src_stat->st_mode) && copyDir (src, src_stat, dst)) || + ((S_ISBLK (src_stat->st_mode) || + S_ISCHR (src_stat->st_mode) || + S_ISFIFO(src_stat->st_mode)) && copyNode(src, src_stat, dst)) + ) && + setModes(dst, src_stat) && + Unify_setTime(dst, src_stat)); +}