minor optimizations
[util-vserver.git] / util-vserver / lib_internal / unify-copy.c
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 <sys/stat.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <fcntl.h>
28
29 #define ENSC_WRAPPERS_IO        1
30 #include <wrappers.h>
31
32 static inline bool
33 verifySource(int fd, struct stat const *exp_stat)
34 {
35   struct stat           st;
36   
37   return (fstat(fd, &st)!=-1 &&
38           st.st_dev==exp_stat->st_dev &&
39           st.st_ino==exp_stat->st_ino);
40 }
41
42 static inline bool
43 copyLnk(char const *src, char const *dst)
44 {
45   ssize_t       len = 1024;
46   for (;;) {
47     char        buf[len];
48     ssize_t     l;
49     l = readlink(src, buf, len-1);
50     if (l==-1) return false;
51     if (l>=len-1) {
52       len *= 2;
53       continue;
54     }
55     buf[l] = '\0';
56
57     return (symlink(buf, dst)!=-1);
58   }
59 }
60
61 static inline bool
62 copyReg(char const *src, struct stat const *src_stat,
63         char const *dst)
64 {
65   int           in_fd  = open(src, O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE);
66   int           out_fd = in_fd==-1 ? -1 : open(dst, O_CREAT|O_EXCL, 0200);
67   bool          res    = false;
68   
69   if (in_fd==-1 || out_fd==-1 ||
70       !verifySource(in_fd, src_stat)) goto err;
71
72   for (;;) {
73     char        buf[2048];
74     ssize_t     l = read(in_fd, buf, sizeof buf);
75     if (l==-1) goto err;
76     if (l==0)  break;
77     if (!WwriteAll(out_fd, buf, l, 0)) return false;
78   }
79
80   res = true;
81   
82   err:
83   if (out_fd!=-1 && close(out_fd)==-1) res=false;
84   if (in_fd!=-1  && close(in_fd)==-1)  res=false;
85   return res;
86 }
87
88 static inline bool
89 copyNode(char const UNUSED *src, struct stat const *src_stat,
90          char const *dst)
91 {
92   return mknod(dst, src_stat->st_mode & (S_IFMT|S_IWUSR),
93                src_stat->st_rdev)!=-1;
94 }
95
96 static inline bool
97 copyDir(char const UNUSED *src, struct stat const UNUSED *src_stat,
98         char const *dst)
99 {
100   return mkdir(dst, 0700)!=-1;
101 }
102
103 static inline bool
104 setModes(char const *path, struct stat const *st)
105 {
106   return (lchown(path, st->st_uid, st->st_gid)!=-1 &&
107           (S_ISLNK(st->st_mode) || chmod(path, st->st_mode)!=-1));
108 }
109
110
111 bool
112 Unify_copy(char const *src, struct stat const *src_stat,
113            char const *dst)
114 {
115   // skip sockets
116   // TODO: message
117   if (S_ISSOCK(src_stat->st_mode))
118     return true;
119   
120   return
121     (((S_ISLNK (src_stat->st_mode) && copyLnk (src, dst)) ||
122       (S_ISREG (src_stat->st_mode) && copyReg (src, src_stat, dst)) ||
123       (S_ISDIR (src_stat->st_mode) && copyDir (src, src_stat, dst)) ||
124       ((S_ISBLK (src_stat->st_mode) ||
125         S_ISCHR (src_stat->st_mode) || 
126         S_ISFIFO(src_stat->st_mode)) && copyNode(src, src_stat, dst))
127       ) &&
128      setModes(dst, src_stat) &&
129      Unify_setTime(dst, src_stat));
130 }