initial checkin
[util-vserver.git] / util-vserver / lib_internal / unify-deunify.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 <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <utime.h>
30 #include <fcntl.h>
31 #include <errno.h>
32
33 #define ENSC_WRAPPERS_IO        1
34 #include <wrappers.h>
35
36 bool
37 Unify_deUnify(char const UNUSED *src, struct stat const UNUSED *src_stat,
38               char const *dst,        struct stat const UNUSED *dst_stat)
39 {
40   size_t                l = strlen(dst);
41   char                  tmpfile[l + sizeof(";XXXXXX")];
42   int                   fd_src, fd_tmp;
43   struct stat           st;
44   struct utimbuf        utm;
45
46   fd_src = open(dst, O_RDONLY);
47   if (fd_src==-1) {
48     perror("open()");
49     return false;
50   }
51
52   if (fstat(fd_src, &st)==-1) {
53     perror("fstat()");
54     close(fd_src);
55     return false;
56   }
57   
58   memcpy(tmpfile,   dst, l);
59   memcpy(tmpfile+l, ";XXXXXX", 8);
60   fd_tmp = mkstemp(tmpfile);
61
62   if (fd_tmp==-1) {
63     perror("mkstemp()");
64     tmpfile[0] = '\0';
65     goto err;
66   }
67
68   if (fchown(fd_tmp, st.st_uid, st.st_gid)==-1 ||
69       fchmod(fd_tmp, st.st_mode)==-1) {
70     perror("fchown()/fchmod()");
71     goto err;
72   }
73
74   // todo: acl?
75
76   for (;;) {
77     char        buf[0x4000];
78     ssize_t     len = read(fd_src, buf, sizeof buf);
79     if (len==-1) {
80       perror("read()");
81       goto err;
82     }
83     if (len==0) break;
84
85     if (!WwriteAll(fd_tmp, buf, len)) goto err;
86   }
87
88   if (close(fd_src)==-1) {
89     perror("close()");
90     goto err;
91   }
92   if (close(fd_tmp)==-1) {
93     perror("close()");
94     goto err;
95   }
96   
97   utm.actime  = st.st_atime;
98   utm.modtime = st.st_mtime;
99
100   // ALERT: race !!!
101   if (utime(tmpfile, &utm)==-1) {
102     perror("utime()");
103     goto err1;
104   }
105
106   if (unlink(dst)==-1) {
107     perror("unlink()");
108     goto err1;
109   }
110   
111   // ALERT: race !!!
112   if (rename(tmpfile, dst)==-1) {
113     perror("FATAL error in rename()");
114     _exit(1);
115   }
116
117   return true;
118   
119   err:
120   close(fd_src);
121   close(fd_tmp);
122   err1:
123   if (tmpfile[0]) unlink(tmpfile);
124
125   return false;
126 }