File: | rpmio/rpmio.c |
Warning: | line 97, column 5 Use of memory after it is freed |
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 | ||||
24 | typedef struct FDSTACK_s * FDSTACK_t; | |||
25 | ||||
26 | struct 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 | */ | |||
39 | typedef 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 | */ | |||
46 | struct _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 | ||||
67 | static FDSTACK_t fdGetFps(FD_t fd) | |||
68 | { | |||
69 | return (fd != NULL((void*)0)) ? fd->fps : NULL((void*)0); | |||
70 | } | |||
71 | ||||
72 | static void fdSetFdno(FD_t fd, int fdno) | |||
73 | { | |||
74 | if (fd) | |||
75 | fd->fps->fdno = fdno; | |||
76 | } | |||
77 | ||||
78 | static 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 | ||||
90 | static 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); | |||
97 | return fps; | |||
| ||||
98 | } | |||
99 | ||||
100 | void fdSetBundle(FD_t fd, rpmDigestBundle bundle) | |||
101 | { | |||
102 | if (fd) | |||
103 | fd->digests = bundle; | |||
104 | } | |||
105 | ||||
106 | rpmDigestBundle 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 | */ | |||
120 | typedef ssize_t (*fdio_read_function_t) (FDSTACK_t fps, void *buf, size_t nbytes); | |||
121 | typedef ssize_t (*fdio_write_function_t) (FDSTACK_t fps, const void *buf, size_t nbytes); | |||
122 | typedef int (*fdio_seek_function_t) (FDSTACK_t fps, off_t pos, int whence); | |||
123 | typedef int (*fdio_close_function_t) (FDSTACK_t fps); | |||
124 | typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode); | |||
125 | typedef FD_t (*fdio_fdopen_function_t) (FD_t fd, int fdno, const char * fmode); | |||
126 | typedef int (*fdio_fflush_function_t) (FDSTACK_t fps); | |||
127 | typedef long (*fdio_ftell_function_t) (FDSTACK_t fps); | |||
128 | typedef int (*fdio_ferror_function_t) (FDSTACK_t fps); | |||
129 | typedef const char * (*fdio_fstrerr_function_t)(FDSTACK_t fps); | |||
130 | ||||
131 | struct 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 */ | |||
148 | static const FDIO_t fdio; | |||
149 | static const FDIO_t ufdio; | |||
150 | static const FDIO_t gzdio; | |||
151 | #if HAVE_BZLIB_H1 | |||
152 | static const FDIO_t bzdio; | |||
153 | #endif | |||
154 | #ifdef HAVE_LZMA_H1 | |||
155 | static const FDIO_t xzdio; | |||
156 | static const FDIO_t lzdio; | |||
157 | #endif | |||
158 | #ifdef HAVE_ZSTD | |||
159 | static const FDIO_t zstdio; | |||
160 | #endif | |||
161 | ||||
162 | /** \ingroup rpmio | |||
163 | * Update digest(s) attached to fd. | |||
164 | */ | |||
165 | static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen); | |||
166 | static FD_t fdNew(int fdno, const char *descr); | |||
167 | /** | |||
168 | */ | |||
169 | int _rpmio_debug = 0; | |||
170 | ||||
171 | /* =============================================================== */ | |||
172 | ||||
173 | static 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 | ||||
201 | static 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 | ||||
207 | static 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 | ||||
217 | static 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 | ||||
247 | off_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 | ||||
257 | FD_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)); | |||
265 | DBGIO(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 */ | |||
270 | static int fdFlush(FDSTACK_t fps) | |||
271 | { | |||
272 | return 0; | |||
273 | } | |||
274 | ||||
275 | static int fdError(FDSTACK_t fps) | |||
276 | { | |||
277 | return fps->syserrno; | |||
278 | } | |||
279 | ||||
280 | static int zfdError(FDSTACK_t fps) | |||
281 | { | |||
282 | return (fps->syserrno || fps->errcookie != NULL((void*)0)) ? -1 : 0; | |||
283 | } | |||
284 | ||||
285 | static const char * fdStrerr(FDSTACK_t fps) | |||
286 | { | |||
287 | return (fps->syserrno != 0) ? strerror(fps->syserrno) : ""; | |||
288 | } | |||
289 | ||||
290 | static const char * zfdStrerr(FDSTACK_t fps) | |||
291 | { | |||
292 | return (fps->errcookie != NULL((void*)0)) ? fps->errcookie : ""; | |||
293 | } | |||
294 | ||||
295 | const 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 | ||||
329 | FD_t fdLink(FD_t fd) | |||
330 | { | |||
331 | if (fd) | |||
332 | fd->nrefs++; | |||
333 | return fd; | |||
334 | } | |||
335 | ||||
336 | FD_t fdFree( FD_t fd) | |||
337 | { | |||
338 | if (fd) { | |||
339 | if (--fd->nrefs > 0) | |||
340 | return fd; | |||
341 | fd->stats = _free(fd->stats)rfree((fd->stats)); | |||
342 | if (fd->digests) { | |||
343 | fd->digests = rpmDigestBundleFree(fd->digests); | |||
344 | } | |||
345 | free(fd->fps); | |||
346 | free(fd->descr); | |||
347 | free(fd); | |||
348 | } | |||
349 | return NULL((void*)0); | |||
350 | } | |||
351 | ||||
352 | static 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 | ||||
367 | static ssize_t fdRead(FDSTACK_t fps, void * buf, size_t count) | |||
368 | { | |||
369 | return read(fps->fdno, buf, count); | |||
370 | } | |||
371 | ||||
372 | static 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 | ||||
380 | static int fdSeek(FDSTACK_t fps, off_t pos, int whence) | |||
381 | { | |||
382 | return lseek(fps->fdno, pos, whence); | |||
383 | } | |||
384 | ||||
385 | static 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 | ||||
397 | static 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 | ||||
413 | static long fdTell(FDSTACK_t fps) | |||
414 | { | |||
415 | return lseek(fps->fdno, 0, SEEK_CUR1); | |||
416 | } | |||
417 | ||||
418 | static 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 | }; | |||
423 | static const FDIO_t fdio = &fdio_s ; | |||
424 | ||||
425 | off_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 | ||||
459 | static 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 | } | |||
483 | static 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 | ||||
489 | if (_rpmio_debug) | |||
490 | fprintf(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 | ||||
523 | static 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 | }; | |||
528 | static const FDIO_t ufdio = &ufdio_s ; | |||
529 | ||||
530 | /* =============================================================== */ | |||
531 | /* Support for GZIP library. */ | |||
532 | #include <zlib.h> | |||
533 | ||||
534 | static 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 | ||||
546 | static 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 | ||||
553 | static 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 | ||||
564 | static 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 | ||||
577 | static 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 */ | |||
592 | static 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 | ||||
610 | static 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 | ||||
622 | static 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 | } | |||
638 | static const struct FDIO_s gzdio_s = { | |||
639 | "gzdio", "gzip", | |||
640 | gzdRead, gzdWrite, gzdSeek, gzdClose, | |||
641 | NULL((void*)0), gzdFdopen, gzdFlush, gzdTell, zfdError, zfdStrerr | |||
642 | }; | |||
643 | static const FDIO_t gzdio = &gzdio_s ; | |||
644 | ||||
645 | /* =============================================================== */ | |||
646 | /* Support for BZIP2 library. */ | |||
647 | #if HAVE_BZLIB_H1 | |||
648 | ||||
649 | #include <bzlib.h> | |||
650 | ||||
651 | static 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 | ||||
663 | static int bzdFlush(FDSTACK_t fps) | |||
664 | { | |||
665 | return BZ2_bzflush(fps->fp); | |||
666 | } | |||
667 | ||||
668 | static 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 | ||||
684 | static 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 | ||||
697 | static 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 | ||||
709 | static 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 | }; | |||
714 | static 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 | ||||
733 | typedef 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 | ||||
746 | static 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 | ||||
879 | static 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 | ||||
907 | static 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 | ||||
939 | static 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 | ||||
963 | static 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 | ||||
975 | static 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 | ||||
987 | static int lzdFlush(FDSTACK_t fps) | |||
988 | { | |||
989 | LZFILE *lzfile = fps->fp; | |||
990 | return fflush(lzfile->file); | |||
991 | } | |||
992 | ||||
993 | static 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 | ||||
1006 | static 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 | ||||
1018 | static 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 | ||||
1029 | static 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 | }; | |||
1034 | static const FDIO_t xzdio = &xzdio_s; | |||
1035 | ||||
1036 | static 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 | }; | |||
1041 | static 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 | ||||
1051 | typedef 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 | ||||
1063 | static 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 | ||||
1153 | static 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 | ||||
1165 | static int zstdFlush(FDSTACK_t fps) | |||
1166 | { | |||
1167 | rpmzstd zstd = (rpmzstd) fps->fp; | |||
1168 | assert(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 | ||||
1189 | static ssize_t zstdRead(FDSTACK_t fps, void * buf, size_t count) | |||
1190 | { | |||
1191 | rpmzstd zstd = (rpmzstd) fps->fp; | |||
1192 | assert(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 | ||||
1215 | static ssize_t zstdWrite(FDSTACK_t fps, const void * buf, size_t count) | |||
1216 | { | |||
1217 | rpmzstd zstd = (rpmzstd) fps->fp; | |||
1218 | assert(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 | ||||
1247 | static int zstdClose(FDSTACK_t fps) | |||
1248 | { | |||
1249 | rpmzstd zstd = (rpmzstd) fps->fp; | |||
1250 | assert(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 | ||||
1280 | static 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 | }; | |||
1285 | static 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 | ||||
1294 | const 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 | ||||
1309 | ssize_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 | ||||
1333 | ssize_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 | ||||
1357 | int 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 | ||||
1376 | int Fclose(FD_t fd) | |||
1377 | { | |||
1378 | int rc = 0, ec = 0; | |||
1379 | ||||
1380 | if (fd == NULL((void*)0)) | |||
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)) { | |||
1386 | if (fps->fdno >= 0) { | |||
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) | |||
1396 | fdstat_print(fd, fps->io->ioname, stderrstderr); | |||
1397 | ||||
1398 | /* Leave freeing the last one after stats */ | |||
1399 | if (fps->prev == NULL((void*)0)) | |||
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 | */ | |||
1422 | static 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 | ||||
1492 | static 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 | ||||
1523 | FD_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 | ||||
1531 | if (_rpmio_debug) | |||
1532 | fprintf(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 | ||||
1559 | DBGIO(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 | ||||
1563 | FD_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 | ||||
1599 | int 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 | ||||
1611 | off_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 | ||||
1623 | int 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 | } | |||
1635 | DBGIO(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 | ||||
1639 | int 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 | ||||
1650 | DBGIO(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 */ | |||
1655 | int Fcntl(FD_t fd, int op, void *lip) | |||
1656 | { | |||
1657 | return fcntl(Fileno(fd), op, lip); | |||
1658 | } | |||
1659 | ||||
1660 | rpmop 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 | ||||
1669 | int 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)) { | |||
| ||||
1680 | rc = 2; | |||
1681 | goto exit; | |||
1682 | } | |||
1683 | ||||
1684 | size = fdSize(fd); | |||
1685 | blen = (size >= 0 ? size : blenmax); | |||
1686 | if (blen) { | |||
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) { | |||
1696 | blen = nb; | |||
1697 | b = xrealloc(b, blen+1)rrealloc((b), (blen+1)); | |||
1698 | } | |||
1699 | b[blen] = '\0'; | |||
1700 | } | |||
1701 | ||||
1702 | exit: | |||
1703 | if (fd) (void) Fclose(fd); | |||
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 | ||||
1719 | void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags) | |||
1720 | { | |||
1721 | return fdInitDigestID(fd, hashalgo, hashalgo, flags); | |||
1722 | } | |||
1723 | ||||
1724 | void 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 | ||||
1734 | static 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 | ||||
1743 | void 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 | ||||
1753 | DIGEST_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 | } |