1 // $Id: unify-copy.c 2485 2007-02-04 17:18:27Z ensc $ --*- c -*--
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
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.
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.
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.
34 #define ENSC_WRAPPERS_IO 1
37 #define MMAP_BLOCKSIZE (16 * 1024*1024)
39 #ifndef TESTSUITE_COPY_CODE
40 # define TESTSUITE_COPY_CODE do { } while (false)
44 verifySource(int fd, struct stat const *exp_stat)
48 return (fstat(fd, &st)!=-1 &&
49 st.st_dev==exp_stat->st_dev &&
50 st.st_ino==exp_stat->st_ino);
54 copyLnk(char const *src, char const *dst)
60 l = readlink(src, buf, len-1);
61 if (l==-1) return false;
68 return (symlink(buf, dst)!=-1);
72 static sigjmp_buf bus_error_restore;
73 static volatile sig_atomic_t bus_error;
76 handlerSIGBUS(int UNUSED num)
79 siglongjmp(bus_error_restore, 1);
83 copyMem(void *dst_v, void const *src_v, size_t len_v)
86 // Do not use memcpy because this would dirty pages consisting only of
89 int const *src = src_v;
90 size_t len = len_v / sizeof(int);
91 size_t rest = len_v - sizeof(int)*len;
95 if (*src != 0) *dst = *src;
100 char *dst_c = (void *)(dst);
101 char const *src_c = (void const *)(src);
103 for (i=0; i<rest; ++i) {
104 if (*src_c != 0) *dst_c = *src_c;
109 memcpy(dst_v, src_v, len_v);
114 copyMMap(int in_fd, int out_fd)
116 off_t in_len = lseek(in_fd, 0, SEEK_END);
117 void const * volatile in_buf = 0;
118 void * volatile out_buf = 0;
120 loff_t volatile buf_size = 0;
121 bool volatile res = false;
123 if (in_len==-1) return false;
124 if (in_len>0 && ftruncate(out_fd, in_len)==-1) // create sparse file
128 if (sigsetjmp(bus_error_restore, 1)==0) {
131 while (offset < in_len) {
132 buf_size = in_len - offset;
133 if (buf_size > MMAP_BLOCKSIZE) buf_size = MMAP_BLOCKSIZE;
135 if ((in_buf = mmap(0, buf_size, PROT_READ, MAP_SHARED, in_fd, offset))==0 ||
136 (out_buf = mmap(0, buf_size, PROT_WRITE, MAP_SHARED, out_fd, offset))==0) {
142 madvise(const_cast(void *)(in_buf), buf_size, MADV_SEQUENTIAL);
143 madvise(out_buf, buf_size, MADV_SEQUENTIAL);
146 copyMem(out_buf, in_buf, buf_size);
148 munmap(const_cast(void *)(in_buf), buf_size); in_buf = 0;
149 munmap(out_buf, buf_size); out_buf = 0;
156 if (in_buf !=0) munmap(const_cast(void *)(in_buf), buf_size);
157 if (out_buf!=0) munmap(out_buf, buf_size);
163 copyReg(char const *src, struct stat const *src_stat,
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);
170 if (in_fd==-1 || out_fd==-1 ||
171 !verifySource(in_fd, src_stat)) goto err;
176 ssize_t l = read(in_fd, buf, sizeof buf);
179 if (!WwriteAll(out_fd, buf, l, 0)) goto err;
184 void (*old_handler)(int) = signal(SIGBUS, handlerSIGBUS);
186 res = copyMMap(in_fd, out_fd);
188 signal(SIGBUS, old_handler);
192 if (out_fd!=-1 && close(out_fd)==-1) res=false;
193 if (in_fd!=-1 && close(in_fd)==-1) res=false;
198 copyNode(char const UNUSED *src, struct stat const *src_stat,
201 return mknod(dst, src_stat->st_mode & (S_IFMT|S_IWUSR),
202 src_stat->st_rdev)!=-1;
206 copyDir(char const UNUSED *src, struct stat const UNUSED *src_stat,
209 return mkdir(dst, 0700)!=-1;
213 setModes(char const *path, struct stat const *st)
215 return (lchown(path, st->st_uid, st->st_gid)!=-1 &&
216 (S_ISLNK(st->st_mode) || chmod(path, st->st_mode)!=-1));
221 Unify_copy(char const *src, struct stat const *src_stat,
226 if (S_ISSOCK(src_stat->st_mode))
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))
237 setModes(dst, src_stat) &&
238 Unify_setTime(dst, src_stat));