Bug Summary

File:rpmio/rpmio.c
Warning:line 97, column 5
Use of memory after it is freed

Annotated Source Code

1/** \ingroup rpmio
2 * \file rpmio/rpmio.c
3 */
4
5#include "system.h"
6#include <stdarg.h>
7#include <errno(*__errno_location ()).h>
8#include <ctype.h>
9#if defined(__linux__1)
10#include <sys/personality.h>
11#endif
12#include <sys/utsname.h>
13
14#include <rpm/rpmlog.h>
15#include <rpm/rpmmacro.h>
16#include <rpm/rpmfileutil.h>
17#include <rpm/rpmsw.h>
18#include <rpm/rpmurl.h>
19
20#include "rpmio/rpmio_internal.h"
21
22#include "debug.h"
23
24typedef struct FDSTACK_s * FDSTACK_t;
25
26struct FDSTACK_s {
27 FDIO_t io;
28 void * fp;
29 int fdno;
30 int syserrno; /* last system errno encountered */
31 const char *errcookie; /* pointer to custom error string */
32
33 FDSTACK_t prev;
34};
35
36/** \ingroup rpmio
37 * Cumulative statistics for a descriptor.
38 */
39typedef struct {
40 struct rpmop_s ops[FDSTAT_MAX]; /*!< Cumulative statistics. */
41} * FDSTAT_t;
42
43/** \ingroup rpmio
44 * The FD_t File Handle data structure.
45 */
46struct _FD_s {
47 int nrefs;
48 int flags;
49#define RPMIO_DEBUG_IO0x40000000 0x40000000
50 int magic;
51#define FDMAGIC0x04463138 0x04463138
52 FDSTACK_t fps;
53 int urlType; /* ufdio: */
54
55 char *descr; /* file name (or other description) */
56 FDSTAT_t stats; /* I/O statistics */
57
58 rpmDigestBundle digests;
59};
60
61#define DBG(_f, _m, _x)if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) &
(_m)) fprintf _x
\
62 \
63 if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x \
64
65#define DBGIO(_f, _x)if ((_rpmio_debug | (((_f)) ? ((FD_t)((_f)))->flags : 0)) &
(0x40000000)) fprintf _x
DBG((_f), RPMIO_DEBUG_IO, _x)if ((_rpmio_debug | (((_f)) ? ((FD_t)((_f)))->flags : 0)) &
(0x40000000)) fprintf _x
66
67static FDSTACK_t fdGetFps(FD_t fd)
68{
69 return (fd != NULL((void*)0)) ? fd->fps : NULL((void*)0);
70}
71
72static void fdSetFdno(FD_t fd, int fdno)
73{
74 if (fd)
75 fd->fps->fdno = fdno;
76}
77
78static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
79{
80 FDSTACK_t fps = xcalloc(1, sizeof(*fps))rcalloc((1), (sizeof(*fps)));
81 fps->io = io;
82 fps->fp = fp;
83 fps->fdno = fdno;
84 fps->prev = fd->fps;
85
86 fd->fps = fps;
87 fdLink(fd);
88}
89
90static FDSTACK_t fdPop(FD_t fd)
91{
92 FDSTACK_t fps = fd->fps;
93 fd->fps = fps->prev;
94 free(fps);
95 fps = fd->fps;
96 fdFree(fd);
16
Calling 'fdFree'
23
Returning; memory was released
97 return fps;
24
Use of memory after it is freed
98}
99
100void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
101{
102 if (fd)
103 fd->digests = bundle;
104}
105
106rpmDigestBundle fdGetBundle(FD_t fd, int create)
107{
108 rpmDigestBundle bundle = NULL((void*)0);
109 if (fd) {
110 if (fd->digests == NULL((void*)0) && create)
111 fd->digests = rpmDigestBundleNew();
112 bundle = fd->digests;
113 }
114 return bundle;
115}
116
117/** \ingroup rpmio
118 * \name RPMIO Vectors.
119 */
120typedef ssize_t (*fdio_read_function_t) (FDSTACK_t fps, void *buf, size_t nbytes);
121typedef ssize_t (*fdio_write_function_t) (FDSTACK_t fps, const void *buf, size_t nbytes);
122typedef int (*fdio_seek_function_t) (FDSTACK_t fps, off_t pos, int whence);
123typedef int (*fdio_close_function_t) (FDSTACK_t fps);
124typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
125typedef FD_t (*fdio_fdopen_function_t) (FD_t fd, int fdno, const char * fmode);
126typedef int (*fdio_fflush_function_t) (FDSTACK_t fps);
127typedef long (*fdio_ftell_function_t) (FDSTACK_t fps);
128typedef int (*fdio_ferror_function_t) (FDSTACK_t fps);
129typedef const char * (*fdio_fstrerr_function_t)(FDSTACK_t fps);
130
131struct FDIO_s {
132 const char * ioname;
133 const char * name;
134 fdio_read_function_t read;
135 fdio_write_function_t write;
136 fdio_seek_function_t seek;
137 fdio_close_function_t close;
138
139 fdio_open_function_t _open;
140 fdio_fdopen_function_t _fdopen;
141 fdio_fflush_function_t _fflush;
142 fdio_ftell_function_t _ftell;
143 fdio_ferror_function_t _ferror;
144 fdio_fstrerr_function_t _fstrerr;
145};
146
147/* forward refs */
148static const FDIO_t fdio;
149static const FDIO_t ufdio;
150static const FDIO_t gzdio;
151#if HAVE_BZLIB_H1
152static const FDIO_t bzdio;
153#endif
154#ifdef HAVE_LZMA_H1
155static const FDIO_t xzdio;
156static const FDIO_t lzdio;
157#endif
158#ifdef HAVE_ZSTD
159static const FDIO_t zstdio;
160#endif
161
162/** \ingroup rpmio
163 * Update digest(s) attached to fd.
164 */
165static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
166static FD_t fdNew(int fdno, const char *descr);
167/**
168 */
169int _rpmio_debug = 0;
170
171/* =============================================================== */
172
173static const char * fdbg(FD_t fd)
174{
175 static char buf[BUFSIZ8192];
176 char *be = buf;
177
178 buf[0] = '\0';
179 if (fd == NULL((void*)0))
180 return buf;
181
182 *be++ = '\t';
183 for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) {
184 FDIO_t iot = fps->io;
185 if (fps != fd->fps)
186 *be++ = ' ';
187 *be++ = '|';
188 *be++ = ' ';
189 /* plain fd io types dont have _fopen() method */
190 if (iot->_fdopen == NULL((void*)0)) {
191 sprintf(be, "%s %d fp %p", iot->ioname, fps->fdno, fps->fp);
192 } else {
193 sprintf(be, "%s %p fp %d", iot->ioname, fps->fp, fps->fdno);
194 }
195 be += strlen(be);
196 *be = '\0';
197 }
198 return buf;
199}
200
201static void fdstat_enter(FD_t fd, fdOpX opx)
202{
203 if (fd->stats != NULL((void*)0))
204 (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0);
205}
206
207static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
208{
209 if (rc == -1) {
210 FDSTACK_t fps = fdGetFps(fd);
211 fps->syserrno = errno(*__errno_location ());
212 }
213 if (fd->stats != NULL((void*)0))
214 (void) rpmswExit(fdOp(fd, opx), rc);
215}
216
217static void fdstat_print(FD_t fd, const char * msg, FILE * fp)
218{
219 static const int usec_scale = (1000*1000);
220 int opx;
221
222 if (fd == NULL((void*)0) || fd->stats == NULL((void*)0)) return;
223 for (opx = 0; opx < 4; opx++) {
224 rpmop op = &fd->stats->ops[opx];
225 if (op->count <= 0) continue;
226 switch (opx) {
227 case FDSTAT_READ:
228 if (msg) fprintf(fp, "%s:", msg);
229 fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
230 op->count, (long)op->bytes,
231 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
232 break;
233 case FDSTAT_WRITE:
234 if (msg) fprintf(fp, "%s:", msg);
235 fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
236 op->count, (long)op->bytes,
237 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
238 break;
239 case FDSTAT_SEEK:
240 break;
241 case FDSTAT_CLOSE:
242 break;
243 }
244 }
245}
246
247off_t fdSize(FD_t fd)
248{
249 struct stat sb;
250 off_t rc = -1;
251
252 if (fd != NULL((void*)0) && fstat(Fileno(fd), &sb) == 0)
253 rc = sb.st_size;
254 return rc;
255}
256
257FD_t fdDup(int fdno)
258{
259 FD_t fd;
260 int nfdno;
261
262 if ((nfdno = dup(fdno)) < 0)
263 return NULL((void*)0);
264 fd = fdNew(nfdno, NULL((void*)0));
265DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==> fdDup(%d) fd %p %s\n"
, fdno, (fd ? fd : ((void*)0)), fdbg(fd))
;
266 return fd;
267}
268
269/* Regular fd doesn't have fflush() equivalent but its not an error either */
270static int fdFlush(FDSTACK_t fps)
271{
272 return 0;
273}
274
275static int fdError(FDSTACK_t fps)
276{
277 return fps->syserrno;
278}
279
280static int zfdError(FDSTACK_t fps)
281{
282 return (fps->syserrno || fps->errcookie != NULL((void*)0)) ? -1 : 0;
283}
284
285static const char * fdStrerr(FDSTACK_t fps)
286{
287 return (fps->syserrno != 0) ? strerror(fps->syserrno) : "";
288}
289
290static const char * zfdStrerr(FDSTACK_t fps)
291{
292 return (fps->errcookie != NULL((void*)0)) ? fps->errcookie : "";
293}
294
295const char * Fdescr(FD_t fd)
296{
297 if (fd == NULL((void*)0))
298 return _("[none]")dcgettext ("rpm", "[none]", 5);
299
300 /* Lazy lookup if description is not set (eg dupped fd) */
301 if (fd->descr == NULL((void*)0)) {
302 int fdno = fd->fps->fdno;
303#if defined(__linux__1)
304 /* Grab the path from /proc if we can */
305 char *procpath = NULL((void*)0);
306 char buf[PATH_MAX4096];
307 ssize_t llen;
308
309 rasprintf(&procpath, "/proc/self/fd/%d", fdno);
310 llen = readlink(procpath, buf, sizeof(buf)-1);
311 free(procpath);
312
313 if (llen >= 1) {
314 buf[llen] = '\0';
315 /* Real paths in /proc are always absolute */
316 if (buf[0] == '/')
317 fd->descr = xstrdup(buf)rstrdup((buf));
318 else
319 fd->descr = rstrscat(NULL((void*)0), "[", buf, "]", NULL((void*)0));
320 }
321#endif
322 /* Still no description, base it on fdno which is always there */
323 if (fd->descr == NULL((void*)0))
324 rasprintf(&(fd->descr), "[fd %d]", fdno);
325 }
326 return fd->descr;
327}
328
329FD_t fdLink(FD_t fd)
330{
331 if (fd)
332 fd->nrefs++;
333 return fd;
334}
335
336FD_t fdFree( FD_t fd)
337{
338 if (fd) {
17
Taking true branch
339 if (--fd->nrefs > 0)
18
Assuming the condition is false
19
Taking false branch
340 return fd;
341 fd->stats = _free(fd->stats)rfree((fd->stats));
342 if (fd->digests) {
20
Assuming the condition is false
21
Taking false branch
343 fd->digests = rpmDigestBundleFree(fd->digests);
344 }
345 free(fd->fps);
22
Memory is released
346 free(fd->descr);
347 free(fd);
348 }
349 return NULL((void*)0);
350}
351
352static FD_t fdNew(int fdno, const char *descr)
353{
354 FD_t fd = xcalloc(1, sizeof(*fd))rcalloc((1), (sizeof(*fd)));
355 fd->nrefs = 0;
356 fd->flags = 0;
357 fd->magic = FDMAGIC0x04463138;
358 fd->urlType = URL_IS_UNKNOWN;
359 fd->stats = xcalloc(1, sizeof(*fd->stats))rcalloc((1), (sizeof(*fd->stats)));
360 fd->digests = NULL((void*)0);
361 fd->descr = descr ? xstrdup(descr)rstrdup((descr)) : NULL((void*)0);
362
363 fdPush(fd, fdio, NULL((void*)0), fdno);
364 return fd;
365}
366
367static ssize_t fdRead(FDSTACK_t fps, void * buf, size_t count)
368{
369 return read(fps->fdno, buf, count);
370}
371
372static ssize_t fdWrite(FDSTACK_t fps, const void * buf, size_t count)
373{
374 if (count == 0)
375 return 0;
376
377 return write(fps->fdno, buf, count);
378}
379
380static int fdSeek(FDSTACK_t fps, off_t pos, int whence)
381{
382 return lseek(fps->fdno, pos, whence);
383}
384
385static int fdClose(FDSTACK_t fps)
386{
387 int fdno = fps->fdno;
388 int rc;
389
390 fps->fdno = -1;
391
392 rc = ((fdno >= 0) ? close(fdno) : -2);
393
394 return rc;
395}
396
397static FD_t fdOpen(const char *path, int flags, mode_t mode)
398{
399 FD_t fd;
400 int fdno;
401
402 fdno = open(path, flags, mode);
403 if (fdno < 0) return NULL((void*)0);
404 if (fcntl(fdno, F_SETFD2, FD_CLOEXEC1)) {
405 (void) close(fdno);
406 return NULL((void*)0);
407 }
408 fd = fdNew(fdno, path);
409 fd->flags = flags;
410 return fd;
411}
412
413static long fdTell(FDSTACK_t fps)
414{
415 return lseek(fps->fdno, 0, SEEK_CUR1);
416}
417
418static const struct FDIO_s fdio_s = {
419 "fdio", NULL((void*)0),
420 fdRead, fdWrite, fdSeek, fdClose,
421 fdOpen, NULL((void*)0), fdFlush, fdTell, fdError, fdStrerr,
422};
423static const FDIO_t fdio = &fdio_s ;
424
425off_t ufdCopy(FD_t sfd, FD_t tfd)
426{
427 char buf[BUFSIZ8192];
428 ssize_t rdbytes, wrbytes;
429 off_t total = 0;
430
431 while (1) {
432 rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd);
433
434 if (rdbytes > 0) {
435 wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, tfd);
436 if (wrbytes != rdbytes) {
437 total = -1;
438 break;
439 }
440 total += wrbytes;
441 } else {
442 if (rdbytes < 0)
443 total = -1;
444 break;
445 }
446 }
447
448 return total;
449}
450
451/*
452 * Deal with remote url's by fetching them with a helper application
453 * and treat as local file afterwards.
454 * TODO:
455 * - better error checking + reporting
456 * - curl & friends don't know about hkp://, transform to http?
457 */
458
459static FD_t urlOpen(const char * url, int flags, mode_t mode)
460{
461 FD_t fd;
462 char *dest = NULL((void*)0);
463 int rc = 1; /* assume failure */
464
465 fd = rpmMkTempFile(NULL((void*)0), &dest);
466 if (fd == NULL((void*)0)) {
467 return NULL((void*)0);
468 }
469 Fclose(fd);
470
471 rc = urlGetFile(url, dest);
472 if (rc == 0) {
473 fd = fdOpen(dest, flags, mode);
474 unlink(dest);
475 } else {
476 fd = NULL((void*)0);
477 }
478 dest = _free(dest)rfree((dest));
479
480 return fd;
481
482}
483static FD_t ufdOpen(const char * url, int flags, mode_t mode)
484{
485 FD_t fd = NULL((void*)0);
486 const char * path;
487 urltype urlType = urlPath(url, &path);
488
489if (_rpmio_debug)
490fprintf(stderrstderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode);
491
492 switch (urlType) {
493 case URL_IS_FTP:
494 case URL_IS_HTTPS:
495 case URL_IS_HTTP:
496 case URL_IS_HKP:
497 fd = urlOpen(url, flags, mode);
498 /* we're dealing with local file when urlOpen() returns */
499 urlType = URL_IS_UNKNOWN;
500 break;
501 case URL_IS_DASH:
502 if ((flags & O_ACCMODE0003) == O_RDWR02) {
503 fd = NULL((void*)0);
504 } else {
505 fd = fdDup((flags & O_ACCMODE0003) == O_WRONLY01 ?
506 STDOUT_FILENO1 : STDIN_FILENO0);
507 }
508 break;
509 case URL_IS_PATH:
510 case URL_IS_UNKNOWN:
511 default:
512 fd = fdOpen(path, flags, mode);
513 break;
514 }
515
516 if (fd != NULL((void*)0)) {
517 fd->fps->io = ufdio;
518 fd->urlType = urlType;
519 }
520 return fd;
521}
522
523static const struct FDIO_s ufdio_s = {
524 "ufdio", NULL((void*)0),
525 fdRead, fdWrite, fdSeek, fdClose,
526 ufdOpen, NULL((void*)0), fdFlush, fdTell, fdError, fdStrerr
527};
528static const FDIO_t ufdio = &ufdio_s ;
529
530/* =============================================================== */
531/* Support for GZIP library. */
532#include <zlib.h>
533
534static FD_t gzdFdopen(FD_t fd, int fdno, const char *fmode)
535{
536 gzFile gzfile = gzdopen(fdno, fmode);
537
538 if (gzfile == NULL((void*)0))
539 return NULL((void*)0);
540
541 fdSetFdno(fd, -1); /* XXX skip the fdio close */
542 fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
543 return fd;
544}
545
546static int gzdFlush(FDSTACK_t fps)
547{
548 gzFile gzfile = fps->fp;
549 if (gzfile == NULL((void*)0)) return -2;
550 return gzflush(gzfile, Z_SYNC_FLUSH2); /* XXX W2DO? */
551}
552
553static void gzdSetError(FDSTACK_t fps)
554{
555 gzFile gzfile = fps->fp;
556 int zerror = 0;
557 fps->errcookie = gzerror(gzfile, &zerror);
558 if (zerror == Z_ERRNO(-1)) {
559 fps->syserrno = errno(*__errno_location ());
560 fps->errcookie = strerror(fps->syserrno);
561 }
562}
563
564static ssize_t gzdRead(FDSTACK_t fps, void * buf, size_t count)
565{
566 gzFile gzfile = fps->fp;
567 ssize_t rc;
568
569 if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */
570
571 rc = gzread(gzfile, buf, count);
572 if (rc < 0)
573 gzdSetError(fps);
574 return rc;
575}
576
577static ssize_t gzdWrite(FDSTACK_t fps, const void * buf, size_t count)
578{
579 gzFile gzfile;
580 ssize_t rc;
581
582 gzfile = fps->fp;
583 if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */
584
585 rc = gzwrite(gzfile, (void *)buf, count);
586 if (rc < 0)
587 gzdSetError(fps);
588 return rc;
589}
590
591/* XXX zlib-1.0.4 has not */
592static int gzdSeek(FDSTACK_t fps, off_t pos, int whence)
593{
594 off_t p = pos;
595 int rc;
596#if HAVE_GZSEEK1
597 gzFile gzfile = fps->fp;
598
599 if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */
600
601 rc = gzseek(gzfile, p, whence);
602 if (rc < 0)
603 gzdSetError(fps);
604#else
605 rc = -2;
606#endif
607 return rc;
608}
609
610static int gzdClose(FDSTACK_t fps)
611{
612 gzFile gzfile = fps->fp;
613 int rc;
614
615 if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */
616
617 rc = gzclose(gzfile);
618
619 return (rc != 0) ? -1 : 0;
620}
621
622static long gzdTell(FDSTACK_t fps)
623{
624 off_t pos = -1;
625 gzFile gzfile = fps->fp;
626
627 if (gzfile != NULL((void*)0)) {
628#if HAVE_GZSEEK1
629 pos = gztell(gzfile);
630 if (pos < 0)
631 gzdSetError(fps);
632#else
633 pos = -2;
634#endif
635 }
636 return pos;
637}
638static const struct FDIO_s gzdio_s = {
639 "gzdio", "gzip",
640 gzdRead, gzdWrite, gzdSeek, gzdClose,
641 NULL((void*)0), gzdFdopen, gzdFlush, gzdTell, zfdError, zfdStrerr
642};
643static const FDIO_t gzdio = &gzdio_s ;
644
645/* =============================================================== */
646/* Support for BZIP2 library. */
647#if HAVE_BZLIB_H1
648
649#include <bzlib.h>
650
651static FD_t bzdFdopen(FD_t fd, int fdno, const char * fmode)
652{
653 BZFILE *bzfile = BZ2_bzdopen(fdno, fmode);
654
655 if (bzfile == NULL((void*)0))
656 return NULL((void*)0);
657
658 fdSetFdno(fd, -1); /* XXX skip the fdio close */
659 fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
660 return fd;
661}
662
663static int bzdFlush(FDSTACK_t fps)
664{
665 return BZ2_bzflush(fps->fp);
666}
667
668static ssize_t bzdRead(FDSTACK_t fps, void * buf, size_t count)
669{
670 BZFILE *bzfile = fps->fp;
671 ssize_t rc = 0;
672
673 if (bzfile)
674 rc = BZ2_bzread(bzfile, buf, count);
675 if (rc == -1) {
676 int zerror = 0;
677 if (bzfile) {
678 fps->errcookie = BZ2_bzerror(bzfile, &zerror);
679 }
680 }
681 return rc;
682}
683
684static ssize_t bzdWrite(FDSTACK_t fps, const void * buf, size_t count)
685{
686 BZFILE *bzfile = fps->fp;
687 ssize_t rc;
688
689 rc = BZ2_bzwrite(bzfile, (void *)buf, count);
690 if (rc == -1) {
691 int zerror = 0;
692 fps->errcookie = BZ2_bzerror(bzfile, &zerror);
693 }
694 return rc;
695}
696
697static int bzdClose(FDSTACK_t fps)
698{
699 BZFILE *bzfile = fps->fp;
700
701 if (bzfile == NULL((void*)0)) return -2;
702
703 /* bzclose() doesn't return errors */
704 BZ2_bzclose(bzfile);
705
706 return 0;
707}
708
709static const struct FDIO_s bzdio_s = {
710 "bzdio", "bzip2",
711 bzdRead, bzdWrite, NULL((void*)0), bzdClose,
712 NULL((void*)0), bzdFdopen, bzdFlush, NULL((void*)0), zfdError, zfdStrerr
713};
714static const FDIO_t bzdio = &bzdio_s ;
715
716#endif /* HAVE_BZLIB_H */
717
718/* =============================================================== */
719/* Support for LZMA library. */
720
721#ifdef HAVE_LZMA_H1
722
723#include <sys/types.h>
724#include <inttypes.h>
725#include <lzma.h>
726/* Multithreading support in stable API since xz 5.2.0 */
727#if LZMA_VERSION(5 * 10000000U + 2 * 10000U + 3 * 10U + 2) >= 50020002
728#define HAVE_LZMA_MT
729#endif
730
731#define kBufferSize(1 << 15) (1 << 15)
732
733typedef struct lzfile {
734 /* IO buffer */
735 uint8_t buf[kBufferSize(1 << 15)];
736
737 lzma_stream strm;
738
739 FILE *file;
740
741 int encoding;
742 int eof;
743
744} LZFILE;
745
746static LZFILE *lzopen_internal(const char *mode, int fd, int xz)
747{
748 int level = LZMA_PRESET_DEFAULT6U;
749 int encoding = 0;
750 FILE *fp;
751 LZFILE *lzfile;
752 lzma_ret ret;
753 lzma_stream init_strm = LZMA_STREAM_INIT{ ((void*)0), 0, 0, ((void*)0), 0, 0, ((void*)0), ((void*)0),
((void*)0), ((void*)0), ((void*)0), ((void*)0), 0, 0, 0, 0, LZMA_RESERVED_ENUM
, LZMA_RESERVED_ENUM }
;
754 uint64_t mem_limit = rpmExpandNumeric("%{_xz_memlimit}");
755#ifdef HAVE_LZMA_MT
756 int threads = 0;
757#endif
758 for (; *mode; mode++) {
759 if (*mode == 'w')
760 encoding = 1;
761 else if (*mode == 'r')
762 encoding = 0;
763 else if (*mode >= '0' && *mode <= '9')
764 level = *mode - '0';
765 else if (*mode == 'T') {
766 if (isdigit(*(mode+1))((*__ctype_b_loc ())[(int) ((*(mode+1)))] & (unsigned short
int) _ISdigit)
) {
767#ifdef HAVE_LZMA_MT
768 threads = atoi(++mode);
769#endif
770 /* skip past rest of digits in string that atoi()
771 * should've processed
772 * */
773 while (isdigit(*++mode)((*__ctype_b_loc ())[(int) ((*++mode))] & (unsigned short
int) _ISdigit)
);
774 }
775#ifdef HAVE_LZMA_MT
776 else
777 threads = -1;
778#endif
779 }
780 }
781 fp = fdopen(fd, encoding ? "w" : "r");
782 if (!fp)
783 return NULL((void*)0);
784 lzfile = calloc(1, sizeof(*lzfile));
785 lzfile->file = fp;
786 lzfile->encoding = encoding;
787 lzfile->eof = 0;
788 lzfile->strm = init_strm;
789 if (encoding) {
790 if (xz) {
791#ifdef HAVE_LZMA_MT
792 if (!threads) {
793#endif
794 ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
795#ifdef HAVE_LZMA_MT
796 } else {
797 if (threads == -1)
798 threads = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN);
799 lzma_mt mt_options = {
800 .flags = 0,
801 .threads = threads,
802 .block_size = 0,
803 .timeout = 0,
804 .preset = level,
805 .filters = NULL((void*)0),
806 .check = LZMA_CHECK_SHA256 };
807
808#if __WORDSIZE64 == 32
809 /* In 32 bit environment, required memory easily exceeds memory address
810 * space limit if compressing using multiple threads.
811 * By setting a memory limit, liblzma will automatically adjust number
812 * of threads to avoid exceeding memory.
813 */
814 if (threads > 1) {
815 struct utsname u;
816 uint32_t memlimit = (SIZE_MAX(18446744073709551615UL)>>1) + (SIZE_MAX(18446744073709551615UL)>>3);
817 uint64_t memory_usage;
818 /* While a 32 bit linux kernel will have an address limit of 3GiB
819 * for processes (which is why set the memory limit to 2.5GiB as a safety
820 * margin), 64 bit kernels will have a limit of 4GiB for 32 bit binaries.
821 * Therefore the memory limit should be higher if running on a 64 bit
822 * kernel, so we increase it to 3,5GiB.
823 */
824 uname(&u);
825 if (strstr(u.machine, "64") || strstr(u.machine, "s390x")
826#if defined(__linux__1)
827 || ((personality(0xffffffff) & PER_MASK) == PER_LINUX32)
828#endif
829 )
830 memlimit += (SIZE_MAX(18446744073709551615UL)>>2);
831
832 /* keep reducing the number of threads until memory usage gets below limit */
833 while ((memory_usage = lzma_stream_encoder_mt_memusage(&mt_options)) > memlimit) {
834 /* number of threads shouldn't be able to hit zero with compression
835 * settings aailable to set through rpm... */
836 assert(--mt_options.threads != 0)((void) sizeof ((--mt_options.threads != 0) == 0), __extension__
({ if (--mt_options.threads != 0) ; else __assert_fail ("--mt_options.threads != 0"
, "rpmio.c", 836, __extension__ __PRETTY_FUNCTION__); }))
;
837 }
838 lzma_memlimit_set(&lzfile->strm, memlimit);
839
840 if (threads != (int)mt_options.threads)
841 rpmlog(RPMLOG_NOTICE,
842 "XZ: Adjusted the number of threads from %d to %d to not exceed the memory usage limit of %lu bytes",
843 threads, mt_options.threads, memlimit);
844 }
845#endif
846
847 ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options);
848 }
849#endif
850 } else {
851 lzma_options_lzma options;
852 lzma_lzma_preset(&options, level);
853 ret = lzma_alone_encoder(&lzfile->strm, &options);
854 }
855 } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
856 ret = lzma_auto_decoder(&lzfile->strm, mem_limit ? mem_limit : 100<<20, 0);
857 }
858 if (ret != LZMA_OK) {
859 switch (ret) {
860 case LZMA_MEM_ERROR:
861 rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed");
862 break;
863
864 case LZMA_DATA_ERROR:
865 rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded");
866 break;
867
868 default:
869 rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret);
870 break;
871 }
872 fclose(fp);
873 free(lzfile);
874 return NULL((void*)0);
875 }
876 return lzfile;
877}
878
879static int lzclose(LZFILE *lzfile)
880{
881 lzma_ret ret;
882 size_t n;
883 int rc;
884
885 if (!lzfile)
886 return -1;
887 if (lzfile->encoding) {
888 for (;;) {
889 lzfile->strm.avail_out = kBufferSize(1 << 15);
890 lzfile->strm.next_out = lzfile->buf;
891 ret = lzma_code(&lzfile->strm, LZMA_FINISH);
892 if (ret != LZMA_OK && ret != LZMA_STREAM_END)
893 return -1;
894 n = kBufferSize(1 << 15) - lzfile->strm.avail_out;
895 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
896 return -1;
897 if (ret == LZMA_STREAM_END)
898 break;
899 }
900 }
901 lzma_end(&lzfile->strm);
902 rc = fclose(lzfile->file);
903 free(lzfile);
904 return rc;
905}
906
907static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
908{
909 lzma_ret ret;
910 int eof = 0;
911
912 if (!lzfile || lzfile->encoding)
913 return -1;
914 if (lzfile->eof)
915 return 0;
916 lzfile->strm.next_out = buf;
917 lzfile->strm.avail_out = len;
918 for (;;) {
919 if (!lzfile->strm.avail_in) {
920 lzfile->strm.next_in = lzfile->buf;
921 lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize(1 << 15), lzfile->file);
922 if (!lzfile->strm.avail_in)
923 eof = 1;
924 }
925 ret = lzma_code(&lzfile->strm, LZMA_RUN);
926 if (ret == LZMA_STREAM_END) {
927 lzfile->eof = 1;
928 return len - lzfile->strm.avail_out;
929 }
930 if (ret != LZMA_OK)
931 return -1;
932 if (!lzfile->strm.avail_out)
933 return len;
934 if (eof)
935 return -1;
936 }
937}
938
939static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
940{
941 lzma_ret ret;
942 size_t n;
943 if (!lzfile || !lzfile->encoding)
944 return -1;
945 if (!len)
946 return 0;
947 lzfile->strm.next_in = buf;
948 lzfile->strm.avail_in = len;
949 for (;;) {
950 lzfile->strm.next_out = lzfile->buf;
951 lzfile->strm.avail_out = kBufferSize(1 << 15);
952 ret = lzma_code(&lzfile->strm, LZMA_RUN);
953 if (ret != LZMA_OK)
954 return -1;
955 n = kBufferSize(1 << 15) - lzfile->strm.avail_out;
956 if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
957 return -1;
958 if (!lzfile->strm.avail_in)
959 return len;
960 }
961}
962
963static FD_t xzdFdopen(FD_t fd, int fdno, const char * fmode)
964{
965 LZFILE *lzfile = lzopen_internal(fmode, fdno, 1);
966
967 if (lzfile == NULL((void*)0))
968 return NULL((void*)0);
969
970 fdSetFdno(fd, -1); /* XXX skip the fdio close */
971 fdPush(fd, xzdio, lzfile, fdno);
972 return fd;
973}
974
975static FD_t lzdFdopen(FD_t fd, int fdno, const char * fmode)
976{
977 LZFILE *lzfile = lzopen_internal(fmode, fdno, 0);
978
979 if (lzfile == NULL((void*)0))
980 return NULL((void*)0);
981
982 fdSetFdno(fd, -1); /* XXX skip the fdio close */
983 fdPush(fd, lzdio, lzfile, fdno);
984 return fd;
985}
986
987static int lzdFlush(FDSTACK_t fps)
988{
989 LZFILE *lzfile = fps->fp;
990 return fflush(lzfile->file);
991}
992
993static ssize_t lzdRead(FDSTACK_t fps, void * buf, size_t count)
994{
995 LZFILE *lzfile = fps->fp;
996 ssize_t rc = 0;
997
998 if (lzfile)
999 rc = lzread(lzfile, buf, count);
1000 if (rc == -1) {
1001 fps->errcookie = "Lzma: decoding error";
1002 }
1003 return rc;
1004}
1005
1006static ssize_t lzdWrite(FDSTACK_t fps, const void * buf, size_t count)
1007{
1008 LZFILE *lzfile = fps->fp;
1009 ssize_t rc = 0;
1010
1011 rc = lzwrite(lzfile, (void *)buf, count);
1012 if (rc < 0) {
1013 fps->errcookie = "Lzma: encoding error";
1014 }
1015 return rc;
1016}
1017
1018static int lzdClose(FDSTACK_t fps)
1019{
1020 LZFILE *lzfile = fps->fp;
1021 int rc;
1022
1023 if (lzfile == NULL((void*)0)) return -2;
1024 rc = lzclose(lzfile);
1025
1026 return rc;
1027}
1028
1029static struct FDIO_s xzdio_s = {
1030 "xzdio", "xz",
1031 lzdRead, lzdWrite, NULL((void*)0), lzdClose,
1032 NULL((void*)0), xzdFdopen, lzdFlush, NULL((void*)0), zfdError, zfdStrerr
1033};
1034static const FDIO_t xzdio = &xzdio_s;
1035
1036static struct FDIO_s lzdio_s = {
1037 "lzdio", "lzma",
1038 lzdRead, lzdWrite, NULL((void*)0), lzdClose,
1039 NULL((void*)0), lzdFdopen, lzdFlush, NULL((void*)0), zfdError, zfdStrerr
1040};
1041static const FDIO_t lzdio = &lzdio_s;
1042
1043#endif /* HAVE_LZMA_H */
1044
1045/* =============================================================== */
1046/* Support for ZSTD library. */
1047#ifdef HAVE_ZSTD
1048
1049#include <zstd.h>
1050
1051typedef struct rpmzstd_s {
1052 int flags; /*!< open flags. */
1053 int fdno;
1054 int level; /*!< compression level */
1055 FILE * fp;
1056 void * _stream; /*!< ZSTD_{C,D}Stream */
1057 size_t nb;
1058 void * b;
1059 ZSTD_inBuffer zib; /*!< ZSTD_inBuffer */
1060 ZSTD_outBuffer zob; /*!< ZSTD_outBuffer */
1061} * rpmzstd;
1062
1063static rpmzstd rpmzstdNew(int fdno, const char *fmode)
1064{
1065 int flags = 0;
1066 int level = 3;
1067 const char * s = fmode;
1068 char stdio[32];
1069 char *t = stdio;
1070 char *te = t + sizeof(stdio) - 2;
1071 int c;
1072
1073 switch ((c = *s++)) {
1074 case 'a':
1075 *t++ = (char)c;
1076 flags &= ~O_ACCMODE0003;
1077 flags |= O_WRONLY01 | O_CREAT0100 | O_APPEND02000;
1078 break;
1079 case 'w':
1080 *t++ = (char)c;
1081 flags &= ~O_ACCMODE0003;
1082 flags |= O_WRONLY01 | O_CREAT0100 | O_TRUNC01000;
1083 break;
1084 case 'r':
1085 *t++ = (char)c;
1086 flags &= ~O_ACCMODE0003;
1087 flags |= O_RDONLY00;
1088 break;
1089 }
1090
1091 while ((c = *s++) != 0) {
1092 switch (c) {
1093 case '.':
1094 break;
1095 case '+':
1096 if (t < te) *t++ = c;
1097 flags &= ~O_ACCMODE0003;
1098 flags |= O_RDWR02;
1099 continue;
1100 break;
1101 default:
1102 if (c >= (int)'0' && c <= (int)'9') {
1103 level = strtol(s-1, (char **)&s, 10);
1104 if (level < 1){
1105 level = 1;
1106 rpmlog(RPMLOG_WARNING, "Invalid compression level for zstd. Using %i instead.\n", 1);
1107 }
1108 if (level > 19) {
1109 level = 19;
1110 rpmlog(RPMLOG_WARNING, "Invalid compression level for zstd. Using %i instead.\n", 19);
1111 }
1112 }
1113 continue;
1114 break;
1115 }
1116 break;
1117 }
1118 *t = '\0';
1119
1120 FILE * fp = fdopen(fdno, stdio);
1121 if (fp == NULL((void*)0))
1122 return NULL((void*)0);
1123
1124 void * _stream = NULL((void*)0);
1125 size_t nb = 0;
1126
1127 if ((flags & O_ACCMODE0003) == O_RDONLY00) { /* decompressing */
1128 if ((_stream = (void *) ZSTD_createDStream()) == NULL((void*)0)
1129 || ZSTD_isError(ZSTD_initDStream(_stream))) {
1130 return NULL((void*)0);
1131 }
1132 nb = ZSTD_DStreamInSize();
1133 } else { /* compressing */
1134 if ((_stream = (void *) ZSTD_createCStream()) == NULL((void*)0)
1135 || ZSTD_isError(ZSTD_initCStream(_stream, level))) {
1136 return NULL((void*)0);
1137 }
1138 nb = ZSTD_CStreamOutSize();
1139 }
1140
1141 rpmzstd zstd = (rpmzstd) xcalloc(1, sizeof(*zstd))rcalloc((1), (sizeof(*zstd)));
1142 zstd->flags = flags;
1143 zstd->fdno = fdno;
1144 zstd->level = level;
1145 zstd->fp = fp;
1146 zstd->_stream = _stream;
1147 zstd->nb = nb;
1148 zstd->b = xmalloc(nb)rmalloc((nb));
1149
1150 return zstd;
1151}
1152
1153static FD_t zstdFdopen(FD_t fd, int fdno, const char * fmode)
1154{
1155 rpmzstd zstd = rpmzstdNew(fdno, fmode);
1156
1157 if (zstd == NULL((void*)0))
1158 return NULL((void*)0);
1159
1160 fdSetFdno(fd, -1); /* XXX skip the fdio close */
1161 fdPush(fd, zstdio, zstd, fdno); /* Push zstdio onto stack */
1162 return fd;
1163}
1164
1165static int zstdFlush(FDSTACK_t fps)
1166{
1167 rpmzstd zstd = (rpmzstd) fps->fp;
1168assert(zstd)((void) sizeof ((zstd) == 0), __extension__ ({ if (zstd) ; else
__assert_fail ("zstd", "rpmio.c", 1168, __extension__ __PRETTY_FUNCTION__
); }))
;
1169 int rc = -1;
1170
1171 if ((zstd->flags & O_ACCMODE0003) == O_RDONLY00) { /* decompressing */
1172 rc = 0;
1173 } else { /* compressing */
1174 /* close frame */
1175 zstd->zob.dst = zstd->b;
1176 zstd->zob.size = zstd->nb;
1177 zstd->zob.pos = 0;
1178 int xx = ZSTD_flushStream(zstd->_stream, &zstd->zob);
1179 if (ZSTD_isError(xx))
1180 fps->errcookie = ZSTD_getErrorName(xx);
1181 else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))
1182 fps->errcookie = "zstdFlush fwrite failed.";
1183 else
1184 rc = 0;
1185 }
1186 return rc;
1187}
1188
1189static ssize_t zstdRead(FDSTACK_t fps, void * buf, size_t count)
1190{
1191 rpmzstd zstd = (rpmzstd) fps->fp;
1192assert(zstd)((void) sizeof ((zstd) == 0), __extension__ ({ if (zstd) ; else
__assert_fail ("zstd", "rpmio.c", 1192, __extension__ __PRETTY_FUNCTION__
); }))
;
1193 ZSTD_outBuffer zob = { buf, count, 0 };
1194
1195 while (zob.pos < zob.size) {
1196 /* Re-fill compressed data buffer. */
1197 if (zstd->zib.pos >= zstd->zib.size) {
1198 zstd->zib.size = fread(zstd->b, 1, zstd->nb, zstd->fp);
1199 if (zstd->zib.size == 0)
1200 break; /* EOF */
1201 zstd->zib.src = zstd->b;
1202 zstd->zib.pos = 0;
1203 }
1204
1205 /* Decompress next chunk. */
1206 int xx = ZSTD_decompressStream(zstd->_stream, &zob, &zstd->zib);
1207 if (ZSTD_isError(xx)) {
1208 fps->errcookie = ZSTD_getErrorName(xx);
1209 return -1;
1210 }
1211 }
1212 return zob.pos;
1213}
1214
1215static ssize_t zstdWrite(FDSTACK_t fps, const void * buf, size_t count)
1216{
1217 rpmzstd zstd = (rpmzstd) fps->fp;
1218assert(zstd)((void) sizeof ((zstd) == 0), __extension__ ({ if (zstd) ; else
__assert_fail ("zstd", "rpmio.c", 1218, __extension__ __PRETTY_FUNCTION__
); }))
;
1219 ZSTD_inBuffer zib = { buf, count, 0 };
1220
1221 while (zib.pos < zib.size) {
1222
1223 /* Reset to beginning of compressed data buffer. */
1224 zstd->zob.dst = zstd->b;
1225 zstd->zob.size = zstd->nb;
1226 zstd->zob.pos = 0;
1227
1228 /* Compress next chunk. */
1229 int xx = ZSTD_compressStream(zstd->_stream, &zstd->zob, &zib);
1230 if (ZSTD_isError(xx)) {
1231 fps->errcookie = ZSTD_getErrorName(xx);
1232 return -1;
1233 }
1234
1235 /* Write compressed data buffer. */
1236 if (zstd->zob.pos > 0) {
1237 size_t nw = fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp);
1238 if (nw != zstd->zob.pos) {
1239 fps->errcookie = "zstdWrite fwrite failed.";
1240 return -1;
1241 }
1242 }
1243 }
1244 return zib.pos;
1245}
1246
1247static int zstdClose(FDSTACK_t fps)
1248{
1249 rpmzstd zstd = (rpmzstd) fps->fp;
1250assert(zstd)((void) sizeof ((zstd) == 0), __extension__ ({ if (zstd) ; else
__assert_fail ("zstd", "rpmio.c", 1250, __extension__ __PRETTY_FUNCTION__
); }))
;
1251 int rc = -2;
1252
1253 if ((zstd->flags & O_ACCMODE0003) == O_RDONLY00) { /* decompressing */
1254 rc = 0;
1255 ZSTD_freeDStream(zstd->_stream);
1256 } else { /* compressing */
1257 /* close frame */
1258 zstd->zob.dst = zstd->b;
1259 zstd->zob.size = zstd->nb;
1260 zstd->zob.pos = 0;
1261 int xx = ZSTD_endStream(zstd->_stream, &zstd->zob);
1262 if (ZSTD_isError(xx))
1263 fps->errcookie = ZSTD_getErrorName(xx);
1264 else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))
1265 fps->errcookie = "zstdClose fwrite failed.";
1266 else
1267 rc = 0;
1268 ZSTD_freeCStream(zstd->_stream);
1269 }
1270
1271 if (zstd->fp && fileno(zstd->fp) > 2)
1272 (void) fclose(zstd->fp);
1273
1274 if (zstd->b) free(zstd->b);
1275 free(zstd);
1276
1277 return rc;
1278}
1279
1280static const struct FDIO_s zstdio_s = {
1281 "zstdio", "zstd",
1282 zstdRead, zstdWrite, NULL((void*)0), zstdClose,
1283 NULL((void*)0), zstdFdopen, zstdFlush, NULL((void*)0), zfdError, zfdStrerr
1284};
1285static const FDIO_t zstdio = &zstdio_s ;
1286
1287#endif /* HAVE_ZSTD */
1288
1289/* =============================================================== */
1290
1291#define FDIOVEC(_fps, _vec)((_fps) && (_fps)->io) ? (_fps)->io->_vec : (
(void*)0)
\
1292 ((_fps) && (_fps)->io) ? (_fps)->io->_vec : NULL((void*)0)
1293
1294const char *Fstrerror(FD_t fd)
1295{
1296 const char *err = "";
1297
1298 if (fd != NULL((void*)0)) {
1299 FDSTACK_t fps = fdGetFps(fd);
1300 fdio_fstrerr_function_t _fstrerr = FDIOVEC(fps, _fstrerr)((fps) && (fps)->io) ? (fps)->io->_fstrerr :
((void*)0)
;
1301 if (_fstrerr)
1302 err = _fstrerr(fps);
1303 } else if (errno(*__errno_location ())){
1304 err = strerror(errno(*__errno_location ()));
1305 }
1306 return err;
1307}
1308
1309ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
1310{
1311 ssize_t rc = -1;
1312
1313 if (fd != NULL((void*)0)) {
1314 FDSTACK_t fps = fdGetFps(fd);
1315 fdio_read_function_t _read = FDIOVEC(fps, read)((fps) && (fps)->io) ? (fps)->io->read : ((void
*)0)
;
1316
1317 fdstat_enter(fd, FDSTAT_READ);
1318 do {
1319 rc = (_read ? (*_read) (fps, buf, size * nmemb) : -2);
1320 } while (rc == -1 && errno(*__errno_location ()) == EINTR4);
1321 fdstat_exit(fd, FDSTAT_READ, rc);
1322
1323 if (fd->digests && rc > 0)
1324 fdUpdateDigests(fd, buf, rc);
1325 }
1326
1327 DBGIO(fd, (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n",if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n"
, fd, buf, (long)size * nmemb, (long)rc, fdbg(fd))
1328 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFread(%p,%p,%ld) rc %ld %s\n"
, fd, buf, (long)size * nmemb, (long)rc, fdbg(fd))
;
1329
1330 return rc;
1331}
1332
1333ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
1334{
1335 ssize_t rc = -1;
1336
1337 if (fd != NULL((void*)0)) {
1338 FDSTACK_t fps = fdGetFps(fd);
1339 fdio_write_function_t _write = FDIOVEC(fps, write)((fps) && (fps)->io) ? (fps)->io->write : ((
void*)0)
;
1340
1341 fdstat_enter(fd, FDSTAT_WRITE);
1342 do {
1343 rc = (_write ? _write(fps, buf, size * nmemb) : -2);
1344 } while (rc == -1 && errno(*__errno_location ()) == EINTR4);
1345 fdstat_exit(fd, FDSTAT_WRITE, rc);
1346
1347 if (fd->digests && rc > 0)
1348 fdUpdateDigests(fd, buf, rc);
1349 }
1350
1351 DBGIO(fd, (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n",if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n"
, fd, buf, (long)size * nmemb, (long)rc, fdbg(fd))
1352 fd, buf, (long)size * nmemb, (long)rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFwrite(%p,%p,%ld) rc %ld %s\n"
, fd, buf, (long)size * nmemb, (long)rc, fdbg(fd))
;
1353
1354 return rc;
1355}
1356
1357int Fseek(FD_t fd, off_t offset, int whence)
1358{
1359 int rc = -1;
1360
1361 if (fd != NULL((void*)0)) {
1362 FDSTACK_t fps = fdGetFps(fd);
1363 fdio_seek_function_t _seek = FDIOVEC(fps, seek)((fps) && (fps)->io) ? (fps)->io->seek : ((void
*)0)
;
1364
1365 fdstat_enter(fd, FDSTAT_SEEK);
1366 rc = (_seek ? _seek(fps, offset, whence) : -2);
1367 fdstat_exit(fd, FDSTAT_SEEK, rc);
1368 }
1369
1370 DBGIO(fd, (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n",if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n"
, fd, (long)offset, whence, (unsigned long)rc, fdbg(fd))
1371 fd, (long)offset, whence, (unsigned long)rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFseek(%p,%ld,%d) rc %lx %s\n"
, fd, (long)offset, whence, (unsigned long)rc, fdbg(fd))
;
1372
1373 return rc;
1374}
1375
1376int Fclose(FD_t fd)
1377{
1378 int rc = 0, ec = 0;
1379
1380 if (fd == NULL((void*)0))
7
Taking false branch
1381 return -1;
1382
1383 fd = fdLink(fd);
1384 fdstat_enter(fd, FDSTAT_CLOSE);
1385 for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fdPop(fd)) {
8
Assuming 'fps' is not equal to NULL
9
Loop condition is true. Entering loop body
15
Calling 'fdPop'
1386 if (fps->fdno >= 0) {
10
Assuming the condition is false
11
Taking false branch
1387 fdio_close_function_t _close = FDIOVEC(fps, close)((fps) && (fps)->io) ? (fps)->io->close : ((
void*)0)
;
1388 rc = _close ? _close(fps) : -2;
1389
1390 if (ec == 0 && rc)
1391 ec = rc;
1392 }
1393
1394 /* Debugging stats for compresed types */
1395 if ((_rpmio_debug || rpmIsDebug()(rpmlogSetMask(0) >= (1 << ((unsigned)(RPMLOG_DEBUG)
)))
) && fps->fdno == -1)
12
Assuming '_rpmio_debug' is 0
1396 fdstat_print(fd, fps->io->ioname, stderrstderr);
1397
1398 /* Leave freeing the last one after stats */
1399 if (fps->prev == NULL((void*)0))
13
Assuming the condition is false
14
Taking false branch
1400 break;
1401 }
1402 fdstat_exit(fd, FDSTAT_CLOSE, rc);
1403 DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFclose(%p) rc %lx %s\n"
, (fd ? fd : ((void*)0)), (unsigned long)rc, fdbg(fd))
1404 (fd ? fd : NULL), (unsigned long)rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFclose(%p) rc %lx %s\n"
, (fd ? fd : ((void*)0)), (unsigned long)rc, fdbg(fd))
;
1405 fdPop(fd);
1406
1407 fdFree(fd);
1408 return ec;
1409}
1410
1411/**
1412 * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags.
1413 * returns stdio[0] = NUL on error.
1414 *
1415 * - gzopen: [0-9] is compression level
1416 * - gzopen: 'f' is filtered (Z_FILTERED)
1417 * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY)
1418 * - bzopen: [1-9] is block size (modulo 100K)
1419 * - bzopen: 's' is smallmode
1420 * - HACK: '.' terminates, rest is type of I/O
1421 */
1422static void cvtfmode (const char *m,
1423 char *stdio, size_t nstdio,
1424 char *other, size_t nother,
1425 const char **end, int * f)
1426{
1427 int flags = 0;
1428 char c;
1429
1430 switch (*m) {
1431 case 'a':
1432 flags &= ~O_ACCMODE0003;
1433 flags |= O_WRONLY01 | O_CREAT0100 | O_APPEND02000;
1434 if (--nstdio > 0) *stdio++ = *m;
1435 break;
1436 case 'w':
1437 flags &= ~O_ACCMODE0003;
1438 flags |= O_WRONLY01 | O_CREAT0100 | O_TRUNC01000;
1439 if (--nstdio > 0) *stdio++ = *m;
1440 break;
1441 case 'r':
1442 flags &= ~O_ACCMODE0003;
1443 flags |= O_RDONLY00;
1444 if (--nstdio > 0) *stdio++ = *m;
1445 break;
1446 default:
1447 *stdio = '\0';
1448 return;
1449 break;
1450 }
1451 m++;
1452
1453 while ((c = *m++) != '\0') {
1454 switch (c) {
1455 case '.':
1456 break;
1457 case '+':
1458 flags &= ~O_ACCMODE0003;
1459 flags |= O_RDWR02;
1460 if (--nstdio > 0) *stdio++ = c;
1461 continue;
1462 break;
1463 case 'b':
1464 if (--nstdio > 0) *stdio++ = c;
1465 continue;
1466 break;
1467 case 'x':
1468 flags |= O_EXCL0200;
1469 if (--nstdio > 0) *stdio++ = c;
1470 continue;
1471 break;
1472 case '?':
1473 flags |= RPMIO_DEBUG_IO0x40000000;
1474 if (--nother > 0) *other++ = c;
1475 continue;
1476 break;
1477 default:
1478 if (--nother > 0) *other++ = c;
1479 continue;
1480 break;
1481 }
1482 break;
1483 }
1484
1485 *stdio = *other = '\0';
1486 if (end != NULL((void*)0))
1487 *end = (*m != '\0' ? m : NULL((void*)0));
1488 if (f != NULL((void*)0))
1489 *f = flags;
1490}
1491
1492static FDIO_t findIOT(const char *name)
1493{
1494 static FDIO_t fdio_types[] = {
1495 &fdio_s,
1496 &ufdio_s,
1497 &gzdio_s,
1498#if HAVE_BZLIB_H1
1499 &bzdio_s,
1500#endif
1501#if HAVE_LZMA_H1
1502 &xzdio_s,
1503 &lzdio_s,
1504#endif
1505#ifdef HAVE_ZSTD
1506 &zstdio_s,
1507#endif
1508 NULL((void*)0)
1509 };
1510 FDIO_t iot = NULL((void*)0);
1511
1512 for (FDIO_t *t = fdio_types; t && *t; t++) {
1513 if (rstreq(name, (*t)->ioname) ||
1514 ((*t)->name && rstreq(name, (*t)->name))) {
1515 iot = (*t);
1516 break;
1517 }
1518 }
1519
1520 return iot;
1521}
1522
1523FD_t Fdopen(FD_t ofd, const char *fmode)
1524{
1525 char stdio[20], other[20], zstdio[40];
1526 const char *end = NULL((void*)0);
1527 FDIO_t iot = NULL((void*)0);
1528 FD_t fd = ofd;
1529 int fdno = Fileno(ofd);
1530
1531if (_rpmio_debug)
1532fprintf(stderrstderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
1533
1534 if (fd == NULL((void*)0) || fmode == NULL((void*)0) || fdno < 0)
1535 return NULL((void*)0);
1536
1537 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL((void*)0));
1538 if (stdio[0] == '\0')
1539 return NULL((void*)0);
1540 zstdio[0] = '\0';
1541 strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio) - 1);
1542 strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio) - 1);
1543
1544 if (end == NULL((void*)0) && other[0] == '\0')
1545 return fd;
1546
1547 if (end && *end) {
1548 iot = findIOT(end);
1549 } else if (other[0] != '\0') {
1550 for (end = other; *end && strchr("0123456789fh", *end); end++)
1551 {};
1552 if (*end == '\0')
1553 iot = findIOT("gzdio");
1554 }
1555
1556 if (iot && iot->_fdopen)
1557 fd = iot->_fdopen(fd, fdno, zstdio);
1558
1559DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n"
, ofd, fmode, (fd ? fd : ((void*)0)), fdbg(fd))
;
1560 return fd;
1561}
1562
1563FD_t Fopen(const char *path, const char *fmode)
1564{
1565 char stdio[20], other[20];
1566 const char *end = NULL((void*)0);
1567 mode_t perms = 0666;
1568 int flags = 0;
1569 FD_t fd = NULL((void*)0);
1570
1571 if (path == NULL((void*)0) || fmode == NULL((void*)0))
1572 return NULL((void*)0);
1573
1574 stdio[0] = '\0';
1575 cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags);
1576 if (stdio[0] == '\0')
1577 return NULL((void*)0);
1578
1579 if (end == NULL((void*)0) || rstreq(end, "fdio")) {
1580 if (_rpmio_debug)
1581 fprintf(stderrstderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
1582 fd = fdOpen(path, flags, perms);
1583 } else {
1584 if (_rpmio_debug)
1585 fprintf(stderrstderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
1586 fd = ufdOpen(path, flags, perms);
1587 }
1588
1589 /* Open compressed stream if necessary */
1590 if (fd)
1591 fd = Fdopen(fd, fmode);
1592
1593 DBGIO(fd, (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n",if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n"
, path, (unsigned)flags, (unsigned)perms, fdbg(fd))
1594 path, (unsigned)flags, (unsigned)perms, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==>\tFopen(\"%s\",%x,0%o) %s\n"
, path, (unsigned)flags, (unsigned)perms, fdbg(fd))
;
1595
1596 return fd;
1597}
1598
1599int Fflush(FD_t fd)
1600{
1601 int rc = -1;
1602 if (fd != NULL((void*)0)) {
1603 FDSTACK_t fps = fdGetFps(fd);
1604 fdio_fflush_function_t _fflush = FDIOVEC(fps, _fflush)((fps) && (fps)->io) ? (fps)->io->_fflush : (
(void*)0)
;
1605
1606 rc = (_fflush ? _fflush(fps) : -2);
1607 }
1608 return rc;
1609}
1610
1611off_t Ftell(FD_t fd)
1612{
1613 off_t pos = -1;
1614 if (fd != NULL((void*)0)) {
1615 FDSTACK_t fps = fdGetFps(fd);
1616 fdio_ftell_function_t _ftell = FDIOVEC(fps, _ftell)((fps) && (fps)->io) ? (fps)->io->_ftell : (
(void*)0)
;
1617
1618 pos = (_ftell ? _ftell(fps) : -2);
1619 }
1620 return pos;
1621}
1622
1623int Ferror(FD_t fd)
1624{
1625 int rc = 0;
1626
1627 if (fd == NULL((void*)0)) return -1;
1628 for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) {
1629 fdio_ferror_function_t _ferror = FDIOVEC(fps, _ferror)((fps) && (fps)->io) ? (fps)->io->_ferror : (
(void*)0)
;
1630 rc = _ferror(fps);
1631
1632 if (rc)
1633 break;
1634 }
1635DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==> Ferror(%p) rc %d %s\n"
, fd, rc, fdbg(fd))
;
1636 return rc;
1637}
1638
1639int Fileno(FD_t fd)
1640{
1641 int rc = -1;
1642
1643 if (fd == NULL((void*)0)) return -1;
1644 for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) {
1645 rc = fps->fdno;
1646 if (rc != -1)
1647 break;
1648 }
1649
1650DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)))if ((_rpmio_debug | (((fd)) ? ((FD_t)((fd)))->flags : 0)) &
(0x40000000)) fprintf (stderr, "==> Fileno(%p) rc %d %s\n"
, (fd ? fd : ((void*)0)), rc, fdbg(fd))
;
1651 return rc;
1652}
1653
1654/* XXX this is naive */
1655int Fcntl(FD_t fd, int op, void *lip)
1656{
1657 return fcntl(Fileno(fd), op, lip);
1658}
1659
1660rpmop fdOp(FD_t fd, fdOpX opx)
1661{
1662 rpmop op = NULL((void*)0);
1663
1664 if (fd != NULL((void*)0) && fd->stats != NULL((void*)0) && opx >= 0 && opx < FDSTAT_MAX)
1665 op = fd->stats->ops + opx;
1666 return op;
1667}
1668
1669int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp)
1670{
1671 static const ssize_t blenmax = (32 * BUFSIZ8192);
1672 ssize_t blen = 0;
1673 uint8_t * b = NULL((void*)0);
1674 ssize_t size;
1675 FD_t fd;
1676 int rc = 0;
1677
1678 fd = Fopen(fn, "r.ufdio");
1679 if (fd == NULL((void*)0) || Ferror(fd)) {
1
Taking false branch
1680 rc = 2;
1681 goto exit;
1682 }
1683
1684 size = fdSize(fd);
1685 blen = (size >= 0 ? size : blenmax);
2
'?' condition is false
1686 if (blen) {
3
Taking true branch
1687 int nb;
1688 b = xmalloc(blen+1)rmalloc((blen+1));
1689 b[0] = '\0';
1690 nb = Fread(b, sizeof(*b), blen, fd);
1691 if (Ferror(fd) || (size > 0 && nb != blen)) {
1692 rc = 1;
1693 goto exit;
1694 }
1695 if (blen == blenmax && nb < blen) {
4
Taking true branch
1696 blen = nb;
1697 b = xrealloc(b, blen+1)rrealloc((b), (blen+1));
1698 }
1699 b[blen] = '\0';
1700 }
1701
1702exit:
1703 if (fd) (void) Fclose(fd);
5
Taking true branch
6
Calling 'Fclose'
1704
1705 if (rc) {
1706 if (b) free(b);
1707 b = NULL((void*)0);
1708 blen = 0;
1709 }
1710
1711 if (bp) *bp = b;
1712 else if (b) free(b);
1713
1714 if (blenp) *blenp = blen;
1715
1716 return rc;
1717}
1718
1719void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
1720{
1721 return fdInitDigestID(fd, hashalgo, hashalgo, flags);
1722}
1723
1724void fdInitDigestID(FD_t fd, int hashalgo, int id, rpmDigestFlags flags)
1725{
1726 if (fd->digests == NULL((void*)0)) {
1727 fd->digests = rpmDigestBundleNew();
1728 }
1729 fdstat_enter(fd, FDSTAT_DIGEST);
1730 rpmDigestBundleAddID(fd->digests, hashalgo, id, flags);
1731 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1732}
1733
1734static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
1735{
1736 if (fd && fd->digests) {
1737 fdstat_enter(fd, FDSTAT_DIGEST);
1738 rpmDigestBundleUpdate(fd->digests, buf, buflen);
1739 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
1740 }
1741}
1742
1743void fdFiniDigest(FD_t fd, int id,
1744 void ** datap, size_t * lenp, int asAscii)
1745{
1746 if (fd && fd->digests) {
1747 fdstat_enter(fd, FDSTAT_DIGEST);
1748 rpmDigestBundleFinal(fd->digests, id, datap, lenp, asAscii);
1749 fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
1750 }
1751}
1752
1753DIGEST_CTX fdDupDigest(FD_t fd, int id)
1754{
1755 DIGEST_CTX ctx = NULL((void*)0);
1756
1757 if (fd && fd->digests)
1758 ctx = rpmDigestBundleDupCtx(fd->digests, id);
1759
1760 return ctx;
1761}