vshost-util-vserver

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

unify-unify.c (3035B)


      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 "vserver.h"
     25 
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <stdio.h>
     29 #include <signal.h>
     30 #include <unistd.h>
     31 #include <errno.h>
     32 #include <sys/stat.h>
     33 
     34 bool
     35 Unify_unify(char const *src, struct stat const UNUSED *src_stat,
     36 	    char const *dst, bool ignore_zero)
     37 {
     38   size_t	l = strlen(dst);
     39   char		tmpfile[l + sizeof(";XXXXXX")];
     40   int		fd;
     41   bool		res = false;
     42   struct stat	st;
     43   bool		lstat_succeeded;
     44   sigset_t	mask_new, mask_old;
     45   int		old_errno;
     46 
     47   // at first, set the ILI flags on 'src'
     48   if (vc_set_iattr(src,
     49 		   0,
     50 		   VC_IATTR_IUNLINK|VC_IATTR_IMMUTABLE,
     51 		   VC_IATTR_IUNLINK|VC_IATTR_IMMUTABLE)==-1) {
     52     perror("vc_set_iattr()");
     53     return false;
     54   }
     55 
     56   lstat_succeeded = lstat(dst, &st)==0;
     57 
     58   sigfillset(&mask_new);
     59   if (sigprocmask(SIG_SETMASK, &mask_new, &mask_old)==-1) {
     60     perror("sigprocmask()");
     61     return false;
     62   }
     63     
     64   
     65   // check if 'dst' already exists
     66   // when ignore_zero is true, do not make backups of empty destinations
     67   if (lstat_succeeded && (st.st_size>0 || !ignore_zero)) {
     68       // now, create a temporary filename
     69     memcpy(tmpfile,   dst, l);
     70     memcpy(tmpfile+l, ";XXXXXX", 8);
     71     fd = mkstemp(tmpfile);
     72     close(fd);
     73 
     74     if (fd==-1) {
     75       perror("mkstemp()");
     76       tmpfile[0] = '\0';
     77       goto err;
     78     }
     79 
     80       // and rename the old file to this name
     81 
     82       // NOTE: this rename() is race-free; when an attacker makes 'tmpfile' a
     83       // directory, the operation would fail; when making it a symlink to a file
     84       // or directory, the symlink but not the file/directory would be overridden
     85     if (rename(dst, tmpfile)==-1) {
     86       perror("rename()");
     87       goto err;
     88     }
     89   }
     90   else {
     91     if (lstat_succeeded) unlink(dst);	
     92     tmpfile[0] = '\0';
     93   }
     94 
     95   // now, link the src-file to dst
     96   if (link(src, dst)==-1) {
     97     perror("link()");
     98 
     99     unlink(dst);
    100     if (tmpfile[0]!='\0' &&
    101 	rename(tmpfile, dst)==-1) {
    102       perror("FATAL error in rename()");
    103       _exit(1);
    104     }
    105     goto err;
    106   }
    107 
    108   res = true;
    109 
    110   err:
    111   old_errno = errno;
    112 
    113   if (tmpfile[0]!='\0')
    114     unlink(tmpfile);
    115 
    116   if (sigprocmask(SIG_SETMASK, &mask_old, 0)==-1)
    117     perror("sigprocmask()");
    118 
    119   errno     = old_errno;
    120   return res;
    121 }