vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

unify-copy.c (5820B)


      1 // $Id$    --*- c -*--
      2 
      3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 //  
      5 // This program is free software; you can redistribute it and/or modify
      6 // it under the terms of the GNU General Public License as published by
      7 // the Free Software Foundation; version 2 of the License.
      8 //  
      9 // This program is distributed in the hope that it will be useful,
     10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 // GNU General Public License for more details.
     13 //  
     14 // You should have received a copy of the GNU General Public License
     15 // along with this program; if not, write to the Free Software
     16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     17 
     18 
     19 #ifdef HAVE_CONFIG_H
     20 #  include <config.h>
     21 #endif
     22 
     23 #include "unify.h"
     24 #include "util.h"
     25 
     26 #include <unistd.h>
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <setjmp.h>
     30 #include <signal.h>
     31 #include <sys/stat.h>
     32 #include <sys/mman.h>
     33 
     34 #define ENSC_WRAPPERS_IO	1
     35 #include <wrappers.h>
     36 
     37 #define MMAP_BLOCKSIZE		(16 * 1024*1024)
     38 
     39 #ifndef   TESTSUITE_COPY_CODE
     40 #  define TESTSUITE_COPY_CODE	do { } while (false)
     41 #endif
     42 
     43 static inline bool
     44 verifySource(int fd, struct stat const *exp_stat)
     45 {
     46   struct stat		st;
     47   
     48   return (fstat(fd, &st)!=-1 &&
     49 	  st.st_dev==exp_stat->st_dev &&
     50 	  st.st_ino==exp_stat->st_ino);
     51 }
     52 
     53 static inline bool
     54 copyLnk(char const *src, char const *dst)
     55 {
     56   ssize_t	len = 1024;
     57   for (;;) {
     58     char	buf[len];
     59     ssize_t	l;
     60     l = readlink(src, buf, len-1);
     61     if (l==-1) return false;
     62     if (l>=len-1) {
     63       len *= 2;
     64       continue;
     65     }
     66     buf[l] = '\0';
     67 
     68     return (symlink(buf, dst)!=-1);
     69   }
     70 }
     71 
     72 static sigjmp_buf		bus_error_restore;
     73 static volatile sig_atomic_t 	bus_error;
     74 
     75 static void
     76 handlerSIGBUS(int UNUSED num)
     77 {
     78   bus_error = 1;
     79   siglongjmp(bus_error_restore, 1);
     80 }
     81 
     82 static void
     83 copyMem(void *dst_v, void const *src_v, size_t len_v)
     84 {
     85 #if 1
     86     // Do not use memcpy because this would dirty pages consisting only of
     87     // '\0'
     88   int		*dst = dst_v;
     89   int const	*src = src_v;
     90   size_t	len  = len_v / sizeof(int);
     91   size_t	rest = len_v - sizeof(int)*len;
     92   size_t	i=0;
     93 
     94   for (; i<len; ++i) {
     95     if (*src != 0) *dst = *src;
     96     ++dst;
     97     ++src;
     98   }
     99 
    100   char		*dst_c = (void *)(dst);
    101   char const	*src_c = (void const *)(src);
    102 
    103   for (i=0; i<rest; ++i) {
    104     if (*src_c != 0) *dst_c = *src_c;
    105     ++dst_c;
    106     ++src_c;
    107   }
    108 #else
    109   memcpy(dst_v, src_v, len_v);
    110 #endif  
    111 }
    112 
    113 static UNUSED bool
    114 copyMMap(int in_fd, int out_fd)
    115 {
    116   off_t			in_len   = lseek(in_fd, 0, SEEK_END);
    117   void const * volatile in_buf   = 0;
    118   void       * volatile	out_buf  = 0;
    119   
    120   loff_t volatile	buf_size = 0;
    121   bool   volatile 	res      = false;
    122 
    123   if (in_len==-1) return false;
    124   if (in_len>0 && ftruncate(out_fd, in_len)==-1)	// create sparse file
    125     return false;
    126   
    127   bus_error = 0;
    128   if (sigsetjmp(bus_error_restore, 1)==0) {
    129     off_t		offset   = 0;
    130 
    131     while (offset < in_len) {
    132       buf_size = in_len - offset;
    133       if (buf_size > MMAP_BLOCKSIZE) buf_size = MMAP_BLOCKSIZE;
    134       
    135       if ((in_buf  = mmap(0, buf_size, PROT_READ,  MAP_SHARED,  in_fd, offset))==MAP_FAILED ||
    136 	  (out_buf = mmap(0, buf_size, PROT_WRITE, MAP_SHARED, out_fd, offset))==MAP_FAILED) {
    137 	perror("mmap()");
    138 	goto out;
    139       }
    140 
    141       offset  += buf_size;
    142       madvise(const_cast(void *)(in_buf),  buf_size, MADV_SEQUENTIAL);
    143       madvise(out_buf,                     buf_size, MADV_SEQUENTIAL);
    144 
    145       TESTSUITE_COPY_CODE;
    146       copyMem(out_buf, in_buf, buf_size);
    147 
    148       munmap(out_buf,                     buf_size); out_buf = 0;
    149       munmap(const_cast(void *)(in_buf),  buf_size);  in_buf = 0;
    150     }
    151 
    152     res = true;
    153   }
    154 
    155   out:
    156   if (out_buf!=0) munmap(out_buf,                     buf_size);
    157   if (in_buf !=0) munmap(const_cast(void *)(in_buf),  buf_size);
    158 
    159   return res;
    160 }
    161 
    162 static inline bool
    163 copyReg(char const *src, struct stat const *src_stat,
    164 	char const *dst)
    165 {
    166   int		in_fd  = open(src, O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE);
    167   int		out_fd = in_fd==-1 ? -1 : open(dst, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY, 0200);
    168   bool		res    = false;
    169   
    170   if (in_fd==-1 || out_fd==-1 ||
    171       !verifySource(in_fd, src_stat)) goto err;
    172 
    173 #if 0  
    174   for (;;) {
    175     char	buf[2048];
    176     ssize_t	l = read(in_fd, buf, sizeof buf);
    177     if (l==-1) goto err;
    178     if (l==0)  break;
    179     if (!WwriteAll(out_fd, buf, l, 0)) goto err;
    180   }
    181 
    182   res = true;
    183 #else
    184   void		(*old_handler)(int) = signal(SIGBUS, handlerSIGBUS);
    185 
    186   res = copyMMap(in_fd, out_fd);
    187 
    188   signal(SIGBUS, old_handler);
    189 #endif
    190 
    191   err:
    192   if (out_fd!=-1 && close(out_fd)==-1) res=false;
    193   if (in_fd!=-1  && close(in_fd)==-1)  res=false;
    194   return res;
    195 }
    196 
    197 static inline bool
    198 copyNode(char const UNUSED *src, struct stat const *src_stat,
    199 	 char const *dst)
    200 {
    201   return mknod(dst, src_stat->st_mode & (S_IFMT|S_IWUSR),
    202 	       src_stat->st_rdev)!=-1;
    203 }
    204 
    205 static inline bool
    206 copyDir(char const UNUSED *src, struct stat const UNUSED *src_stat,
    207 	char const *dst)
    208 {
    209   return mkdir(dst, 0700)!=-1;
    210 }
    211 
    212 static inline bool
    213 setModes(char const *path, struct stat const *st)
    214 {
    215   return (lchown(path, st->st_uid, st->st_gid)!=-1 &&
    216 	  (S_ISLNK(st->st_mode) || chmod(path, st->st_mode)!=-1));
    217 }
    218 
    219 
    220 bool
    221 Unify_copy(char const *src, struct stat const *src_stat,
    222 	   char const *dst)
    223 {
    224   // skip sockets
    225   // TODO: message
    226   if (S_ISSOCK(src_stat->st_mode))
    227     return true;
    228   
    229   return
    230     (((S_ISLNK (src_stat->st_mode) && copyLnk (src, dst)) ||
    231       (S_ISREG (src_stat->st_mode) && copyReg (src, src_stat, dst)) ||
    232       (S_ISDIR (src_stat->st_mode) && copyDir (src, src_stat, dst)) ||
    233       ((S_ISBLK (src_stat->st_mode) ||
    234 	S_ISCHR (src_stat->st_mode) || 
    235 	S_ISFIFO(src_stat->st_mode)) && copyNode(src, src_stat, dst))
    236       ) &&
    237      setModes(dst, src_stat) &&
    238      Unify_setTime(dst, src_stat));
    239 }