Explorar o código

cope with out-of-disk-space halfways gracefully (that is, don't clobber
the sync state including the journal, but exit immediately).

Oswald Buddenhagen %!s(int64=20) %!d(string=hai) anos
pai
achega
c2209c8470
Modificáronse 1 ficheiros con 62 adicións e 28 borrados
  1. 62 28
      src/sync.c

+ 62 - 28
src/sync.c

@@ -33,6 +33,22 @@
 #include <errno.h>
 #include <sys/stat.h>
 
+void
+Fprintf( FILE *f, const char *msg, ... )
+{
+	int r;
+	va_list va;
+
+	va_start( va, msg );
+	r = vfprintf( f, msg, va );
+	va_end( va );
+	if (r < 0) {
+		perror( "cannot write file" );
+		exit( 1 );
+	}
+}
+
+
 static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
 
 static int
@@ -256,10 +272,10 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
 			default: /* ok */ break;
 			case DRV_OK:
 				if (pull) {
-					fprintf( jfp, "< %d %d 0\n", srec->muid, srec->suid );
+					Fprintf( jfp, "< %d %d 0\n", srec->muid, srec->suid );
 					srec->muid = 0;
 				} else {
-					fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
+					Fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
 					srec->suid = 0;
 				}
 			}
@@ -290,10 +306,10 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
 						case DRV_OK:
 							if (pull) {
 								srec->suid = uid;
-								fprintf( jfp, "> %d -1 %d\n", srec->muid, srec->suid );
+								Fprintf( jfp, "> %d -1 %d\n", srec->muid, srec->suid );
 							} else {
 								srec->muid = uid;
-								fprintf( jfp, "< -1 %d %d\n", srec->suid, srec->muid );
+								Fprintf( jfp, "< -1 %d %d\n", srec->suid, srec->muid );
 							}
 							*nflags = smsg->flags;
 						}
@@ -344,7 +360,7 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
 				if (unex) {
 					debug( "unexpiring pair(%d,%d)\n", srec->muid, srec->suid );
 					/* log last, so deletion can't be misinterpreted! */
-					fprintf( jfp, "~ %d %d 0\n", srec->muid, srec->suid );
+					Fprintf( jfp, "~ %d %d 0\n", srec->muid, srec->suid );
 					srec->status &= ~S_EXPIRED;
 				}
 			}
@@ -407,10 +423,10 @@ sync_new( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
 					srec->next = 0;
 					**srecadd = srec;
 					*srecadd = &srec->next;
-					fprintf( jfp, "+ %d %d %u\n", srec->muid, srec->suid, srec->flags );
+					Fprintf( jfp, "+ %d %d %u\n", srec->muid, srec->suid, srec->flags );
 					if (*smaxuid < msg->uid) {
 						*smaxuid = msg->uid;
-						fprintf( jfp, pull ? "( %d\n" : ") %d\n", msg->uid );
+						Fprintf( jfp, pull ? "( %d\n" : ") %d\n", msg->uid );
 					}
 				}
 			} else
@@ -522,7 +538,13 @@ sync_boxes( store_t *mctx, const char *mname,
 	}
 	if ((dfp = fopen( dname, "r" ))) {
 		debug( "reading sync state %s ...\n", dname );
-		if (fscanf( dfp, "%d:%d %d:%d:%d\n", &muidval, &mmaxuid, &suidval, &smaxxuid, &smaxuid) != 5) {
+		if (!fgets( buf, sizeof(buf), dfp ) || !(i = strlen( buf )) || buf[i - 1] != '\n') {
+			fprintf( stderr, "Error: incomplete sync state header in %s\n", dname );
+			fclose( dfp );
+			ret = SYNC_FAIL;
+			goto bail;
+		}
+		if (sscanf( buf, "%d:%d %d:%d:%d", &muidval, &mmaxuid, &suidval, &smaxxuid, &smaxuid) != 5) {
 			fprintf( stderr, "Error: invalid sync state header in %s\n", dname );
 			fclose( dfp );
 			ret = SYNC_FAIL;
@@ -531,8 +553,14 @@ sync_boxes( store_t *mctx, const char *mname,
 		line = 1;
 		while (fgets( buf, sizeof(buf), dfp )) {
 			line++;
+			if (!(i = strlen( buf )) || buf[i - 1] != '\n') {
+				fprintf( stderr, "Error: incomplete sync state entry at %s:%d\n", dname, line );
+				fclose( dfp );
+				ret = SYNC_FAIL;
+				goto bail;
+			}
 			fbuf[0] = 0;
-			if (sscanf( buf, "%d %d %15s\n", &t1, &t2, fbuf ) < 2) {
+			if (sscanf( buf, "%d %d %15s", &t1, &t2, fbuf ) < 2) {
 				fprintf( stderr, "Error: invalid sync state entry at %s:%d\n", dname, line );
 				fclose( dfp );
 				ret = SYNC_FAIL;
@@ -568,14 +596,20 @@ sync_boxes( store_t *mctx, const char *mname,
 			srec = recs;
 			while (fgets( buf, sizeof(buf), jfp )) {
 				line++;
+				if (!(i = strlen( buf )) || buf[i - 1] != '\n') {
+					fprintf( stderr, "Error: incomplete journal entry at %s:%d\n", jname, line );
+					fclose( jfp );
+					ret = SYNC_FAIL;
+					goto bail;
+				}
 				if (buf[0] == '^')
 					srec = recs;
 				else {
 					if (buf[0] == '(' || buf[0] == ')' ?
-					        (sscanf( buf + 2, "%d\n", &t1 ) != 1) :
+					        (sscanf( buf + 2, "%d", &t1 ) != 1) :
 					    buf[0] == '-' || buf[0] == '|' ?
-						(sscanf( buf + 2, "%d %d\n", &t1, &t2 ) != 2) :
-						(sscanf( buf + 2, "%d %d %d\n", &t1, &t2, &t3 ) != 3))
+						(sscanf( buf + 2, "%d %d", &t1, &t2 ) != 2) :
+						(sscanf( buf + 2, "%d %d %d", &t1, &t2, &t3 ) != 3))
 					{
 						fprintf( stderr, "Error: malformed journal entry at %s:%d\n", jname, line );
 						fclose( jfp );
@@ -719,7 +753,7 @@ sync_boxes( store_t *mctx, const char *mname,
 				minwuid = srec->muid;
 		}
 		debug( "  min non-orphaned master uid is %d\n", minwuid );
-		fprintf( jfp, "^\n" ); /* if any S_EXP_SLAVE */
+		Fprintf( jfp, "^\n" ); /* if any S_EXP_SLAVE */
 		for (srec = recs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
@@ -727,10 +761,10 @@ sync_boxes( store_t *mctx, const char *mname,
 				if (minwuid > srec->muid && mmaxuid >= srec->muid) {
 					debug( "  -> killing (%d,%d)\n", srec->muid, srec->suid );
 					srec->status = S_DEAD;
-					fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
+					Fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
 				} else if (srec->suid) {
 					debug( "  -> orphaning (%d,[%d])\n", srec->muid, srec->suid );
-					fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
+					Fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
 					srec->suid = 0;
 				}
 			} else if (minwuid > srec->muid) {
@@ -738,7 +772,7 @@ sync_boxes( store_t *mctx, const char *mname,
 					if (mmaxuid >= srec->muid) {
 						debug( "  -> killing (%d,%d)\n", srec->muid, srec->suid );
 						srec->status = S_DEAD;
-						fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
+						Fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
 					}
 				} else if (srec->muid > 0 && srec->suid && (mctx->opts & OPEN_OLD) &&
 				           (!(mctx->opts & OPEN_NEW) || mmaxuid >= srec->muid)) {
@@ -785,12 +819,12 @@ sync_boxes( store_t *mctx, const char *mname,
 	if (!muidval || !suidval) {
 		muidval = mctx->uidvalidity;
 		suidval = sctx->uidvalidity;
-		fprintf( jfp, "| %d %d\n", muidval, suidval );
+		Fprintf( jfp, "| %d %d\n", muidval, suidval );
 	}
 
 	info( "Synchronizing\n" );
 	debug( "synchronizing old entries\n" );
-	fprintf( jfp, "^\n" );
+	Fprintf( jfp, "^\n" );
 	for (srec = recs; srec; srec = srec->next) {
 		if (srec->status & S_DEAD)
 			continue;
@@ -803,7 +837,7 @@ sync_boxes( store_t *mctx, const char *mname,
 			debug( "  vanished\n" );
 			/* d.1) d.5) d.6) d.10) d.11) */
 			srec->status = S_DEAD;
-			fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
+			Fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
 		} else {
 			delm = nom && (srec->muid > 0);
 			dels = nos && (srec->suid > 0);
@@ -816,7 +850,7 @@ sync_boxes( store_t *mctx, const char *mname,
 			if (srec->flags != nflags) {
 				debug( "  updating flags (%u -> %u)\n", srec->flags, nflags );
 				srec->flags = nflags;
-				fprintf( jfp, "* %d %d %u\n", srec->muid, srec->suid, nflags );
+				Fprintf( jfp, "* %d %d %u\n", srec->muid, srec->suid, nflags );
 			}
 			if (mmsg && (mmsg->flags & F_DELETED))
 				srec->status |= S_DEL_MASTER;
@@ -849,7 +883,7 @@ sync_boxes( store_t *mctx, const char *mname,
 			}
 		}
 		if (delt) {
-			fprintf( jfp, "^\n" );
+			Fprintf( jfp, "^\n" );
 			for (srec = recs; srec; srec = srec->next) {
 				if (srec->status & (S_DEAD|S_EXPIRED))
 					continue;
@@ -857,7 +891,7 @@ sync_boxes( store_t *mctx, const char *mname,
 				if (smsg && (smsg->status & M_EXPIRED)) {
 					debug( "  expiring pair(%d,%d)\n", srec->muid, srec->suid );
 					/* log first, so deletion can't be misinterpreted! */
-					fprintf( jfp, "~ %d %d 1\n", srec->muid, srec->suid );
+					Fprintf( jfp, "~ %d %d 1\n", srec->muid, srec->suid );
 					if (smaxxuid < srec->suid)
 						smaxxuid = srec->suid;
 					srec->status |= S_EXPIRED;
@@ -914,7 +948,7 @@ sync_boxes( store_t *mctx, const char *mname,
 			debug( "  min non-orphaned master uid is %d\n", minwuid );
 		}
 
-		fprintf( jfp, "^\n" );
+		Fprintf( jfp, "^\n" );
 		for (srec = recs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
@@ -922,15 +956,15 @@ sync_boxes( store_t *mctx, const char *mname,
 				if (srec->muid <= 0 || ((srec->status & S_DEL_MASTER) && mex)) {
 					debug( "  -> killing (%d,%d)\n", srec->muid, srec->suid );
 					srec->status = S_DEAD;
-					fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
+					Fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
 				} else if (srec->status & S_EXPIRED) {
 					if (mmaxuid >= srec->muid && minwuid > srec->muid) {
 						debug( "  -> killing (%d,%d)\n", srec->muid, srec->suid );
 						srec->status = S_DEAD;
-						fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
+						Fprintf( jfp, "- %d %d\n", srec->muid, srec->suid );
 					} else if (srec->suid) {
 						debug( "  -> orphaning (%d,[%d])\n", srec->muid, srec->suid );
-						fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
+						Fprintf( jfp, "> %d %d 0\n", srec->muid, srec->suid );
 						srec->suid = 0;
 					}
 				}
@@ -939,12 +973,12 @@ sync_boxes( store_t *mctx, const char *mname,
 	}
 
   finish:
-	fprintf( nfp, "%d:%d %d:%d:%d\n", muidval, mmaxuid, suidval, smaxxuid, smaxuid );
+	Fprintf( nfp, "%d:%d %d:%d:%d\n", muidval, mmaxuid, suidval, smaxxuid, smaxuid );
 	for (srec = recs; srec; srec = srec->next) {
 		if (srec->status & S_DEAD)
 			continue;
 		make_flags( srec->flags, fbuf );
-		fprintf( nfp, "%d %d %s%s\n", srec->muid, srec->suid,
+		Fprintf( nfp, "%d %d %s%s\n", srec->muid, srec->suid,
 		         srec->status & S_EXPIRED ? "X" : "", fbuf );
 	}