copyfile.c 6.5 KB
Newer Older
Bernhard Link's avatar
Bernhard Link committed
1
/*  This file is part of "reprepro"
2
 *  Copyright (C) 2003,2004 Bernhard R. Link
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <config.h>

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
27
#include <string.h>
28 29

#include "error.h"
30
#include "strlist.h"
31 32
#include "names.h"
#include "dirs.h"
33
#include "md5sum.h"
34 35
#include "copyfile.h"

36 37
extern int verbose;

38 39
/* Copy a file and calculate the md5sum of the result,
 * return RET_NOTHING (and no md5sum), if it already exists*/
40
static retvalue copyfile(const char *origfile,const char *destfullfilename,char **md5sum) {
41 42
	retvalue r;

43 44 45 46
	r = md5sum_copy(origfile,destfullfilename,md5sum);
	if( r == RET_NOTHING ) {
		fprintf(stderr,"Error opening '%s'!\n",origfile);
		r = RET_ERROR;
47
	}
48 49 50 51
	if( r == RET_ERROR_EXIST )
		r = RET_NOTHING;
	return r;
}
52

53 54 55 56 57
/* fullfilename is already there, but we want it do be md5expected, try
 * to get there by copying origfile, if it has the wrong md5sum... */
static retvalue copyfile_force(const char *fullfilename,const char *origfile,const char *md5expected) {
	char *md5old;
	retvalue r;
58

59 60 61 62
	r = md5sum_read(fullfilename,&md5old);
	if( r == RET_NOTHING ) {
		fprintf(stderr,"Strange file '%s'!\n",fullfilename);
		r = RET_ERROR;
63
	}
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	if( RET_WAS_ERROR(r) )
		return r;
	if( strcmp(md5old,md5expected) != 0 ) {
		int ret;

		/* There already is a file there, as
		 * we should have queried the db, this
		 * means this is a leftover file, we
		 * just delete and try again... */
		fprintf(stderr,"There already is a non-registered file '%s' with the wrong md5sum ('%s', but expect '%s'). Removing it...\n",fullfilename,md5old,md5expected);
		free(md5old);
		ret = unlink(fullfilename);
		if( ret < 0 ) {
			ret = errno;
			fprintf(stderr,"Error deleting '%s': %m\n",fullfilename);
79 80
			return RET_ERRNO(ret);
		}
81 82 83 84
		/* try again: */
		r = copyfile(origfile,fullfilename,&md5old);
		if( RET_WAS_ERROR(r) )
			return r;
85
	}
86 87 88 89
	if( strcmp(md5old,md5expected) != 0 ) {
		unlink(fullfilename);
		fprintf(stderr,"'%s' has md5sum '%s', while '%s' was expected.\n",origfile,md5old,md5expected);
		r = RET_ERROR_WRONG_MD5;
90
	}
91 92
	free(md5old);
	return r;
93 94
}

95 96 97 98 99
/* Make sure <mirrordir>/<filekey> has <md5expected>, and we can get
 * there by copying <origfile> there. */
retvalue copyfile_md5known(const char *mirrordir,const char *filekey,const char *origfile,const char *md5expected) {
	retvalue r;
	char *fullfilename;
100
	char *md5sum;
101 102 103 104 105

	fullfilename = calc_dirconcat(mirrordir,filekey);
	if( fullfilename == NULL )
		return RET_ERROR_OOM;

106
	r = copyfile(origfile,fullfilename,&md5sum);
107
	if( r == RET_ERROR_EXIST || r == RET_NOTHING ) {
108 109
		r = copyfile_force(origfile,fullfilename,md5expected);
	} else if( RET_IS_OK(r) ) {
110
		if( strcmp(md5sum,md5expected) == 0 ) {
111
			r = RET_OK;
112
		} else {
113 114 115
			unlink(fullfilename);
			fprintf(stderr,"'%s' has md5sum '%s', while '%s' was expected.\n",origfile,md5sum,md5expected);
			r = RET_ERROR_WRONG_MD5;
116 117 118
		}
		free(md5sum);
	}
119 120
	free(fullfilename);
	return r;
121 122 123 124 125 126 127 128 129 130
}

retvalue copyfile_getmd5(const char *mirrordir,const char *filekey,const char *origfile,char **md5sum) {
	retvalue r;
	char *fullfilename;

	fullfilename = calc_dirconcat(mirrordir,filekey);
	if( fullfilename == NULL )
		return RET_ERROR_OOM;

131
	r = copyfile(origfile,fullfilename,md5sum);
132
	if( r == RET_ERROR_EXIST || r == RET_NOTHING ) {
133 134 135 136 137 138 139 140 141 142 143 144 145 146
		r = md5sum_read(origfile,md5sum);
		if( r == RET_NOTHING ) {
			/* where did it go? */
			fprintf(stderr,"File '%s' disapeared!\n",fullfilename);
			r = RET_ERROR;
		}
		if( RET_IS_OK(r) )
			r = copyfile_force(origfile,fullfilename,*md5sum);
		if( RET_WAS_ERROR(r) ) {
			free(*md5sum);
			*md5sum = NULL;
			free(fullfilename);
			return r;
		}
147

148 149 150
	} 
	free(fullfilename);
	return r;
151
}
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
void copyfile_delete(const char *fullfilename) {
	int err;

	err = unlink(fullfilename);
	if( err != 0 ) {
		fprintf(stderr,"error while unlinking %s: %m\n",fullfilename);
	}

}

static retvalue copy(const char *fullfilename,const char *origfile,const char *md5expected,char **calculatedmd5sum) {
	char *md5sum;
	retvalue r;

	r = md5sum_copy(origfile,fullfilename,&md5sum);
	if( r == RET_NOTHING ) {
		fprintf(stderr,"Could not open '%s'!\n",origfile);
		return RET_ERROR_MISSING;
	}
	if( r == RET_ERROR_EXIST ) {
		fprintf(stderr,"File '%s' does already exist!\n",fullfilename);
	}
	if( RET_WAS_ERROR(r) )
		return r;

177 178 179 180 181 182 183 184
	if( md5expected != NULL ) {
		if( strcmp(md5sum,md5expected) == 0 ) {
			r = RET_OK;
		} else {
			unlink(fullfilename);
			fprintf(stderr,"WARNING: '%s' has md5sum '%s', while '%s' was expected.\n",origfile,md5sum,md5expected);
			r = RET_ERROR_WRONG_MD5;
		}
185 186
	}

187 188
	if( calculatedmd5sum != NULL )
		*calculatedmd5sum = md5sum;
189 190 191 192 193 194 195 196 197 198 199 200 201
	if( calculatedmd5sum == NULL )
		free(md5sum);

	return r;
}

static retvalue move(const char *fullfilename,const char *origfile,const char *md5expected,char **md5sum) {
	retvalue r;
	// TODO: try a rename first, if md5sum is know and correct??
	
	r = copy(fullfilename,origfile,md5expected,md5sum);
	if( RET_IS_OK(r) ) {
		if( verbose > 15 ) {
202
			fprintf(stderr,"Deleting '%s' after copying away.\n",origfile);
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		}
		if( unlink(origfile) != 0 ) {
			fprintf(stderr,"Error deleting '%s': %m",origfile);
		}
	}
	return r;
}

retvalue copyfile_move(const char *mirrordir,const char *filekey,const char *origfile,const char *md5expected,char **md5sum) {
	retvalue r;
	char *fullfilename;

	fullfilename = calc_dirconcat(mirrordir,filekey);
	if( fullfilename == NULL )
		return RET_ERROR_OOM;
	r = move(fullfilename,origfile,md5expected,md5sum);
	free(fullfilename);
	return r;
}
retvalue copyfile_copy(const char *mirrordir,const char *filekey,const char *origfile,const char *md5expected,char **md5sum) {
	retvalue r;
	char *fullfilename;

	fullfilename = calc_dirconcat(mirrordir,filekey);
	if( fullfilename == NULL )
		return RET_ERROR_OOM;
	r = copy(fullfilename,origfile,md5expected,md5sum);
	free(fullfilename);
	return r;
}