2 * Copyright (c) 2011, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
15 #include "solv_xfopen.h"
19 static FILE *cookieopen(void *cookie, const char *mode,
20 ssize_t (*cread)(void *, char *, size_t),
21 ssize_t (*cwrite)(void *, const char *, size_t),
22 int (*cclose)(void *))
27 return funopen(cookie,
28 (int (*)(void *, char *, int))(*mode == 'r' ? cread : NULL), /* readfn */
29 (int (*)(void *, const char *, int))(*mode == 'w' ? cwrite : NULL), /* writefn */
30 (fpos_t (*)(void *, fpos_t, int))NULL, /* seekfn */
33 #elif defined(HAVE_FOPENCOOKIE)
34 cookie_io_functions_t cio;
38 memset(&cio, 0, sizeof(cio));
41 else if (*mode == 'w')
44 return fopencookie(cookie, *mode == 'w' ? "w" : "r", cio);
46 # error Need to implement custom I/O
51 #ifdef ENABLE_ZLIB_COMPRESSION
53 /* gzip compression */
57 static ssize_t cookie_gzread(void *cookie, char *buf, size_t nbytes)
59 return gzread((gzFile)cookie, buf, nbytes);
62 static ssize_t cookie_gzwrite(void *cookie, const char *buf, size_t nbytes)
64 return gzwrite((gzFile)cookie, buf, nbytes);
67 static int cookie_gzclose(void *cookie)
69 return gzclose((gzFile)cookie);
72 static inline FILE *mygzfopen(const char *fn, const char *mode)
74 gzFile gzf = gzopen(fn, mode);
75 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
78 static inline FILE *mygzfdopen(int fd, const char *mode)
80 gzFile gzf = gzdopen(fd, mode);
81 return cookieopen(gzf, mode, cookie_gzread, cookie_gzwrite, cookie_gzclose);
87 #ifdef ENABLE_BZIP2_COMPRESSION
89 /* bzip2 compression */
93 static ssize_t cookie_bzread(void *cookie, char *buf, size_t nbytes)
95 return BZ2_bzread((BZFILE *)cookie, buf, nbytes);
98 static ssize_t cookie_bzwrite(void *cookie, const char *buf, size_t nbytes)
100 return BZ2_bzwrite((BZFILE *)cookie, (char *)buf, nbytes);
103 static int cookie_bzclose(void *cookie)
105 BZ2_bzclose((BZFILE *)cookie);
109 static inline FILE *mybzfopen(const char *fn, const char *mode)
111 BZFILE *bzf = BZ2_bzopen(fn, mode);
112 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
115 static inline FILE *mybzfdopen(int fd, const char *mode)
117 BZFILE *bzf = BZ2_bzdopen(fd, mode);
118 return cookieopen(bzf, mode, cookie_bzread, cookie_bzwrite, cookie_bzclose);
124 #ifdef ENABLE_LZMA_COMPRESSION
126 /* lzma code written by me in 2008 for rpm's rpmio.c */
130 typedef struct lzfile {
131 unsigned char buf[1 << 15];
138 static inline lzma_ret setup_alone_encoder(lzma_stream *strm, int level)
140 lzma_options_lzma options;
141 lzma_lzma_preset(&options, level);
142 return lzma_alone_encoder(strm, &options);
145 static lzma_stream stream_init = LZMA_STREAM_INIT;
147 static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
157 for (; *mode; mode++)
161 else if (*mode == 'r')
163 else if (*mode >= '1' && *mode <= '9')
167 fp = fdopen(fd, encoding ? "w" : "r");
169 fp = fopen(path, encoding ? "w" : "r");
172 lzfile = calloc(1, sizeof(*lzfile));
179 lzfile->encoding = encoding;
181 lzfile->strm = stream_init;
185 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
187 ret = setup_alone_encoder(&lzfile->strm, level);
190 ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
200 static int lzclose(void *cookie)
202 LZFILE *lzfile = cookie;
209 if (lzfile->encoding)
213 lzfile->strm.avail_out = sizeof(lzfile->buf);
214 lzfile->strm.next_out = lzfile->buf;
215 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
216 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
218 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
219 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
221 if (ret == LZMA_STREAM_END)
225 lzma_end(&lzfile->strm);
226 rc = fclose(lzfile->file);
231 static ssize_t lzread(void *cookie, char *buf, size_t len)
233 LZFILE *lzfile = cookie;
237 if (!lzfile || lzfile->encoding)
241 lzfile->strm.next_out = (unsigned char *)buf;
242 lzfile->strm.avail_out = len;
245 if (!lzfile->strm.avail_in)
247 lzfile->strm.next_in = lzfile->buf;
248 lzfile->strm.avail_in = fread(lzfile->buf, 1, sizeof(lzfile->buf), lzfile->file);
249 if (!lzfile->strm.avail_in)
252 ret = lzma_code(&lzfile->strm, LZMA_RUN);
253 if (ret == LZMA_STREAM_END)
256 return len - lzfile->strm.avail_out;
260 if (!lzfile->strm.avail_out)
267 static ssize_t lzwrite(void *cookie, const char *buf, size_t len)
269 LZFILE *lzfile = cookie;
272 if (!lzfile || !lzfile->encoding)
276 lzfile->strm.next_in = (unsigned char *)buf;
277 lzfile->strm.avail_in = len;
280 lzfile->strm.next_out = lzfile->buf;
281 lzfile->strm.avail_out = sizeof(lzfile->buf);
282 ret = lzma_code(&lzfile->strm, LZMA_RUN);
285 n = sizeof(lzfile->buf) - lzfile->strm.avail_out;
286 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
288 if (!lzfile->strm.avail_in)
293 static inline FILE *myxzfopen(const char *fn, const char *mode)
295 LZFILE *lzf = lzopen(fn, mode, -1, 1);
296 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
299 static inline FILE *myxzfdopen(int fd, const char *mode)
301 LZFILE *lzf = lzopen(0, mode, fd, 1);
302 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
305 static inline FILE *mylzfopen(const char *fn, const char *mode)
307 LZFILE *lzf = lzopen(fn, mode, -1, 0);
308 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
311 static inline FILE *mylzfdopen(int fd, const char *mode)
313 LZFILE *lzf = lzopen(0, mode, fd, 0);
314 return cookieopen(lzf, mode, lzread, lzwrite, lzclose);
317 #endif /* ENABLE_LZMA_COMPRESSION */
321 solv_xfopen(const char *fn, const char *mode)
329 suf = strrchr(fn, '.');
330 #ifdef ENABLE_ZLIB_COMPRESSION
331 if (suf && !strcmp(suf, ".gz"))
332 return mygzfopen(fn, mode);
334 if (suf && !strcmp(suf, ".gz"))
337 #ifdef ENABLE_LZMA_COMPRESSION
338 if (suf && !strcmp(suf, ".xz"))
339 return myxzfopen(fn, mode);
340 if (suf && !strcmp(suf, ".lzma"))
341 return mylzfopen(fn, mode);
343 if (suf && !strcmp(suf, ".xz"))
345 if (suf && !strcmp(suf, ".lzma"))
348 #ifdef ENABLE_BZIP2_COMPRESSION
349 if (suf && !strcmp(suf, ".bz2"))
350 return mybzfopen(fn, mode);
352 if (suf && !strcmp(suf, ".bz2"))
355 return fopen(fn, mode);
359 solv_xfopen_fd(const char *fn, int fd, const char *mode)
361 const char *simplemode = mode;
364 suf = fn ? strrchr(fn, '.') : 0;
367 int fl = fcntl(fd, F_GETFL, 0);
370 fl &= O_RDONLY|O_WRONLY|O_RDWR;
372 mode = simplemode = "w";
373 else if (fl == O_RDWR)
379 mode = simplemode = "r";
381 #ifdef ENABLE_ZLIB_COMPRESSION
382 if (suf && !strcmp(suf, ".gz"))
383 return mygzfdopen(fd, simplemode);
385 if (suf && !strcmp(suf, ".gz"))
388 #ifdef ENABLE_LZMA_COMPRESSION
389 if (suf && !strcmp(suf, ".xz"))
390 return myxzfdopen(fd, simplemode);
391 if (suf && !strcmp(suf, ".lzma"))
392 return mylzfdopen(fd, simplemode);
394 if (suf && !strcmp(suf, ".xz"))
396 if (suf && !strcmp(suf, ".lzma"))
399 #ifdef ENABLE_BZIP2_COMPRESSION
400 if (suf && !strcmp(suf, ".bz2"))
401 return mybzfdopen(fd, simplemode);
403 if (suf && !strcmp(suf, ".bz2"))
406 return fdopen(fd, mode);
410 solv_xfopen_iscompressed(const char *fn)
412 const char *suf = fn ? strrchr(fn, '.') : 0;
415 #ifdef ENABLE_ZLIB_COMPRESSION
416 if (!strcmp(suf, ".gz"))
421 if (!strcmp(suf, ".xz") || !strcmp(suf, ".lzma"))
422 #ifdef ENABLE_LZMA_COMPRESSION
427 if (!strcmp(suf, ".bz2"))
428 #ifdef ENABLE_BZIP2_COMPRESSION
443 static ssize_t cookie_bufread(void *cookie, char *buf, size_t nbytes)
445 struct bufcookie *bc = cookie;
446 size_t n = *bc->buflp > nbytes ? nbytes : *bc->buflp;
449 memcpy(buf, *bc->bufp, n);
456 static ssize_t cookie_bufwrite(void *cookie, const char *buf, size_t nbytes)
458 struct bufcookie *bc = cookie;
459 int n = nbytes > 0x40000000 ? 0x40000000 : nbytes;
462 *bc->bufp = solv_extend(*bc->bufp, *bc->buflp, n + 1, 1, 4095);
463 memcpy(*bc->bufp, buf, n);
464 (*bc->bufp)[n] = 0; /* zero-terminate */
470 static int cookie_bufclose(void *cookie)
472 struct bufcookie *bc = cookie;
474 solv_free(bc->freemem);
480 solv_xfopen_buf(const char *fn, char **bufp, size_t *buflp, const char *mode)
482 struct bufcookie *bc;
484 if (*mode != 'r' && *mode != 'w')
486 bc = solv_calloc(1, sizeof(*bc));
491 bc->bufl_int = *mode == 'w' ? 0 : strlen(*bufp);
492 buflp = &bc->bufl_int;
497 *bc->bufp = solv_extend(0, 0, 1, 1, 4095); /* always zero-terminate */
501 fp = cookieopen(bc, mode, cookie_bufread, cookie_bufwrite, cookie_bufclose);
502 if (!strcmp(mode, "rf")) /* auto-free */
507 *bc->bufp = solv_free(*bc->bufp);