make checkpoint stuff actually proper
This commit is contained in:
parent
f575bbe011
commit
5b4074a47e
150
ioutil.c
150
ioutil.c
@ -2,6 +2,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "ioutil.h"
|
#include "ioutil.h"
|
||||||
|
#include "vec.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ FH createfile(const char *path,int secret)
|
|||||||
int fd;
|
int fd;
|
||||||
do {
|
do {
|
||||||
fd = open(path,O_WRONLY | O_CREAT | O_TRUNC,secret ? 0600 : 0666);
|
fd = open(path,O_WRONLY | O_CREAT | O_TRUNC,secret ? 0600 : 0666);
|
||||||
if (fd == -1) {
|
if (fd < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
return -1;
|
return -1;
|
||||||
@ -45,7 +47,7 @@ int closefile(FH fd)
|
|||||||
int cret;
|
int cret;
|
||||||
do {
|
do {
|
||||||
cret = close(fd);
|
cret = close(fd);
|
||||||
if (cret == -1) {
|
if (cret < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
return -1;
|
return -1;
|
||||||
@ -59,6 +61,107 @@ int createdir(const char *path,int secret)
|
|||||||
return mkdir(path,secret ? 0700 : 0777);
|
return mkdir(path,secret ? 0700 : 0777);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int syncwrite(const char *filename,int secret,const u8 *data,size_t datalen)
|
||||||
|
{
|
||||||
|
//fprintf(stderr,"filename = %s\n",filename);
|
||||||
|
|
||||||
|
VEC_STRUCT(,char) tmpname;
|
||||||
|
size_t fnlen = strlen(filename);
|
||||||
|
VEC_INIT(tmpname);
|
||||||
|
VEC_ADDN(tmpname,fnlen + 4 /* ".tmp" */ + 1 /* "\0" */);
|
||||||
|
memcpy(&VEC_BUF(tmpname,0),filename,fnlen);
|
||||||
|
strcpy(&VEC_BUF(tmpname,fnlen),".tmp");
|
||||||
|
const char *tmpnamestr = &VEC_BUF(tmpname,0);
|
||||||
|
|
||||||
|
//fprintf(stderr,"tmpnamestr = %s\n",tmpnamestr);
|
||||||
|
|
||||||
|
FH f = createfile(tmpnamestr,secret);
|
||||||
|
if (f == FH_invalid)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (writeall(f,data,datalen) < 0) {
|
||||||
|
closefile(f);
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sret;
|
||||||
|
do {
|
||||||
|
sret = fsync(f);
|
||||||
|
if (sret < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
closefile(f);
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
if (closefile(f) < 0) {
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(tmpnamestr,filename) < 0) {
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VEC_STRUCT(,char) dirname;
|
||||||
|
const char *dirnamestr;
|
||||||
|
|
||||||
|
for (ssize_t x = ((ssize_t)fnlen) - 1;x >= 0;--x) {
|
||||||
|
if (filename[x] == '/') {
|
||||||
|
if (x)
|
||||||
|
--x;
|
||||||
|
++x;
|
||||||
|
VEC_INIT(dirname);
|
||||||
|
VEC_ADDN(dirname,x + 1);
|
||||||
|
memcpy(&VEC_BUF(dirname,0),filename,x);
|
||||||
|
VEC_BUF(dirname,x) = '\0';
|
||||||
|
dirnamestr = &VEC_BUF(dirname,0);
|
||||||
|
goto foundslash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* not found slash, fall back to "." */
|
||||||
|
dirnamestr = ".";
|
||||||
|
|
||||||
|
foundslash:
|
||||||
|
//fprintf(stderr,"dirnamestr = %s\n",dirnamestr);
|
||||||
|
;
|
||||||
|
|
||||||
|
int dirf;
|
||||||
|
do {
|
||||||
|
dirf = open(dirnamestr,O_RDONLY);
|
||||||
|
if (dirf < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// failed for non-eintr reasons
|
||||||
|
goto skipdsync; // don't really care enough
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
sret = fsync(dirf);
|
||||||
|
if (sret < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// failed for non-eintr reasons
|
||||||
|
break; // don't care
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
(void) closefile(dirf); // don't care
|
||||||
|
|
||||||
|
skipdsync:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int writeall(FH fd,const u8 *data,size_t len)
|
int writeall(FH fd,const u8 *data,size_t len)
|
||||||
@ -99,6 +202,49 @@ int createdir(const char *path,int secret)
|
|||||||
return CreateDirectoryA(path,0) ? 0 : -1;
|
return CreateDirectoryA(path,0) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int syncwrite(const char *filename,int secret,const char *data,size_t datalen)
|
||||||
|
{
|
||||||
|
VEC_STRUCT(,char) tmpname;
|
||||||
|
size_t fnlen = strlen(filename);
|
||||||
|
VEC_INIT(tmpname);
|
||||||
|
VEC_ADDN(tmpname,fnlen + 4 /* ".tmp" */ + 1 /* "\0" */);
|
||||||
|
memcpy(&VEC_BUF(tmpname,0),filename,fnlen);
|
||||||
|
strcpy(&VEC_BUF(tmpname,fnlen),".tmp");
|
||||||
|
const char *tmpnamestr = &VEC_BUF(tmpname,0);
|
||||||
|
|
||||||
|
FH f = createfile(tmpnamestr,secret)
|
||||||
|
if (f == FH_invalid)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (writeall(f,data,datalen) < 0) {
|
||||||
|
closefile(f);
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FlushFileBuffers(f) == 0) {
|
||||||
|
closefile(f);
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closefile(f) < 0) {
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MoveFileA(tmpnamestr,filename) == 0) {
|
||||||
|
remove(tmpnamestr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't fsync parent dir on windows so just end here
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int writetofile(const char *path,const u8 *data,size_t len,int secret)
|
int writetofile(const char *path,const u8 *data,size_t len,int secret)
|
||||||
|
1
ioutil.h
1
ioutil.h
@ -18,3 +18,4 @@ int closefile(FH fd);
|
|||||||
int writeall(FH,const u8 *data,size_t len);
|
int writeall(FH,const u8 *data,size_t len);
|
||||||
int writetofile(const char *path,const u8 *data,size_t len,int secret);
|
int writetofile(const char *path,const u8 *data,size_t len,int secret);
|
||||||
int createdir(const char *path,int secret);
|
int createdir(const char *path,int secret);
|
||||||
|
int syncwrite(const char *filename,int secret,const u8 *data,size_t datalen);
|
||||||
|
114
main.c
114
main.c
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "worker.h"
|
#include "worker.h"
|
||||||
|
|
||||||
|
#include "likely.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define FSZ "%zu"
|
#define FSZ "%zu"
|
||||||
#else
|
#else
|
||||||
@ -182,35 +184,55 @@ static void setpassphrase(const char *pass)
|
|||||||
|
|
||||||
static void savecheckpoint(void)
|
static void savecheckpoint(void)
|
||||||
{
|
{
|
||||||
if (checkpointfile) {
|
u8 checkpoint[SEED_LEN];
|
||||||
// Open checkpoint file
|
bool carry = 0;
|
||||||
FILE *checkout = fopen(checkpointfile, "w");
|
pthread_mutex_lock(&determseed_mutex);
|
||||||
if (!checkout) {
|
for (int i = 0; i < SEED_LEN; i++) {
|
||||||
fprintf(stderr,"cannot open checkpoint file for writing\n");
|
checkpoint[i] = determseed[i] - orig_determseed[i] - carry;
|
||||||
exit(1);
|
carry = checkpoint[i] > determseed[i];
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate checkpoint as the difference between original seed and the current seed
|
|
||||||
u8 checkpoint[SEED_LEN];
|
|
||||||
bool carry = 0;
|
|
||||||
pthread_mutex_lock(&determseed_mutex);
|
|
||||||
for (int i = 0; i < SEED_LEN; i++) {
|
|
||||||
checkpoint[i] = determseed[i] - orig_determseed[i] - carry;
|
|
||||||
carry = checkpoint[i] > determseed[i];
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&determseed_mutex);
|
|
||||||
|
|
||||||
// Write checkpoint file
|
|
||||||
if(fwrite(checkpoint, 1, SEED_LEN, checkout) != SEED_LEN) {
|
|
||||||
fprintf(stderr,"cannot write to checkpoint file\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fclose(checkout);
|
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&determseed_mutex);
|
||||||
|
|
||||||
|
if (syncwrite(checkpointfile,1,checkpoint,SEED_LEN) < 0) {
|
||||||
|
pthread_mutex_lock(&fout_mutex);
|
||||||
|
fprintf(stderr,"ERROR: could not save checkpoint\n");
|
||||||
|
pthread_mutex_unlock(&fout_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile int checkpointer_endwork = 0;
|
||||||
|
|
||||||
|
static void *checkpointworker(void *arg)
|
||||||
|
{
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
struct timespec ts;
|
||||||
|
memset(&ts,0,sizeof(ts));
|
||||||
|
ts.tv_nsec = 100000000;
|
||||||
|
|
||||||
|
struct timespec nowtime;
|
||||||
|
u64 ilasttime,inowtime;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC,&nowtime);
|
||||||
|
ilasttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
|
||||||
|
|
||||||
|
while (!unlikely(checkpointer_endwork)) {
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC,&nowtime);
|
||||||
|
inowtime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
|
||||||
|
|
||||||
|
if (inowtime - ilasttime >= 300 * 1000000 /* 5 minutes */) {
|
||||||
|
savecheckpoint();
|
||||||
|
ilasttime = inowtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
savecheckpoint();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VEC_STRUCT(threadvec, pthread_t);
|
VEC_STRUCT(threadvec,pthread_t);
|
||||||
|
|
||||||
#include "filters_inc.inc.h"
|
#include "filters_inc.inc.h"
|
||||||
#include "filters_main.inc.h"
|
#include "filters_main.inc.h"
|
||||||
@ -458,6 +480,11 @@ int main(int argc,char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkpointfile && !deterministic) {
|
||||||
|
fprintf(stderr,"--checkpoint requires passphrase\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (outfile) {
|
if (outfile) {
|
||||||
fout = fopen(outfile,!outfileoverwrite ? "a" : "w");
|
fout = fopen(outfile,!outfileoverwrite ? "a" : "w");
|
||||||
if (!fout) {
|
if (!fout) {
|
||||||
@ -543,16 +570,16 @@ int main(int argc,char **argv)
|
|||||||
numthreads,numthreads == 1 ? "thread" : "threads");
|
numthreads,numthreads == 1 ? "thread" : "threads");
|
||||||
|
|
||||||
#ifdef PASSPHRASE
|
#ifdef PASSPHRASE
|
||||||
memcpy(orig_determseed, determseed, sizeof(determseed));
|
|
||||||
if (deterministic) {
|
if (deterministic) {
|
||||||
|
memcpy(orig_determseed,determseed,sizeof(determseed));
|
||||||
if (!quietflag && numneedgenerate != 1)
|
if (!quietflag && numneedgenerate != 1)
|
||||||
fprintf(stderr,"CAUTION: avoid using keys generated with same password for unrelated services, as single leaked key may help attacker to regenerate related keys.\n");
|
fprintf(stderr,"CAUTION: avoid using keys generated with same password for unrelated services, as single leaked key may help attacker to regenerate related keys.\n");
|
||||||
if (checkpointfile) {
|
if (checkpointfile) {
|
||||||
// Read current checkpoint position if file exists
|
// Read current checkpoint position if file exists
|
||||||
FILE *checkout = fopen(checkpointfile, "r");
|
FILE *checkout = fopen(checkpointfile,"r");
|
||||||
if (checkout) {
|
if (checkout) {
|
||||||
u8 checkpoint[SEED_LEN];
|
u8 checkpoint[SEED_LEN];
|
||||||
if(fread(checkpoint, 1, SEED_LEN, checkout) != SEED_LEN) {
|
if(fread(checkpoint,1,SEED_LEN,checkout) != SEED_LEN) {
|
||||||
fprintf(stderr,"failed to read checkpoint file\n");
|
fprintf(stderr,"failed to read checkpoint file\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -634,6 +661,18 @@ int main(int argc,char **argv)
|
|||||||
perror("pthread_attr_destroy");
|
perror("pthread_attr_destroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if PASSPHRASE
|
||||||
|
pthread_t checkpoint_thread;
|
||||||
|
|
||||||
|
if (checkpointfile) {
|
||||||
|
tret = pthread_create(&checkpoint_thread,NULL,checkpointworker,NULL);
|
||||||
|
if (tret) {
|
||||||
|
fprintf(stderr,"error while making checkpoint thread: %s\n",strerror(tret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef STATISTICS
|
#ifdef STATISTICS
|
||||||
struct timespec nowtime;
|
struct timespec nowtime;
|
||||||
u64 istarttime,inowtime,ireporttime = 0,elapsedoffset = 0;
|
u64 istarttime,inowtime,ireporttime = 0,elapsedoffset = 0;
|
||||||
@ -643,20 +682,15 @@ int main(int argc,char **argv)
|
|||||||
}
|
}
|
||||||
istarttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
|
istarttime = (1000000 * (u64)nowtime.tv_sec) + ((u64)nowtime.tv_nsec / 1000);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
memset(&ts,0,sizeof(ts));
|
memset(&ts,0,sizeof(ts));
|
||||||
ts.tv_nsec = 100000000;
|
ts.tv_nsec = 100000000;
|
||||||
u16 loopcounter = 0;
|
|
||||||
while (!endwork) {
|
while (!endwork) {
|
||||||
if (numneedgenerate && keysgenerated >= numneedgenerate) {
|
if (numneedgenerate && keysgenerated >= numneedgenerate) {
|
||||||
endwork = 1;
|
endwork = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
loopcounter++;
|
|
||||||
if (loopcounter >= 3000) { // Save checkpoint every 5 minutes
|
|
||||||
savecheckpoint();
|
|
||||||
loopcounter = 0;
|
|
||||||
}
|
|
||||||
nanosleep(&ts,0);
|
nanosleep(&ts,0);
|
||||||
|
|
||||||
#ifdef STATISTICS
|
#ifdef STATISTICS
|
||||||
@ -722,14 +756,18 @@ int main(int argc,char **argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PASSPHRASE
|
|
||||||
savecheckpoint();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!quietflag)
|
if (!quietflag)
|
||||||
fprintf(stderr,"waiting for threads to finish...");
|
fprintf(stderr,"waiting for threads to finish...");
|
||||||
|
|
||||||
for (size_t i = 0;i < VEC_LENGTH(threads);++i)
|
for (size_t i = 0;i < VEC_LENGTH(threads);++i)
|
||||||
pthread_join(VEC_BUF(threads,i),0);
|
pthread_join(VEC_BUF(threads,i),0);
|
||||||
|
#ifdef PASSPHRASE
|
||||||
|
if (checkpointfile) {
|
||||||
|
checkpointer_endwork = 1;
|
||||||
|
pthread_join(checkpoint_thread,0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!quietflag)
|
if (!quietflag)
|
||||||
fprintf(stderr," done.\n");
|
fprintf(stderr," done.\n");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user