Commit 340d9742 authored by Bernhard Link's avatar Bernhard Link

cleaning: port changestool to new checksums code, finaly removing the old md5sum code.

parent 9979200f
2008-01-01 Bernhard R. Link <brlink@debian.org>
* cleaning: port changestool to new checksums code,
finaly removing the old md5sum code.
2008-02-29 Bernhard R. Link <brlink@debian.org>
* improve documentation of listfilter command
......
......@@ -21,9 +21,9 @@ changestool_LDADD = $(ARCHIVELIBS)
reprepro_SOURCES = checksums.c readtextfile.c filecntl.c sha1.c configparser.c database.c freespace.c log.c changes.c incoming.c uploaderslist.c guesscomponent.c files.c md5.c dirs.c chunks.c reference.c binaries.c sources.c checks.c names.c dpkgversions.c release.c mprintf.c updates.c strlist.c signature.c distribution.c checkindeb.c checkindsc.c checkin.c upgradelist.c target.c aptmethod.c downloadcache.c main.c override.c terms.c ignore.c filterlist.c exports.c tracking.c optionsfile.c readrelease.c donefile.c pull.c contents.c filelist.c $(ARCHIVE_USED) $(ARCHIVE_CONTENTS)
EXTRA_reprepro_SOURCE = $(ARCHIVE_UNUSED)
changestool_SOURCES = readtextfile.c filecntl.c tool.c chunkedit.c strlist.c md5sum.c sha1.c md5.c mprintf.c chunks.c signature.c dirs.c names.c $(ARCHIVE_USED)
changestool_SOURCES = readtextfile.c filecntl.c tool.c chunkedit.c strlist.c checksums.c sha1.c md5.c mprintf.c chunks.c signature.c dirs.c names.c $(ARCHIVE_USED)
noinst_HEADERS = checksums.h readtextfile.h filecntl.h sha1.h configparser.h database_p.h database.h freespace.h log.h changes.h incoming.h guesscomponent.h md5.h md5sum.h dirs.h files.h chunks.h reference.h binaries.h sources.h checks.h names.h release.h error.h mprintf.h updates.h strlist.h signature.h distribution.h debfile.h checkindeb.h checkindsc.h upgradelist.h target.h aptmethod.h downloadcache.h override.h terms.h ignore.h filterlist.h dpkgversions.h checkin.h exports.h globals.h tracking.h trackingt.h optionsfile.h readrelease.h donefile.h pull.h ar.h filelist.h contents.h chunkedit.h uploaderslist.h
noinst_HEADERS = checksums.h readtextfile.h filecntl.h sha1.h configparser.h database_p.h database.h freespace.h log.h changes.h incoming.h guesscomponent.h md5.h dirs.h files.h chunks.h reference.h binaries.h sources.h checks.h names.h release.h error.h mprintf.h updates.h strlist.h signature.h distribution.h debfile.h checkindeb.h checkindsc.h upgradelist.h target.h aptmethod.h downloadcache.h override.h terms.h ignore.h filterlist.h dpkgversions.h checkin.h exports.h globals.h tracking.h trackingt.h optionsfile.h readrelease.h donefile.h pull.h ar.h filelist.h contents.h chunkedit.h uploaderslist.h
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/configure $(srcdir)/install-sh $(srcdir)/stamp-h.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in $(srcdir)/mkinstalldirs $(srcdir)/config.guess $(srcdir)/config.sub $(srcdir)/missing
......
/* This file is part of "reprepro"
* Copyright (C) 2003,2004,2005,2006 Bernhard R. Link
* Copyright (C) 2003,2004,2005,2006,2008 Bernhard R. Link
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
......@@ -24,12 +24,10 @@
#include <sys/types.h>
#include "error.h"
#include "names.h"
#include "checksums.h"
#include "changes.h"
retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_type,
/*@out@*/char **result_basename, /*@out@*/char **result_md5sum,
/*@out@*/char **result_section, /*@out@*/char **result_priority,
/*@out@*/char **result_architecture, /*@out@*/char **result_name) {
retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_type, /*@out@*/char **result_basename, /*@out@*/struct checksums **result_checksums, /*@out@*/char **result_section, /*@out@*/char **result_priority, /*@out@*/char **result_architecture, /*@out@*/char **result_name) {
const char *p,*md5start,*md5end;
const char *sizestart,*sizeend;
......@@ -39,20 +37,37 @@ retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_t
const char *archstart,*archend;
const char *versionstart,*typestart;
filetype type;
char *md5sum,*section,*priority,*basename,*architecture,*name;
char *section, *priority, *basename, *architecture, *name;
retvalue r;
p = fileline;
while( *p !='\0' && xisspace(*p) )
p++;
md5start = p;
while( *p !='\0' && !xisspace(*p) )
while( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') )
p++;
if( *p == '\0' ) {
fprintf(stderr,"Missing md5sum in '%s'!\n", fileline);
return RET_ERROR;
}
if( !xisspace(*p) ) {
fprintf(stderr,"Malformed md5 hash in '%s'!\n", fileline);
return RET_ERROR;
}
md5end = p;
while( *p !='\0' && xisspace(*p) )
p++;
sizestart = p;
while( *p !='\0' && !xisspace(*p) )
while( *p >= '0' && *p <= '9' )
p++;
if( *p == '\0' ) {
fprintf(stderr,"Missing size (second argument) in '%s'!\n", fileline);
return RET_ERROR;
}
if( !xisspace(*p) ) {
fprintf(stderr,"Malformed size (second argument) in '%s'!\n", fileline);
return RET_ERROR;
}
sizeend = p;
while( *p !='\0' && xisspace(*p) )
p++;
......@@ -166,19 +181,25 @@ retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_t
archstart = "source";
archend = archstart + 6;
}
md5sum = names_concatmd5sumandsize(md5start,md5end,sizestart,sizeend);
section = strndup(sectionstart,sectionend-sectionstart);
priority = strndup(priostart,prioend-priostart);
basename = strndup(filestart,fileend-filestart);
architecture = strndup(archstart,archend-archstart);
name = strndup(filestart,nameend-filestart);
if( md5sum == NULL || section == NULL || priority == NULL ||
if( section == NULL || priority == NULL ||
basename == NULL || architecture == NULL || name == NULL ) {
free(md5sum);free(section);free(priority);
free(basename);free(architecture);free(name);
free(section); free(priority);
free(basename); free(architecture); free(name);
return RET_ERROR_OOM;
}
*result_md5sum = md5sum;
r = checksums_set(result_checksums, md5start, md5end - md5start,
sizestart, sizeend - sizestart);
assert( r != RET_NOTHING );
if( RET_WAS_ERROR(r) ) {
free(section); free(priority);
free(basename); free(architecture); free(name);
return r;
}
*result_section = section;
*result_priority = priority;
*result_basename = basename;
......
......@@ -7,8 +7,6 @@ typedef enum { fe_UNKNOWN=0,fe_DEB,fe_UDEB,fe_DSC,fe_DIFF,fe_ORIG,fe_TAR} filety
#define FE_BINARY(ft) ( (ft) == fe_DEB || (ft) == fe_UDEB )
#define FE_SOURCE(ft) ( (ft) == fe_DIFF || (ft) == fe_ORIG || (ft) == fe_TAR || (ft) == fe_DSC || (ft) == fe_UNKNOWN)
retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_type,
/*@out@*/char **result_basename, /*@out@*/char **result_md5sum,
/*@out@*/char **result_section, /*@out@*/char **result_priority,
/*@out@*/char **result_architecture, /*@out@*/char **result_name);
struct checksums;
retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_type, /*@out@*/char **result_basename, /*@out@*/struct checksums **, /*@out@*/char **result_section, /*@out@*/char **result_priority, /*@out@*/char **result_architecture, /*@out@*/char **result_name);
#endif
......@@ -167,25 +167,18 @@ static void changes_free(/*@only@*/struct changes *changes) {
static retvalue newentry(struct fileentry **entry,const char *fileline,const char *packagetypeonly,const char *forcearchitecture, const char *sourcename) {
struct fileentry *e;
retvalue r;
char *md5sum;
e = calloc(1,sizeof(struct fileentry));
if( e == NULL )
return RET_ERROR_OOM;
r = changes_parsefileline(fileline, &e->type, &e->basename, &md5sum,
r = changes_parsefileline(fileline, &e->type, &e->basename, &e->checksums,
&e->section, &e->priority, &e->architecture, &e->name);
if( RET_WAS_ERROR(r) ) {
free(e);
return r;
}
assert( RET_IS_OK(r) );
r = checksums_set(&e->checksums, md5sum);
free(md5sum);
if( RET_WAS_ERROR(r) ) {
freeentries(e);
return r;
}
if( FE_SOURCE(e->type) && packagetypeonly != NULL && strcmp(packagetypeonly,"dsc")!=0) {
freeentries(e);
return RET_NOTHING;
......
......@@ -68,13 +68,34 @@ void checksums_free(struct checksums *checksums) {
free(checksums);
}
/* create a checksum record from an md5sum: */
retvalue checksums_set(struct checksums **result, const char *md5sum) {
// TODO: depreceate this function?
// or reimplement it? otherwise the error messaged might be even
// wronger. (and checking things from the database could be done
// faster than stuff from outside)
return checksums_parse(result, md5sum);
retvalue checksums_set(struct checksums **result, const char *md5, size_t md5len, const char *size, size_t sizelen) {
char *d;
struct checksums *n;
size_t len;
assert( md5 != NULL && size != NULL);
len = md5len + 1 + sizelen;
n = malloc(sizeof(struct checksums) + len + 1);
if( n == NULL )
return RET_ERROR_OOM;
memset(n, 0, sizeof(struct checksums));
d = n->representation;
n->parts[cs_md5sum].ofs = 0;
n->parts[cs_md5sum].len = md5len;
memcpy(d, md5, md5len);
d += md5len;
*(d++) = ' ';
n->parts[cs_length].ofs = d - n->representation;
n->parts[cs_length].len = sizelen;
memcpy(d, size, sizelen);
d += sizelen;
*d = '\0';
assert( (size_t)(d-n->representation) == len );
*result = n;
return RET_OK;
}
retvalue checksums_init(/*@out@*/struct checksums **checksums_p, char *hashes[cs_COUNT]) {
......@@ -331,29 +352,16 @@ bool checksums_gethashpart(const struct checksums *checksums, enum checksumtype
return true;
}
retvalue checksums_get(const struct checksums *checksums, enum checksumtype type, char **result) {
const char *hash, *size;
size_t hashlen, sizelen;
if( checksums_gethashpart(checksums, type,
&hash, &hashlen, &size, &sizelen) ) {
char *checksum;
checksum = malloc(hashlen + sizelen + 2);
if( checksum == NULL )
return RET_ERROR_OOM;
memcpy(checksum, hash, hashlen);
checksum[hashlen] = ' ';
memcpy(checksum+hashlen+1, size, sizelen);
checksum[hashlen+1+sizelen] = '\0';
*result = checksum;
return RET_OK;
} else
return RET_NOTHING;
const char *checksums_getmd5sum(const struct checksums *checksums) {
assert( checksums->parts[cs_md5sum].len != 0 &&
checksums->parts[cs_length].len != 0 &&
checksums->parts[cs_md5sum].ofs +
checksums->parts[cs_md5sum].len + 1 ==
checksums->parts[cs_length].ofs);
/* using the knowledge about the format, this is just what is wanted: */
return checksums_hashpart(checksums, cs_md5sum);
}
retvalue checksums_getcombined(const struct checksums *checksums, /*@out@*/const char **data_p, /*@out@*/size_t *datalen_p) {
size_t len;
......@@ -556,9 +564,9 @@ retvalue checksumsarray_parse(struct checksumsarray *out, const struct strlist *
return RET_ERROR_OOM;
}
for( i = 0 ; i < lines->count ; i++ ) {
char *filename, *md5sum;
char *filename;
r = calc_parsefileline(lines->values[i], &filename, &md5sum);
r = calc_parsefileline(lines->values[i], &filename, &a.checksums[i]);
if( RET_WAS_ERROR(r) ) {
if( r != RET_ERROR_OOM )
fprintf(stderr, "Error was parsing %s\n",
......@@ -570,17 +578,6 @@ retvalue checksumsarray_parse(struct checksumsarray *out, const struct strlist *
checksumsarray_done(&a);
return r;
}
r = checksums_set(&a.checksums[i], md5sum);
free(md5sum);
if( RET_WAS_ERROR(r) ) {
free(filename);
if( i == 0 ) {
free(a.checksums);
a.checksums = NULL;
}
checksumsarray_done(&a);
return r;
}
r = strlist_add(&a.names, filename);
if( RET_WAS_ERROR(r) ) {
checksums_free(a.checksums[i]);
......@@ -1040,3 +1037,77 @@ retvalue checksums_linkorcopyfile(const char *destination, const char *source, s
return RET_OK;
}
retvalue checksums_replace(const char *filename, const char *data, size_t len, struct checksums **checksums_p){
struct checksumscontext context;
size_t todo; const char *towrite;
char *tempfilename;
struct checksums *checksums;
int fd, ret;
retvalue r;
tempfilename = calc_addsuffix(filename, "new");
if( tempfilename == NULL )
return RET_ERROR_OOM;
fd = open(tempfilename, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666);
if( fd < 0 ) {
int e = errno;
fprintf(stderr, "ERROR creating '%s': %s\n", tempfilename,
strerror(e));
free(tempfilename);
return RET_ERRNO(e);
}
todo = len; towrite = data;
while( todo > 0 ) {
ssize_t written = write(fd, towrite, todo);
if( written >= 0 ) {
todo -= written;
towrite += written;
} else {
int e = errno;
close(fd);
fprintf(stderr, "Error writing to '%s': %s\n",
tempfilename, strerror(e));
unlink(tempfilename);
free(tempfilename);
return RET_ERRNO(e);
}
}
ret = close(fd);
if( ret < 0 ) {
int e = errno;
fprintf(stderr, "Error writing to '%s': %s\n",
tempfilename, strerror(e));
unlink(tempfilename);
free(tempfilename);
return RET_ERRNO(e);
}
if( checksums_p != NULL ) {
checksumscontext_init(&context);
checksumscontext_update(&context, (const unsigned char *)data, len);
r = checksums_from_context(&checksums, &context);
assert( r != RET_NOTHING );
if( RET_WAS_ERROR(r) ) {
unlink(tempfilename);
free(tempfilename);
return r;
}
} else
checksums = NULL;
ret = rename(tempfilename, filename);
if( ret < 0 ) {
int e = errno;
fprintf(stderr, "Error moving '%s' to '%s': %s\n",
tempfilename, filename, strerror(e));
unlink(tempfilename);
free(tempfilename);
checksums_free(checksums);
return RET_ERRNO(e);
}
free(tempfilename);
if( checksums_p != NULL )
*checksums_p = checksums;
return RET_OK;
}
......@@ -29,14 +29,13 @@ void checksums_free(/*@only@*//*@null@*/struct checksums *);
/*@null@*/struct checksums *checksums_dup(const struct checksums *);
/* create a checksum record from an md5sum: */
retvalue checksums_set(/*@out@*/struct checksums **, const char *);
retvalue checksums_set(/*@out@*/struct checksums **result, const char *md5, size_t md5len, const char *size, size_t sizelen);
retvalue checksums_setall(/*@out@*/struct checksums **checksums_p, const char *combinedchecksum, size_t len, /*@null@*/const char *md5sum);
/* hashes[*] is free'd */
retvalue checksums_init(/*@out@*/struct checksums **, char *hashes[cs_COUNT]);
retvalue checksums_parse(/*@out@*/struct checksums **, const char *);
retvalue checksums_get(const struct checksums *, enum checksumtype, /*@out@*/char **);
off_t checksums_getfilesize(const struct checksums *);
/* get 0-terminated combined textual representation of the checksums,
......@@ -45,6 +44,8 @@ retvalue checksums_getcombined(const struct checksums *, /*@out@*/const char **,
/* get a static pointer to a specific part of a checksum (wihtout size) */
bool checksums_getpart(const struct checksums *, enum checksumtype, /*@out@*/const char **, /*@out@*/size_t *);
/* get the md5sum (including size) in old style format */
const char *checksums_getmd5sum(const struct checksums *);
/* extract a single checksum from the combined data: */
bool checksums_gethashpart(const struct checksums *, enum checksumtype, /*@out@*/const char **hash_p, /*@out@*/size_t *hashlen_p, /*@out@*/const char **size_p, /*@out@*/size_t *sizelen_p);
......@@ -60,6 +61,9 @@ retvalue checksums_linkorcopyfile(const char *destination, const char *origin, /
/* calculare checksums of a file: */
retvalue checksums_read(const char *fullfilename, /*@out@*/struct checksums **);
/* replace the contents of a file with data and calculate the new checksums */
retvalue checksums_replace(const char *filename, const char *, size_t len, /*@out@*//*@null@*/struct checksums **);
/* check if the file has the given md5sum (only cheap tests like size),
* RET_NOTHING means file does not exist, RET_ERROR_WRONG_MD5 means wrong size */
retvalue checksums_cheaptest(const char *fullfilename, const struct checksums *, bool);
......
......@@ -84,8 +84,7 @@ retvalue donefile_isold(const char *filename, const struct checksums *expected)
}
retvalue donefile_create(const char *filename, const struct checksums *checksums) {
retvalue r;
char *md5sum;
const char *md5sum;
const char *start;
size_t len;
ssize_t written;
......@@ -97,10 +96,7 @@ retvalue donefile_create(const char *filename, const struct checksums *checksums
donefilename = calc_addsuffix(filename,"done");
if( donefilename == NULL )
return RET_ERROR_OOM;
r = checksums_get(checksums, cs_md5sum, &md5sum);
assert( r != RET_NOTHING );
if( RET_WAS_ERROR(r) )
return r;
md5sum = checksums_getmd5sum(checksums);
fd = open(donefilename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_NOFOLLOW,
0666);
......@@ -109,7 +105,6 @@ retvalue donefile_create(const char *filename, const struct checksums *checksums
fprintf(stderr, "Error creating file %s: %d=%s\n",
donefilename, e, strerror(e));
free(donefilename);
free(md5sum);
return RET_ERRNO(e);
}
start = md5sum;
......@@ -120,7 +115,6 @@ retvalue donefile_create(const char *filename, const struct checksums *checksums
assert( len >= (size_t)written );
len -= written;
}
free(md5sum);
if( written < 0 ) {
int e = errno;
fprintf(stderr, "Error writing into %s: %d=%s\n",
......
......@@ -57,7 +57,7 @@ static retvalue files_get_checksums(struct database *database, const char *filek
if( RET_WAS_ERROR(r) )
return r;
if( r == RET_NOTHING )
return checksums_set(checksums_p, md5sum);
return checksums_parse(checksums_p, md5sum);
} else {
r = table_gettemprecord(database->checksums, filekey,
&checksums, &checksumslen);
......@@ -73,14 +73,10 @@ retvalue files_add_checksums(struct database *database, const char *filekey, con
size_t combinedlen;
if( database->oldmd5sums != NULL ) {
char *md5sum;
const char *md5sum;
r = checksums_get(checksums, cs_md5sum, &md5sum);
assert( r != RET_NOTHING);
if( !RET_IS_OK(r) )
return r;
md5sum = checksums_getmd5sum(checksums);
r = table_adduniqrecord(database->oldmd5sums, filekey, md5sum);
free(md5sum);
}
assert( database->checksums != NULL );
r = checksums_getcombined(checksums, &combined, &combinedlen);
......@@ -96,15 +92,11 @@ static retvalue files_replace_checksums(struct database *database, const char *f
size_t combinedlen;
if( database->oldmd5sums != NULL ) {
char *md5sum;
const char *md5sum;
r = checksums_get(checksums, cs_md5sum, &md5sum);
assert( r != RET_NOTHING);
if( !RET_IS_OK(r) )
return r;
md5sum = checksums_getmd5sum(checksums);
r = table_adduniqsizedrecord(database->oldmd5sums, filekey,
md5sum, strlen(md5sum) + 1, true, false);
free(md5sum);
}
assert( database->checksums != NULL );
r = checksums_getcombined(checksums, &combined, &combinedlen);
......@@ -633,7 +625,7 @@ retvalue files_checkpool(struct database *database, bool fast) {
nextcombined();
}
if( filekey == NULL || c > 0 ) {
r = checksums_set(&expected, md5sum);
r = checksums_parse(&expected, md5sum);
improveable = true;
} else {
size_t md5sumlen = strlen(md5sum);
......@@ -649,7 +641,7 @@ retvalue files_checkpool(struct database *database, bool fast) {
(void)cursor_delete(
database->checksums,
cursor2, filekey2, NULL);
r = checksums_set(&expected, md5sum);
r = checksums_parse(&expected, md5sum);
improveable = true;
} else {
r = checksums_setall(&expected,
......
/* This file is part of "reprepro"
* Copyright (C) 2006,2007 Bernhard R. Link
* Copyright (C) 2006,2007,2008 Bernhard R. Link
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
......@@ -563,26 +563,19 @@ static retvalue candidate_read(struct incoming *i, int ofs, struct candidate **r
static retvalue candidate_addfileline(struct incoming *i, struct candidate *c, const char *fileline) {
struct candidate_file **p, *n;
char *basename, *md5sum;
char *basename;
retvalue r;
n = calloc(1,sizeof(struct candidate_file));
if( n == NULL )
return RET_ERROR_OOM;
r = changes_parsefileline(fileline, &n->type, &basename, &md5sum,
r = changes_parsefileline(fileline, &n->type, &basename, &n->checksums,
&n->section, &n->priority, &n->architecture, &n->name);
if( RET_WAS_ERROR(r) ) {
free(n);
return r;
}
r = checksums_set(&n->checksums, md5sum);
free(md5sum);
if( RET_WAS_ERROR(r) ) {
free(basename);
candidate_file_free(n);
return r;
}
n->ofs = strlist_ofs(&i->files, basename);
if( n->ofs < 0 ) {
fprintf(stderr,"In '%s': file '%s' not found in the incoming dir!\n", i->files.values[c->ofs], basename);
......
/* This file is part of "reprepro"
* Copyright (C) 2003,2005 Bernhard R. Link
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include <config.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "error.h"
#include "mprintf.h"
#include "strlist.h"
#include "dirs.h"
#include "md5.h"
#include "md5sum.h"
#include "checksums.h"
#include "names.h"
extern int verbose;
static const char tab[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
static retvalue md5sum_genstring(char **md5,struct MD5Context *context,off_t filesize) {
unsigned char buffer[16];
char result[33],*md5sum;
unsigned int i;
MD5Final(buffer,context);
for(i=0;i<16;i++) {
result[i<<1] = tab[buffer[i] >> 4];
result[(i<<1)+1] = tab[buffer[i] & 0xF];
}
result[32] = '\0';
md5sum = mprintf("%s %lld",result,(long long)filesize);
if( md5sum == NULL )
return RET_ERROR_OOM;
*md5 = md5sum;
return RET_OK;
}
static retvalue md5sum_calc(int infd,int outfd, /*@out@*/char **result, size_t bufsize) {
struct MD5Context context;
unsigned char *buffer;
off_t filesize;
ssize_t sizeread;
int ret;
if( bufsize <= 0 )
bufsize = 16384;
buffer = malloc(bufsize);
if( buffer == NULL ) {
return RET_ERROR_OOM;
}
filesize = 0;
MD5Init(&context);
do {
sizeread = read(infd,buffer,bufsize);
if( sizeread < 0 ) {
ret = errno;
fprintf(stderr,"Error while reading: %m\n");
free(buffer);
return RET_ERRNO(ret);;
}
filesize += sizeread;
if( sizeread > 0 ) {
ssize_t written;
MD5Update(&context,buffer,sizeread);
if( outfd >= 0 ) {
written = write(outfd,buffer,sizeread);
if( written < 0 ) {
ret = errno;
fprintf(stderr,"Error while writing: %m\n");
free(buffer);
return RET_ERRNO(ret);;
}
if( written != sizeread ) {
fprintf(stderr,"Error while writing!\n");
free(buffer);
return RET_ERROR;
}
}
}
} while( sizeread > 0 );
free(buffer);
return md5sum_genstring(result,&context,filesize);
}
retvalue md5sum_read(const char *filename,char **result){
retvalue ret;
int fd,i;
assert(result != NULL);
fd = open(filename,O_RDONLY);
if( fd < 0 ) {
i = errno;
if( i == EACCES || i == ENOENT )
return RET_NOTHING;
else {
fprintf(stderr,"Error opening '%s': %d=%m!\n",filename,i);
return RET_ERRNO(i);
}
}
ret = md5sum_calc(fd,-1,result,0);
close(fd);
if( RET_IS_OK(ret) ) {
return RET_OK;
} else {
*result = NULL;
return ret;
}
}
retvalue md5sum_replace(const char *filename, const char *data, size_t len, char **result){
struct MD5Context context;
size_t todo; const char *towrite;
char *tempfilename;
int fd, ret;
retvalue r;
char *md5sum;
tempfilename = calc_addsuffix(filename,"new");
if( tempfilename == NULL )
return RET_ERROR_OOM;
fd = open(tempfilename, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY, 0666);
if( fd < 0 ) {
int e = errno;
fprintf(stderr, "ERROR creating '%s': %s\n", tempfilename,
strerror(e));
free(tempfilename);
return RET_ERRNO(e);
}
todo = len; towrite = data;
while( todo > 0 ) {
ssize_t written = write(fd, towrite, todo);
if( written >= 0 ) {
todo -= written;
towrite += written;
} else {
int e = errno;
close(fd);
fprintf(stderr, "Error writing to '%s': %s\n",
tempfilename, strerror(e));
unlink(tempfilename);
free(tempfilename);
return RET_ERRNO(e);
}
}
ret = close(fd);
if( ret < 0 ) {
int e = errno;
fprintf(stderr, "Error writing to '%s': %s\n",
tempfilename, strerror(e));
unlink(tempfilename);
free(tempfilename);
return RET_ERRNO(e);
}
if( result != NULL ) {
MD5Init(&context);
MD5Update(&context,(const unsigned char*)data,len);
r = md5sum_genstring(&md5sum, &context,len);
assert( r != RET_NOTHING );
if( RET_WAS_ERROR(r) ) {
unlink(tempfilename);
free(tempfilename);
return r;
}
} else
md5sum = NULL;
ret = rename(tempfilename, filename);
if( ret < 0 ) {
int e = errno;
free(md5sum);
fprintf(stderr, "Error moving '%s' to '%s': %s\n",
tempfilename, filename, strerror(e));
unlink(tempfilename);
free(tempfilename);
return RET_ERRNO(e);
}
free(tempfilename);
if( result != NULL )
*result = md5sum;
return RET_OK;
}
#ifndef REPREPRO_MD5SUM_H
#define REPREPRO_MD5SUM_H
#ifndef REPREPRO_ERROR_H
#include "error.h"
#warning "What's hapening here?"
#endif
/* Calculate the md5sum of the given file,
* returns RET_NOTHING, if it does not exist.*/
retvalue md5sum_read(const char *filename,/*@out@*/char **result);
/* replace the given name by data of size len and return its md5sum */
retvalue md5sum_replace(const char *filename, const char *data, size_t len, /*@null@*/char **md5sum);
#endif