#include #include #include #include #include #include #include #include #include "sha256.h" #include "lzma.h" void uncompresslzma(void *buf, size_t bufsize, FILE *out) { lzma_stream s = LZMA_STREAM_INIT; lzma_stream *strm; uint8_t outbuf[BUFSIZ]; int ret; strm = &s; ret = lzma_stream_decoder(strm, UINT64_MAX, 0); /* The only reasonable error here is LZMA_MEM_ERROR. */ if (ret != LZMA_OK) { fprintf(stderr, "%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM) : "Internal error (bug)"); exit(EXIT_FAILURE); } strm->avail_in = bufsize; strm->next_in = buf; strm->avail_out = BUFSIZ; strm->next_out = outbuf; lzma_action action = LZMA_RUN; while (1) { ret = lzma_code(strm, action); // Write and check write error before checking decoder error. // This way as much data as possible gets written to output // even if decoder detected an error. if (strm->avail_out == 0 || ret != LZMA_OK) { const size_t write_size = BUFSIZ - strm->avail_out; if (fwrite(outbuf, 1, write_size, out) != write_size) { // Wouldn't be a surprise if writing to stderr // would fail too but at least try to show an // error message. fprintf(stderr, "Cannot write to output file stream: " "%s", strerror(errno)); exit(EXIT_FAILURE); } strm->next_out = outbuf; strm->avail_out = BUFSIZ; } if (ret != LZMA_OK) { if (ret == LZMA_STREAM_END) { // lzma_stream_decoder() already guarantees // that there's no trailing garbage. assert(strm->avail_in == 0); //assert(action == LZMA_FINISH); return; } const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = strerror(ENOMEM); break; case LZMA_FORMAT_ERROR: msg = "File format not recognized"; break; case LZMA_OPTIONS_ERROR: // FIXME: Better message? msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "File is corrupt"; break; case LZMA_BUF_ERROR: msg = "Unexpected end of input"; break; default: msg = "Internal error (bug)"; break; } fprintf(stderr, "xz: %s\n", msg); exit(EXIT_FAILURE); } } } #define SQLERROR(x) fprintf(stderr, "%s %d: %s\n", __func__, __LINE__, (x)) int main(int ac, char **av){ sqlite3 *db = 0; int rc; int blobsize; int64_t size; void *xzdata; int type; FILE *out; sqlite3_stmt *ifile; char *hash; char *filename; if (ac < 3) { fprintf(stderr, "usage: db hash file\n"); return 1; } rc = sqlite3_open(av[1], &db); if (rc) { SQLERROR(sqlite3_errmsg(db)); sqlite3_close(db); return 1; } rc = sqlite3_prepare(db, "select size, content from files where hash = ?", -1, &ifile,0); if (rc != SQLITE_OK) { SQLERROR(sqlite3_errmsg(db)); return 1; } /* hash, filename */ hash = av[2]; filename = av[3]; sqlite3_bind_text(ifile, 1, hash, 64, SQLITE_STATIC); rc = sqlite3_step(ifile); if (rc == SQLITE_DONE) { /* didn't find a row */ sqlite3_finalize(ifile); sqlite3_close(db); fprintf(stderr, "no such hash\n"); return 1; } /* either way we're done with this now */ if (rc != SQLITE_ROW) { SQLERROR(sqlite3_errmsg(db)); sqlite3_finalize(ifile); sqlite3_close(db); return 2; } type = sqlite3_column_type(ifile, 0); if (type == SQLITE_NULL) { fprintf(stderr, "no file size\n"); sqlite3_finalize(ifile); sqlite3_close(db); return 3; } type = sqlite3_column_type(ifile, 1); if (type == SQLITE_NULL) { fprintf(stderr, "no file data\n"); sqlite3_finalize(ifile); sqlite3_close(db); return 4; } size = sqlite3_column_int64(ifile, 0); xzdata = (void *)sqlite3_column_blob(ifile, 1); blobsize = sqlite3_column_bytes(ifile, 1); out = fopen(filename, "w"); if (!out) { fprintf(stderr, "can't open output file %s\n", filename); sqlite3_finalize(ifile); sqlite3_close(db); return 5; } //fwrite(xzdata, blobsize, 1, stdout); fprintf(stderr, "uncompressing %d bytes at %p, expect %lld\n", blobsize, xzdata, (long long int)size); uncompresslzma(xzdata, blobsize, out); fclose(out); sqlite3_finalize(ifile); sqlite3_close(db); return 0; }