]> pd.if.org Git - zpackage/blob - uncompress.c
fix possible memory leak in uncompress
[zpackage] / uncompress.c
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7
8 #include <sys/mman.h>
9
10 #include <sqlite3.h>
11
12 #include "sha256.h"
13
14 #include "lzma.h"
15
16 void uncompresslzma(void *buf, size_t bufsize, FILE *out) {
17         lzma_stream s = LZMA_STREAM_INIT;
18         lzma_stream *strm;
19         
20         uint8_t outbuf[BUFSIZ];
21
22         int ret;
23
24         strm = &s;
25
26         ret = lzma_stream_decoder(strm, UINT64_MAX, 0);
27         /* The only reasonable error here is LZMA_MEM_ERROR. */
28         if (ret != LZMA_OK) {
29                 fprintf(stderr, "%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM)
30                                 : "Internal error (bug)");
31                 exit(EXIT_FAILURE);
32         }
33
34         strm->avail_in = bufsize;
35         strm->next_in = buf;
36         strm->avail_out = BUFSIZ;
37         strm->next_out = outbuf;
38
39         lzma_action action = LZMA_RUN;
40
41         while (1) {
42                 ret = lzma_code(strm, action);
43
44                 // Write and check write error before checking decoder error.
45                 // This way as much data as possible gets written to output
46                 // even if decoder detected an error.
47                 if (strm->avail_out == 0 || ret != LZMA_OK) {
48                         const size_t write_size = BUFSIZ - strm->avail_out;
49
50                         if (fwrite(outbuf, 1, write_size, out) != write_size) {
51                                 // Wouldn't be a surprise if writing to stderr
52                                 // would fail too but at least try to show an
53                                 // error message.
54                                 fprintf(stderr, "Cannot write to output file stream: "
55                                                 "%s", strerror(errno));
56                                 exit(EXIT_FAILURE);
57                         }
58
59                         strm->next_out = outbuf;
60                         strm->avail_out = BUFSIZ;
61                 }
62
63                 if (ret != LZMA_OK) {
64                         if (ret == LZMA_STREAM_END) {
65                                 // lzma_stream_decoder() already guarantees
66                                 // that there's no trailing garbage.
67                                 assert(strm->avail_in == 0);
68                                 //assert(action == LZMA_FINISH);
69                                 return;
70                         }
71
72                         const char *msg;
73                         switch (ret) {
74                                 case LZMA_MEM_ERROR:
75                                         msg = strerror(ENOMEM);
76                                         break;
77
78                                 case LZMA_FORMAT_ERROR:
79                                         msg = "File format not recognized";
80                                         break;
81
82                                 case LZMA_OPTIONS_ERROR:
83                                         // FIXME: Better message?
84                                         msg = "Unsupported compression options";
85                                         break;
86
87                                 case LZMA_DATA_ERROR:
88                                         msg = "File is corrupt";
89                                         break;
90
91                                 case LZMA_BUF_ERROR:
92                                         msg = "Unexpected end of input";
93                                         break;
94
95                                 default:
96                                         msg = "Internal error (bug)";
97                                         break;
98                         }
99
100                         fprintf(stderr, "xz: %s\n", msg);
101                         exit(EXIT_FAILURE);
102                 }
103         }
104 }
105
106 #define SQLERROR(x) fprintf(stderr, "%s %d: %s\n", __func__, __LINE__, (x))
107
108 int main(int ac, char **av){
109         sqlite3 *db = 0;
110         int rc;
111
112         int blobsize;
113         int64_t size;
114         void *xzdata;
115         int type;
116         FILE *out;
117         sqlite3_stmt *ifile;
118
119         char *hash;
120         char *filename;
121
122         if (ac < 3) {
123                 fprintf(stderr, "usage: db hash file\n");
124                 return 1;
125         }
126
127         rc = sqlite3_open(av[1], &db);
128         if (rc) {
129                 SQLERROR(sqlite3_errmsg(db));
130                 sqlite3_close(db);
131                 return 1;
132         }
133
134         rc = sqlite3_prepare(db, "select size, content from files where hash = ?", -1, &ifile,0);
135         if (rc != SQLITE_OK) {
136                 SQLERROR(sqlite3_errmsg(db));
137                 return 1;
138         }
139
140         /* hash, filename */
141         hash = av[2];
142         filename = av[3];
143
144         sqlite3_bind_text(ifile, 1, hash, 64, SQLITE_STATIC);
145
146         rc = sqlite3_step(ifile);
147
148         if (rc == SQLITE_DONE) {
149                 /* didn't find a row */
150                 sqlite3_finalize(ifile);
151                 sqlite3_close(db);
152                 fprintf(stderr, "no such hash\n");
153                 return 1;
154         }
155         /* either way we're done with this now */
156
157         if (rc != SQLITE_ROW) {
158                 SQLERROR(sqlite3_errmsg(db));
159                 sqlite3_finalize(ifile);
160                 sqlite3_close(db);
161                 return 2;
162         }
163
164         type = sqlite3_column_type(ifile, 0);
165         if (type == SQLITE_NULL) {
166                 fprintf(stderr, "no file size\n");
167                 sqlite3_finalize(ifile);
168                 sqlite3_close(db);
169                 return 3;
170         }
171         type = sqlite3_column_type(ifile, 1);
172         if (type == SQLITE_NULL) {
173                 fprintf(stderr, "no file data\n");
174                 sqlite3_finalize(ifile);
175                 sqlite3_close(db);
176                 return 4;
177         }
178         size = sqlite3_column_int64(ifile, 0);
179         xzdata = (void *)sqlite3_column_blob(ifile, 1);
180         blobsize = sqlite3_column_bytes(ifile, 1);
181
182         out = fopen(filename, "w");
183         if (!out) {
184                 fprintf(stderr, "can't open output file %s\n", filename);
185                 sqlite3_finalize(ifile);
186                 sqlite3_close(db);
187                 return 5;
188         }
189         //fwrite(xzdata, blobsize, 1, stdout);
190
191         fprintf(stderr, "uncompressing %d bytes at %p, expect %lld\n", blobsize, xzdata, (long long int)size);
192         uncompresslzma(xzdata, blobsize, out);
193         fclose(out);
194
195         sqlite3_finalize(ifile);
196         sqlite3_close(db);
197         return 0;
198 }