Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 185 lines (164 sloc) 4.426 kB
b4bd052 @pietern tool to check if AOF is valid
pietern authored
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
4 #include <unistd.h>
b4bd052 @pietern tool to check if AOF is valid
pietern authored
5 #include <sys/stat.h>
6 #include "config.h"
7
8 #define ERROR(...) { \
9 char __buf[1024]; \
10 sprintf(__buf, __VA_ARGS__); \
11 sprintf(error, "0x%08lx: %s", epos, __buf); \
12 }
13
14 static char error[1024];
15 static long epos;
16
17 int consumeNewline(char *buf) {
18 if (strncmp(buf,"\r\n",2) != 0) {
19 ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]);
20 return 0;
21 }
22 return 1;
23 }
24
25 int readLong(FILE *fp, char prefix, long *target) {
26 char buf[128], *eptr;
27 epos = ftell(fp);
28 if (fgets(buf,sizeof(buf),fp) == NULL) {
29 return 0;
30 }
31 if (buf[0] != prefix) {
32 ERROR("Expected prefix '%c', got: '%c'",buf[0],prefix);
33 return 0;
34 }
35 *target = strtol(buf+1,&eptr,10);
36 return consumeNewline(eptr);
37 }
38
39 int readBytes(FILE *fp, char *target, long length) {
40 long real;
41 epos = ftell(fp);
42 real = fread(target,1,length,fp);
43 if (real != length) {
44 ERROR("Expected to read %ld bytes, got %ld bytes",length,real);
45 return 0;
46 }
47 return 1;
48 }
49
50 int readString(FILE *fp, char** target) {
51 long len;
52 *target = NULL;
53 if (!readLong(fp,'$',&len)) {
54 return 0;
55 }
56
57 /* Increase length to also consume \r\n */
58 len += 2;
59 *target = (char*)malloc(len);
60 if (!readBytes(fp,*target,len)) {
61 return 0;
62 }
63 if (!consumeNewline(*target+len-2)) {
64 return 0;
65 }
66 (*target)[len-2] = '\0';
67 return 1;
68 }
69
70 int readArgc(FILE *fp, long *target) {
71 return readLong(fp,'*',target);
72 }
73
74 long process(FILE *fp) {
75 long argc, pos = 0;
76 int i, multi = 0;
77 char *str;
78
79 while(1) {
80 if (!multi) pos = ftell(fp);
e51fa06 @pietern str can be free'd outside readString
pietern authored
81 if (!readArgc(fp, &argc)) break;
b4bd052 @pietern tool to check if AOF is valid
pietern authored
82
83 for (i = 0; i < argc; i++) {
e51fa06 @pietern str can be free'd outside readString
pietern authored
84 if (!readString(fp,&str)) break;
b4bd052 @pietern tool to check if AOF is valid
pietern authored
85 if (i == 0) {
86 if (strcasecmp(str, "multi") == 0) {
87 if (multi++) {
88 ERROR("Unexpected MULTI");
89 break;
90 }
91 } else if (strcasecmp(str, "exec") == 0) {
92 if (--multi) {
93 ERROR("Unexpected EXEC");
94 break;
95 }
96 }
97 }
98 free(str);
99 }
100
e51fa06 @pietern str can be free'd outside readString
pietern authored
101 /* Stop if the loop did not finish */
b4bd052 @pietern tool to check if AOF is valid
pietern authored
102 if (i < argc) {
103 if (str) free(str);
104 break;
105 }
106 }
107
108 if (feof(fp) && multi && strlen(error) == 0) {
109 ERROR("Reached EOF before reading EXEC for MULTI");
110 }
111 if (strlen(error) > 0) {
112 printf("%s\n", error);
113 }
114 return pos;
115 }
116
117 int main(int argc, char **argv) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
118 char *filename;
119 int fix = 0;
57ca68a @pietern moved argument parsing around
pietern authored
120
121 if (argc < 2) {
122 printf("Usage: %s [--fix] <file.aof>\n", argv[0]);
123 exit(1);
124 } else if (argc == 2) {
125 filename = argv[1];
126 } else if (argc == 3) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
127 if (strcmp(argv[1],"--fix") != 0) {
128 printf("Invalid argument: %s\n", argv[1]);
129 exit(1);
130 }
131 filename = argv[2];
57ca68a @pietern moved argument parsing around
pietern authored
132 fix = 1;
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
133 } else {
57ca68a @pietern moved argument parsing around
pietern authored
134 printf("Invalid arguments\n");
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
135 exit(1);
136 }
137
138 FILE *fp = fopen(filename,"r+");
b4bd052 @pietern tool to check if AOF is valid
pietern authored
139 if (fp == NULL) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
140 printf("Cannot open file: %s\n", filename);
b4bd052 @pietern tool to check if AOF is valid
pietern authored
141 exit(1);
142 }
143
144 struct redis_stat sb;
145 if (redis_fstat(fileno(fp),&sb) == -1) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
146 printf("Cannot stat file: %s\n", filename);
b4bd052 @pietern tool to check if AOF is valid
pietern authored
147 exit(1);
148 }
149
150 long size = sb.st_size;
151 if (size == 0) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
152 printf("Empty file: %s\n", filename);
b4bd052 @pietern tool to check if AOF is valid
pietern authored
153 exit(1);
154 }
155
156 long pos = process(fp);
8133014 @pietern ask for confirmation before AOF is truncated
pietern authored
157 long diff = size-pos;
158 if (diff > 0) {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
159 if (fix) {
8133014 @pietern ask for confirmation before AOF is truncated
pietern authored
160 char buf[2];
161 printf("This will shrink the AOF from %ld bytes, with %ld bytes, to %ld bytes\n",size,diff,pos);
162 printf("Continue? [y/N]: ");
163 if (fgets(buf,sizeof(buf),stdin) == NULL ||
164 strncasecmp(buf,"y",1) != 0) {
165 printf("Aborting...\n");
166 exit(1);
167 }
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
168 if (ftruncate(fileno(fp), pos) == -1) {
8133014 @pietern ask for confirmation before AOF is truncated
pietern authored
169 printf("Failed to truncate AOF\n");
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
170 exit(1);
171 } else {
8133014 @pietern ask for confirmation before AOF is truncated
pietern authored
172 printf("Successfully truncated AOF\n");
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
173 }
174 } else {
8133014 @pietern ask for confirmation before AOF is truncated
pietern authored
175 printf("AOF is not valid\n");
176 exit(1);
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
177 }
b4bd052 @pietern tool to check if AOF is valid
pietern authored
178 } else {
cb8ae3c @pietern allow AOF to be fixed by truncating to the portion of the file that i…
pietern authored
179 printf("AOF is valid\n");
b4bd052 @pietern tool to check if AOF is valid
pietern authored
180 }
181
182 fclose(fp);
183 return 0;
184 }
Something went wrong with that request. Please try again.