Commit b5b8f8556365b70a207fd5dd4924d041c378a394
1 parent
1e868e43
Made return codes a bit more sane, and used the return codes from libnbt
Showing
1 changed file
with
111 additions
and
70 deletions
mcpetbackup.c
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <getopt.h> | 2 | #include <getopt.h> |
3 | #include <dirent.h> | 3 | #include <dirent.h> |
4 | +#include <fcntl.h> | ||
5 | +#include <errno.h> | ||
6 | +#include <unistd.h> | ||
7 | +#include <sys/stat.h> | ||
8 | +#include <stdint.h> | ||
4 | 9 | ||
5 | #include "nbt.h" | 10 | #include "nbt.h" |
6 | #include "chunk.h" | 11 | #include "chunk.h" |
7 | 12 | ||
8 | -enum paramIndex | ||
9 | -{ | 13 | +enum paramIndex { |
10 | UNKNOWN = 0, | 14 | UNKNOWN = 0, |
11 | HELP, | 15 | HELP, |
12 | REGION, | 16 | REGION, |
@@ -36,13 +40,17 @@ static struct option longopts[] = { | @@ -36,13 +40,17 @@ static struct option longopts[] = { | ||
36 | 40 | ||
37 | int savePetToFile(Tag* pet, const char* filename) { | 41 | int savePetToFile(Tag* pet, const char* filename) { |
38 | void* petData; | 42 | void* petData; |
39 | - size_t petDataLength = composeTag(*pet, &petData); | 43 | + ssize_t petDataLength = composeTag(*pet, &petData); |
44 | + if(petDataLength < 0) { | ||
45 | + fprintf(stderr,"Error while composing pet tag: code %d\n",(int)petDataLength); | ||
46 | + return petDataLength; | ||
47 | + } | ||
40 | 48 | ||
41 | int fd = open(filename,O_CREAT|O_WRONLY,0644); | 49 | int fd = open(filename,O_CREAT|O_WRONLY,0644); |
42 | if(fd == -1) { | 50 | if(fd == -1) { |
43 | fprintf(stderr,"Unable to open file to save pet: %s\n",strerror(errno)); | 51 | fprintf(stderr,"Unable to open file to save pet: %s\n",strerror(errno)); |
44 | free(petData); | 52 | free(petData); |
45 | - return 1; | 53 | + return -1; |
46 | } | 54 | } |
47 | ssize_t nWritten = 0; | 55 | ssize_t nWritten = 0; |
48 | size_t totalWritten = 0; | 56 | size_t totalWritten = 0; |
@@ -55,7 +63,7 @@ int savePetToFile(Tag* pet, const char* filename) { | @@ -55,7 +63,7 @@ int savePetToFile(Tag* pet, const char* filename) { | ||
55 | fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); | 63 | fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); |
56 | close(fd); | 64 | close(fd); |
57 | free(petData); | 65 | free(petData); |
58 | - return 2; | 66 | + return -2; |
59 | } | 67 | } |
60 | totalWritten += nWritten; | 68 | totalWritten += nWritten; |
61 | } | 69 | } |
@@ -69,14 +77,14 @@ int loadPetFromFile(Tag* pet, const char* filename) { | @@ -69,14 +77,14 @@ int loadPetFromFile(Tag* pet, const char* filename) { | ||
69 | int fd = open(filename,O_RDONLY); | 77 | int fd = open(filename,O_RDONLY); |
70 | if(fd == -1) { | 78 | if(fd == -1) { |
71 | fprintf(stderr,"Unable to open file to load pet: %s\n",strerror(errno)); | 79 | fprintf(stderr,"Unable to open file to load pet: %s\n",strerror(errno)); |
72 | - return 1; | 80 | + return -1; |
73 | } | 81 | } |
74 | 82 | ||
75 | struct stat sb; | 83 | struct stat sb; |
76 | if(stat(filename,&sb) == -1) { | 84 | if(stat(filename,&sb) == -1) { |
77 | fprintf(stderr,"Unable to stat() file to load pet: %s\n",strerror(errno)); | 85 | fprintf(stderr,"Unable to stat() file to load pet: %s\n",strerror(errno)); |
78 | close(fd); | 86 | close(fd); |
79 | - return 2; | 87 | + return -2; |
80 | } | 88 | } |
81 | void* petData = calloc(sb.st_size,sizeof(uint8_t)); | 89 | void* petData = calloc(sb.st_size,sizeof(uint8_t)); |
82 | 90 | ||
@@ -91,17 +99,22 @@ int loadPetFromFile(Tag* pet, const char* filename) { | @@ -91,17 +99,22 @@ int loadPetFromFile(Tag* pet, const char* filename) { | ||
91 | fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); | 99 | fprintf(stderr,"Unable to write pet data: %s\n",strerror(errno)); |
92 | close(fd); | 100 | close(fd); |
93 | free(petData); | 101 | free(petData); |
94 | - return 3; | 102 | + return -3; |
95 | } | 103 | } |
96 | totalRead += nRead; | 104 | totalRead += nRead; |
97 | } | 105 | } |
98 | close(fd); | 106 | close(fd); |
99 | 107 | ||
100 | - size_t pos = parseTag(petData,pet); | 108 | + ssize_t pos = parseTag(petData,pet); |
109 | + if(pos < 0) { | ||
110 | + fprintf(stderr,"Error parsing pet data: code %d\n",(int)pos); | ||
111 | + free(petData); | ||
112 | + return pos; | ||
113 | + } | ||
101 | if(pos != sb.st_size) { | 114 | if(pos != sb.st_size) { |
102 | - fprintf(stderr,"Error parsing pet data\n"); | 115 | + fprintf(stderr,"Didn't reach end of database while parsing\n"); |
103 | free(petData); | 116 | free(petData); |
104 | - return 4; | 117 | + return -4; |
105 | } | 118 | } |
106 | 119 | ||
107 | free(petData); | 120 | free(petData); |
@@ -120,7 +133,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { | @@ -120,7 +133,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { | ||
120 | } | 133 | } |
121 | if(!found) { | 134 | if(!found) { |
122 | fprintf(stderr,"Unable to locate Level tag\n"); | 135 | fprintf(stderr,"Unable to locate Level tag\n"); |
123 | - return 1; | 136 | + return -1; |
124 | } | 137 | } |
125 | found = 0; | 138 | found = 0; |
126 | 139 | ||
@@ -135,7 +148,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { | @@ -135,7 +148,7 @@ int getEntitiesTag(TagCompound* chunkRoot,Tag** entities) { | ||
135 | } | 148 | } |
136 | if(!found) { | 149 | if(!found) { |
137 | fprintf(stderr,"Unable to locate Entities tag\n"); | 150 | fprintf(stderr,"Unable to locate Entities tag\n"); |
138 | - return 2; | 151 | + return -2; |
139 | } | 152 | } |
140 | *entities = t; | 153 | *entities = t; |
141 | return 0; | 154 | return 0; |
@@ -188,22 +201,35 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p | @@ -188,22 +201,35 @@ ssize_t insertPetIntoChunk(void** chunkData, Tag chunkRoot, Tag* entities, Tag p | ||
188 | Tag* newPet = &entitiesList->list[(entitiesList->size) - 1]; | 201 | Tag* newPet = &entitiesList->list[(entitiesList->size) - 1]; |
189 | 202 | ||
190 | void* rawPetData; | 203 | void* rawPetData; |
191 | - size_t rawPetDataLength = composeTag(pet,&rawPetData); | ||
192 | - size_t parsePos = parseTag(rawPetData,newPet); | 204 | + ssize_t rawPetDataLength = composeTag(pet,&rawPetData); |
205 | + if(rawPetDataLength < 0) { | ||
206 | + fprintf(stderr,"Error while composing pet tag: code %d\n",(int)rawPetDataLength); | ||
207 | + return -2; | ||
208 | + } | ||
209 | + ssize_t parsePos = parseTag(rawPetData,newPet); | ||
210 | + if(parsePos < 0) { | ||
211 | + fprintf(stderr,"Error while parsing pet tag: code %d\n",(int)parsePos); | ||
212 | + free(rawPetData); | ||
213 | + return -3; | ||
214 | + } | ||
193 | if(parsePos != rawPetDataLength) { | 215 | if(parsePos != rawPetDataLength) { |
194 | fprintf(stderr,"Error while duplicating pet. New pet data does not match original\n"); | 216 | fprintf(stderr,"Error while duplicating pet. New pet data does not match original\n"); |
195 | free(rawPetData); | 217 | free(rawPetData); |
196 | - return -2; | 218 | + return -4; |
197 | } | 219 | } |
198 | free(rawPetData); | 220 | free(rawPetData); |
199 | 221 | ||
200 | void* newChunkData; | 222 | void* newChunkData; |
201 | - size_t chunkDataLength = composeTag(chunkRoot, &newChunkData); | 223 | + ssize_t chunkDataLength = composeTag(chunkRoot, &newChunkData); |
224 | + if(chunkDataLength < 0) { | ||
225 | + fprintf(stderr,"Error while composing new chunk tag: code %d\n",(int)chunkDataLength); | ||
226 | + return -5; | ||
227 | + } | ||
202 | newptr = realloc(*chunkData,chunkDataLength); | 228 | newptr = realloc(*chunkData,chunkDataLength); |
203 | if(newptr == NULL) { | 229 | if(newptr == NULL) { |
204 | fprintf(stderr,"Unable to realloc chunkData to fit new data\n"); | 230 | fprintf(stderr,"Unable to realloc chunkData to fit new data\n"); |
205 | free(newChunkData); | 231 | free(newChunkData); |
206 | - return -4; | 232 | + return -6; |
207 | } | 233 | } |
208 | *chunkData = newptr; | 234 | *chunkData = newptr; |
209 | memcpy(*chunkData,newChunkData,chunkDataLength); | 235 | memcpy(*chunkData,newChunkData,chunkDataLength); |
@@ -250,7 +276,7 @@ int main(int argc, char** argv) { | @@ -250,7 +276,7 @@ int main(int argc, char** argv) { | ||
250 | fprintf(stderr,"No options specified\n\n"); | 276 | fprintf(stderr,"No options specified\n\n"); |
251 | fprintf(stderr,"Examples:\n"); | 277 | fprintf(stderr,"Examples:\n"); |
252 | printHelp(); | 278 | printHelp(); |
253 | - return 0; | 279 | + return 3; |
254 | } | 280 | } |
255 | 281 | ||
256 | while ((c = getopt_long(argc, argv, "r:s:l:n:o:c:h", longopts, &longIndex)) != -1) | 282 | while ((c = getopt_long(argc, argv, "r:s:l:n:o:c:h", longopts, &longIndex)) != -1) |
@@ -265,19 +291,19 @@ int main(int argc, char** argv) { | @@ -265,19 +291,19 @@ int main(int argc, char** argv) { | ||
265 | else { | 291 | else { |
266 | fprintf(stderr,"Unrecognised argument: %s\n",optarg); | 292 | fprintf(stderr,"Unrecognised argument: %s\n",optarg); |
267 | printHelp(); | 293 | printHelp(); |
268 | - return 1; | 294 | + return 3; |
269 | } | 295 | } |
270 | } | 296 | } |
271 | if(optind != argc) { | 297 | if(optind != argc) { |
272 | fprintf(stderr,"Unrecognised argument: %s\n",argv[optind+1]); | 298 | fprintf(stderr,"Unrecognised argument: %s\n",argv[optind+1]); |
273 | printHelp(); | 299 | printHelp(); |
274 | - return 1; | 300 | + return 3; |
275 | } | 301 | } |
276 | 302 | ||
277 | if(regionFolder == NULL) { | 303 | if(regionFolder == NULL) { |
278 | fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n"); | 304 | fprintf(stderr,"Region path not specified (--regionpath PATH_TO_REGION_FOLDER)\n"); |
279 | printHelp(); | 305 | printHelp(); |
280 | - return 2; | 306 | + return 3; |
281 | } else if(!load && (petName == NULL && ownerUUID == NULL)) { | 307 | } else if(!load && (petName == NULL && ownerUUID == NULL)) { |
282 | fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); | 308 | fprintf(stderr,"OwnerUUID and petName were unspecified (--owner UUID, --name PET_NAME)\n"); |
283 | printHelp(); | 309 | printHelp(); |
@@ -289,7 +315,7 @@ int main(int argc, char** argv) { | @@ -289,7 +315,7 @@ int main(int argc, char** argv) { | ||
289 | } else if(save && coords == NULL) { | 315 | } else if(save && coords == NULL) { |
290 | fprintf(stderr,"Coordinates were not specified\n"); | 316 | fprintf(stderr,"Coordinates were not specified\n"); |
291 | printHelp(); | 317 | printHelp(); |
292 | - return 4; | 318 | + return 3; |
293 | } | 319 | } |
294 | 320 | ||
295 | if(!load) { | 321 | if(!load) { |
@@ -298,7 +324,7 @@ int main(int argc, char** argv) { | @@ -298,7 +324,7 @@ int main(int argc, char** argv) { | ||
298 | 324 | ||
299 | if((dirp = opendir(regionFolder)) == NULL) { | 325 | if((dirp = opendir(regionFolder)) == NULL) { |
300 | fprintf(stderr,"Unable to open region folder '%s'\n",regionFolder); | 326 | fprintf(stderr,"Unable to open region folder '%s'\n",regionFolder); |
301 | - return 1; | 327 | + return 2; |
302 | } | 328 | } |
303 | 329 | ||
304 | do { | 330 | do { |
@@ -326,16 +352,22 @@ int main(int argc, char** argv) { | @@ -326,16 +352,22 @@ int main(int argc, char** argv) { | ||
326 | (chunk.z + 1) * BLOCKS_PER_CHUNK | 352 | (chunk.z + 1) * BLOCKS_PER_CHUNK |
327 | ); | 353 | ); |
328 | ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); | 354 | ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); |
329 | - if(chunkLen < 0) { | ||
330 | - fprintf(stderr, "Unable to load chunk\n"); | ||
331 | - return 5; | 355 | + if(chunkLen == CHUNK_NOT_PRESENT) { |
356 | + continue; | ||
357 | + } else if(chunkLen < 0) { | ||
358 | + fprintf(stderr, "Unable to load chunk: code %d\n",(int)chunkLen); | ||
359 | + return 2; | ||
332 | } else if(chunkLen != 0) { | 360 | } else if(chunkLen != 0) { |
333 | Tag t; | 361 | Tag t; |
334 | - unsigned int pos = parseTag(chunkData,&t); | 362 | + ssize_t pos = parseTag(chunkData,&t); |
363 | + if(pos < 0) { | ||
364 | + fprintf(stderr, "Error parsing chunk root tag: code %d\n",(int)pos); | ||
365 | + return 2; | ||
366 | + } | ||
335 | if(pos != chunkLen) { | 367 | if(pos != chunkLen) { |
336 | fprintf(stderr, "Didn't reach end of NBT file\n"); | 368 | fprintf(stderr, "Didn't reach end of NBT file\n"); |
337 | free(chunkData); | 369 | free(chunkData); |
338 | - return 5; | 370 | + return 2; |
339 | } | 371 | } |
340 | 372 | ||
341 | Tag* entities; | 373 | Tag* entities; |
@@ -343,7 +375,7 @@ int main(int argc, char** argv) { | @@ -343,7 +375,7 @@ int main(int argc, char** argv) { | ||
343 | fprintf(stderr, "Unable to find Entities tag\n"); | 375 | fprintf(stderr, "Unable to find Entities tag\n"); |
344 | free(chunkData); | 376 | free(chunkData); |
345 | destroyTag(&t); | 377 | destroyTag(&t); |
346 | - return 6; | 378 | + return 2; |
347 | } | 379 | } |
348 | Tag* pet; | 380 | Tag* pet; |
349 | if(searchForPet(*entities,petName,ownerUUID,&pet) == 0) { | 381 | if(searchForPet(*entities,petName,ownerUUID,&pet) == 0) { |
@@ -354,7 +386,7 @@ int main(int argc, char** argv) { | @@ -354,7 +386,7 @@ int main(int argc, char** argv) { | ||
354 | fprintf(stderr, "Unable to save pet to file: %s\n",file); | 386 | fprintf(stderr, "Unable to save pet to file: %s\n",file); |
355 | free(chunkData); | 387 | free(chunkData); |
356 | closedir(dirp); | 388 | closedir(dirp); |
357 | - return 8; | 389 | + return 2; |
358 | } | 390 | } |
359 | } | 391 | } |
360 | destroyTag(&t); | 392 | destroyTag(&t); |
@@ -376,55 +408,64 @@ int main(int argc, char** argv) { | @@ -376,55 +408,64 @@ int main(int argc, char** argv) { | ||
376 | Coords location; | 408 | Coords location; |
377 | if(sscanf(coords,"%d,%d,%d",&location.x,&location.y,&location.z) != 3) { | 409 | if(sscanf(coords,"%d,%d,%d",&location.x,&location.y,&location.z) != 3) { |
378 | fprintf(stderr, "Unable to parse coordinates, please specify coordinates correctly (--coords X,Y,Z)\n"); | 410 | fprintf(stderr, "Unable to parse coordinates, please specify coordinates correctly (--coords X,Y,Z)\n"); |
379 | - return 5; | 411 | + return 3; |
380 | } | 412 | } |
381 | 413 | ||
382 | void *chunkData; | 414 | void *chunkData; |
383 | ChunkID chunk = translateCoordsToChunk(location.x, location.y, location.z); | 415 | ChunkID chunk = translateCoordsToChunk(location.x, location.y, location.z); |
384 | ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); | 416 | ssize_t chunkLen = loadChunk(regionFolder, chunk, &chunkData); |
385 | - if(chunkLen <= 0) { | ||
386 | - fprintf(stderr, "Unable to load chunk\n"); | ||
387 | - return 5; | ||
388 | - } | ||
389 | - | ||
390 | - Tag t; | ||
391 | - unsigned int pos = parseTag(chunkData,&t); | ||
392 | - if(pos != chunkLen) { | ||
393 | - fprintf(stderr, "Didn't reach end of NBT file\n"); | ||
394 | - free(chunkData); | ||
395 | - return 5; | 417 | + if(chunkLen == CHUNK_NOT_PRESENT) { |
418 | + fprintf(stderr, "Tried to spawn pet in a chunk that has not been generated!\n"); | ||
419 | + return 2; | ||
420 | + } else if(chunkLen < 0) { | ||
421 | + fprintf(stderr, "Unable to load chunk: code %d\n",(int)chunkLen); | ||
422 | + return 2; | ||
396 | } | 423 | } |
424 | + if(chunkLen != 0) { | ||
425 | + Tag t; | ||
426 | + ssize_t pos = parseTag(chunkData,&t); | ||
427 | + if(pos < 0) { | ||
428 | + fprintf(stderr, "Error parsing chunk root tag: code %d\n",(int)pos); | ||
429 | + return 2; | ||
430 | + } | ||
431 | + if(pos != chunkLen) { | ||
432 | + fprintf(stderr, "Didn't reach end of NBT file\n"); | ||
433 | + free(chunkData); | ||
434 | + return 2; | ||
435 | + } | ||
397 | 436 | ||
398 | - Tag* entities; | ||
399 | - if(getEntitiesTag((TagCompound*)t.payload,&entities)) { | ||
400 | - fprintf(stderr, "Unable to find Entities tag\n"); | ||
401 | - free(chunkData); | ||
402 | - destroyTag(&t); | ||
403 | - return 6; | ||
404 | - } | ||
405 | - Tag pet; | ||
406 | - if(loadPetFromFile(&pet,file)) { | ||
407 | - fprintf(stderr, "Unable to load pet from file: %s\n",file); | ||
408 | - free(chunkData); | ||
409 | - destroyTag(&t); | ||
410 | - return 9; | ||
411 | - } | ||
412 | - chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,location.x,location.y,location.z); | ||
413 | - if(chunkLen <= 0) { | ||
414 | - fprintf(stderr, "Unable to insert pet into chunk\n"); | ||
415 | - free(chunkData); | 437 | + Tag* entities; |
438 | + if(getEntitiesTag((TagCompound*)t.payload,&entities)) { | ||
439 | + fprintf(stderr, "Unable to find Entities tag\n"); | ||
440 | + free(chunkData); | ||
441 | + destroyTag(&t); | ||
442 | + return 2; | ||
443 | + } | ||
444 | + Tag pet; | ||
445 | + if(loadPetFromFile(&pet,file)) { | ||
446 | + fprintf(stderr, "Unable to load pet from file: %s\n",file); | ||
447 | + free(chunkData); | ||
448 | + destroyTag(&t); | ||
449 | + return 2; | ||
450 | + } | ||
451 | + chunkLen = insertPetIntoChunk(&chunkData,t,entities,pet,location.x,location.y,location.z); | ||
452 | + if(chunkLen <= 0) { | ||
453 | + fprintf(stderr, "Unable to insert pet into chunk\n"); | ||
454 | + free(chunkData); | ||
455 | + destroyTag(&t); | ||
456 | + return 2; | ||
457 | + } | ||
458 | + destroyTag(&pet); | ||
459 | + int res = overwriteChunk(regionFolder, chunk, chunkData, chunkLen); | ||
460 | + if(res) { | ||
461 | + fprintf(stderr, "Unable to write new chunk: code %d\n",res); | ||
462 | + free(chunkData); | ||
463 | + destroyTag(&t); | ||
464 | + return 2; | ||
465 | + } | ||
416 | destroyTag(&t); | 466 | destroyTag(&t); |
417 | - return 10; | ||
418 | - } | ||
419 | - destroyTag(&pet); | ||
420 | - if(overwriteChunk(regionFolder, chunk, chunkData, chunkLen)) { | ||
421 | - fprintf(stderr, "Unable to write new chunk\n"); | ||
422 | free(chunkData); | 467 | free(chunkData); |
423 | - destroyTag(&t); | ||
424 | - return 11; | ||
425 | } | 468 | } |
426 | - destroyTag(&t); | ||
427 | - free(chunkData); | ||
428 | } | 469 | } |
429 | return 0; | 470 | return 0; |
430 | } | 471 | } |
431 | \ No newline at end of file | 472 | \ No newline at end of file |