Main Page | Class List | Directories | File List | Class Members | File Members

copy.c

Go to the documentation of this file.
00001 /* 
00002 
00003         Copyright (C) 1995
00004         Free Software Foundation, Inc.
00005 
00006    This file is part of GNU cfengine - written and maintained 
00007    by Mark Burgess, Dept of Computing and Engineering, Oslo College,
00008    Dept. of Theoretical physics, University of Oslo
00009  
00010    This program is free software; you can redistribute it and/or modify it
00011    under the terms of the GNU General Public License as published by the
00012    Free Software Foundation; either version 2, or (at your option) any
00013    later version.
00014  
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019  
00020   You should have received a copy of the GNU General Public License
00021   along with this program; if not, write to the Free Software
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
00023 
00024 */
00025 
00026 
00027 /*******************************************************************/
00028 /*                                                                 */
00029 /* File copying low level                                          */
00030 /*                                                                 */
00031 /*******************************************************************/
00032 
00033 #include "cf.defs.h"
00034 #include "cf.extern.h"
00035 
00036 /*********************************************************************/
00037 
00038 void CheckForHoles(sstat,ip)
00039 
00040 /* Need a transparent way of getting this into CopyReg() */
00041 /* Use a public member in struct Image                   */
00042 
00043 struct stat *sstat;
00044 struct Image *ip;
00045 
00046 {
00047 #ifndef IRIX
00048 if (sstat->st_size > sstat->st_blocks * DEV_BSIZE)
00049 #else
00050 # ifdef HAVE_ST_BLOCKS
00051 if (sstat->st_size > sstat->st_blocks * DEV_BSIZE)
00052 # else
00053 if (sstat->st_size > ST_NBLOCKS((*sstat)) * DEV_BSIZE)
00054 # endif
00055 #endif
00056    {
00057    ip->makeholes = 1;   /* must have a hole to get checksum right */
00058    }
00059 
00060 ip->makeholes = 0;
00061 }
00062 
00063 /*********************************************************************/
00064 
00065 int CopyRegDisk(source,new,ip)
00066 
00067 char *source, *new;
00068 struct Image *ip;
00069 
00070 { int sd, dd, buf_size;
00071   char *buf, *cp;
00072   int n_read, *intp;
00073   long n_read_total = 0;
00074   int last_write_made_hole = 0;
00075   
00076 if ((sd = open(source,O_RDONLY|O_BINARY)) == -1)
00077    {
00078    snprintf(OUTPUT,bufsize,"Can't copy %s!\n",source);
00079    CfLog(cfinform,OUTPUT,"open");
00080    unlink(new);
00081    return false;
00082    }
00083 
00084 unlink(new);  /* To avoid link attacks */
00085  
00086 if ((dd = open(new,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0600)) == -1)
00087    {
00088    snprintf(OUTPUT,bufsize,"Copy %s:%s security - failed attempt to exploit a race? (Not copied)\n",ip->server,new);
00089    CfLog(cfinform,OUTPUT,"open");
00090    close(sd);
00091    unlink(new);
00092    return false;
00093    }
00094 
00095 buf_size = ST_BLKSIZE(dstat);
00096 buf = (char *) malloc(buf_size + sizeof(int));
00097 
00098 while (true)
00099    {
00100    if ((n_read = read (sd, buf, buf_size)) == -1)
00101       {
00102       if (errno == EINTR) 
00103          {
00104          continue;
00105          }
00106 
00107       close(sd);
00108       close(dd);
00109       free(buf);
00110       return false;
00111       }
00112 
00113    if (n_read == 0)
00114       {
00115       break;
00116       }
00117 
00118    n_read_total += n_read;
00119 
00120    intp = 0;
00121 
00122    if (ip->makeholes)
00123       {
00124       buf[n_read] = 1;                     /* Sentinel to stop loop.  */
00125 
00126       /* Find first non-zero *word*, or the word with the sentinel.  */
00127 
00128       intp = (int *) buf;
00129 
00130       while (*intp++ == 0)
00131          {
00132          }
00133 
00134       /* Find the first non-zero *byte*, or the sentinel.  */
00135 
00136       cp = (char *) (intp - 1);
00137 
00138       while (*cp++ == 0)
00139          {
00140          }
00141 
00142       /* If we found the sentinel, the whole input block was zero,
00143          and we can make a hole.  */
00144 
00145       if (cp > buf + n_read)
00146          {
00147          /* Make a hole.  */
00148          if (lseek (dd, (off_t) n_read, SEEK_CUR) < 0L)
00149             {
00150             snprintf(OUTPUT,bufsize,"Copy failed (no space?) while doing %s to %s\n",source,new);
00151             CfLog(cferror,OUTPUT,"lseek");
00152             free(buf);
00153             unlink(new);
00154             close(dd);
00155             close(sd);
00156             return false;
00157             }
00158          last_write_made_hole = 1;
00159          }
00160       else
00161          {
00162          /* Clear to indicate that a normal write is needed. */
00163          intp = 0;
00164          }
00165       }
00166 
00167    if (intp == 0)
00168       {
00169       if (cf_full_write (dd, buf, n_read) < 0)
00170          {
00171          snprintf(OUTPUT,bufsize*2,"Copy failed (no space?) while doing %s to %s\n",source,new);
00172          CfLog(cferror,OUTPUT,"");
00173          close(sd);
00174          close(dd);
00175          free(buf);
00176          unlink(new);
00177          return false;
00178          }
00179       last_write_made_hole = 0;
00180       }
00181    }
00182 
00183   /* If the file ends with a `hole', something needs to be written at
00184      the end.  Otherwise the kernel would truncate the file at the end
00185      of the last write operation.  */
00186 
00187   if (last_write_made_hole)
00188     {
00189     /* Write a null character and truncate it again.  */
00190 
00191     if (cf_full_write (dd, "", 1) < 0 || ftruncate (dd, n_read_total) < 0)
00192        {
00193        CfLog(cferror,"cfengine: full_write or ftruncate error in CopyReg\n","write");
00194        free(buf);
00195        unlink(new);
00196        close(sd);
00197        close(dd);
00198        return false;
00199        }
00200     }
00201 
00202 close(sd);
00203 close(dd);
00204 
00205 free(buf);
00206 return true;
00207 }
00208 
00209 /*********************************************************************/
00210 
00211 int EmbeddedWrite(new,dd,buf,ip,towrite,last_write_made_hole,n_read)
00212 
00213 int dd, towrite,*last_write_made_hole,n_read;
00214 char *new,*buf;
00215 struct Image *ip;
00216 
00217 { int *intp;
00218  char *cp;
00219  
00220  intp = 0;
00221  
00222  if (ip->makeholes)
00223     {
00224     buf[n_read] = 1;                       /* Sentinel to stop loop.  */
00225     
00226     /* Find first non-zero *word*, or the word with the sentinel.  */
00227     intp = (int *) buf;
00228     
00229     while (*intp++ == 0)
00230        {
00231        }
00232     
00233     /* Find the first non-zero *byte*, or the sentinel.  */
00234     
00235     cp = (char *) (intp - 1);
00236     
00237     while (*cp++ == 0)
00238        {
00239        }
00240     
00241     /* If we found the sentinel, the whole input block was zero,
00242        and we can make a hole.  */
00243     
00244     if (cp > buf + n_read)
00245        {
00246        /* Make a hole.  */
00247        if (lseek (dd,(off_t)n_read,SEEK_CUR) < 0L)
00248           {
00249           snprintf(OUTPUT,bufsize,"lseek in EmbeddedWrite, dest=%s\n", new);
00250           CfLog(cferror,OUTPUT,"lseek");
00251           return false;
00252           }
00253        *last_write_made_hole = 1;
00254        }
00255     else
00256        {
00257        /* Clear to indicate that a normal write is needed. */
00258        intp = 0;
00259        }
00260     }
00261  
00262  if (intp == 0)
00263     {
00264     if (cf_full_write (dd,buf,towrite) < 0)
00265        {
00266        snprintf(OUTPUT,bufsize*2,"Local disk write(%.256s) failed\n",new);
00267        CfLog(cferror,OUTPUT,"write");
00268        CONN->error = true;
00269        return false;
00270        }
00271 
00272     *last_write_made_hole = 0;
00273     }
00274 
00275 return true;
00276 }

© sourcejam.com 2005-2008