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 | static const FDIO_t bzdio; | |||
152 | static const FDIO_t xzdio; | |||
153 | static const FDIO_t lzdio; | |||
154 | ||||
155 | /** \ingroup rpmio | |||
156 | * Update digest(s) attached to fd. | |||
157 | */ | |||
158 | static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen); | |||
159 | static FD_t fdNew(int fdno, const char *descr); | |||
160 | /** | |||
161 | */ | |||
162 | int _rpmio_debug = 0; | |||
163 | ||||
164 | /* =============================================================== */ | |||
165 | ||||
166 | static const char * fdbg(FD_t fd) | |||
167 | { | |||
168 | static char buf[BUFSIZ8192]; | |||
169 | char *be = buf; | |||
170 | ||||
171 | buf[0] = '\0'; | |||
172 | if (fd == NULL((void*)0)) | |||
173 | return buf; | |||
174 | ||||
175 | *be++ = '\t'; | |||
176 | for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) { | |||
177 | FDIO_t iot = fps->io; | |||
178 | if (fps != fd->fps) | |||
179 | *be++ = ' '; | |||
180 | *be++ = '|'; | |||
181 | *be++ = ' '; | |||
182 | /* plain fd io types dont have _fopen() method */ | |||
183 | if (iot->_fdopen == NULL((void*)0)) { | |||
184 | sprintf(be, "%s %d fp %p", iot->ioname, fps->fdno, fps->fp); | |||
185 | } else { | |||
186 | sprintf(be, "%s %p fp %d", iot->ioname, fps->fp, fps->fdno); | |||
187 | } | |||
188 | be += strlen(be); | |||
189 | *be = '\0'; | |||
190 | } | |||
191 | return buf; | |||
192 | } | |||
193 | ||||
194 | static void fdstat_enter(FD_t fd, fdOpX opx) | |||
195 | { | |||
196 | if (fd->stats != NULL((void*)0)) | |||
197 | (void) rpmswEnter(fdOp(fd, opx), (ssize_t) 0); | |||
198 | } | |||
199 | ||||
200 | static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc) | |||
201 | { | |||
202 | if (rc == -1) { | |||
203 | FDSTACK_t fps = fdGetFps(fd); | |||
204 | fps->syserrno = errno(*__errno_location ()); | |||
205 | } | |||
206 | if (fd->stats != NULL((void*)0)) | |||
207 | (void) rpmswExit(fdOp(fd, opx), rc); | |||
208 | } | |||
209 | ||||
210 | static void fdstat_print(FD_t fd, const char * msg, FILE * fp) | |||
211 | { | |||
212 | static const int usec_scale = (1000*1000); | |||
213 | int opx; | |||
214 | ||||
215 | if (fd == NULL((void*)0) || fd->stats == NULL((void*)0)) return; | |||
216 | for (opx = 0; opx < 4; opx++) { | |||
217 | rpmop op = &fd->stats->ops[opx]; | |||
218 | if (op->count <= 0) continue; | |||
219 | switch (opx) { | |||
220 | case FDSTAT_READ: | |||
221 | if (msg) fprintf(fp, "%s:", msg); | |||
222 | fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n", | |||
223 | op->count, (long)op->bytes, | |||
224 | (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale)); | |||
225 | break; | |||
226 | case FDSTAT_WRITE: | |||
227 | if (msg) fprintf(fp, "%s:", msg); | |||
228 | fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n", | |||
229 | op->count, (long)op->bytes, | |||
230 | (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale)); | |||
231 | break; | |||
232 | case FDSTAT_SEEK: | |||
233 | break; | |||
234 | case FDSTAT_CLOSE: | |||
235 | break; | |||
236 | } | |||
237 | } | |||
238 | } | |||
239 | ||||
240 | off_t fdSize(FD_t fd) | |||
241 | { | |||
242 | struct stat sb; | |||
243 | off_t rc = -1; | |||
244 | ||||
245 | if (fd != NULL((void*)0) && fstat(Fileno(fd), &sb) == 0) | |||
246 | rc = sb.st_size; | |||
247 | return rc; | |||
248 | } | |||
249 | ||||
250 | FD_t fdDup(int fdno) | |||
251 | { | |||
252 | FD_t fd; | |||
253 | int nfdno; | |||
254 | ||||
255 | if ((nfdno = dup(fdno)) < 0) | |||
256 | return NULL((void*)0); | |||
257 | fd = fdNew(nfdno, NULL((void*)0)); | |||
258 | 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)); | |||
259 | return fd; | |||
260 | } | |||
261 | ||||
262 | /* Regular fd doesn't have fflush() equivalent but its not an error either */ | |||
263 | static int fdFlush(FDSTACK_t fps) | |||
264 | { | |||
265 | return 0; | |||
266 | } | |||
267 | ||||
268 | static int fdError(FDSTACK_t fps) | |||
269 | { | |||
270 | return fps->syserrno; | |||
271 | } | |||
272 | ||||
273 | static int zfdError(FDSTACK_t fps) | |||
274 | { | |||
275 | return (fps->syserrno || fps->errcookie != NULL((void*)0)) ? -1 : 0; | |||
276 | } | |||
277 | ||||
278 | static const char * fdStrerr(FDSTACK_t fps) | |||
279 | { | |||
280 | return (fps->syserrno != 0) ? strerror(fps->syserrno) : ""; | |||
281 | } | |||
282 | ||||
283 | static const char * zfdStrerr(FDSTACK_t fps) | |||
284 | { | |||
285 | return (fps->errcookie != NULL((void*)0)) ? fps->errcookie : ""; | |||
286 | } | |||
287 | ||||
288 | const char * Fdescr(FD_t fd) | |||
289 | { | |||
290 | if (fd == NULL((void*)0)) | |||
291 | return _("[none]")dcgettext ("rpm", "[none]", 5); | |||
292 | ||||
293 | /* Lazy lookup if description is not set (eg dupped fd) */ | |||
294 | if (fd->descr == NULL((void*)0)) { | |||
295 | int fdno = fd->fps->fdno; | |||
296 | #if defined(__linux__1) | |||
297 | /* Grab the path from /proc if we can */ | |||
298 | char *procpath = NULL((void*)0); | |||
299 | char buf[PATH_MAX4096]; | |||
300 | ssize_t llen; | |||
301 | ||||
302 | rasprintf(&procpath, "/proc/self/fd/%d", fdno); | |||
303 | llen = readlink(procpath, buf, sizeof(buf)-1); | |||
304 | free(procpath); | |||
305 | ||||
306 | if (llen >= 1) { | |||
307 | buf[llen] = '\0'; | |||
308 | /* Real paths in /proc are always absolute */ | |||
309 | if (buf[0] == '/') | |||
310 | fd->descr = xstrdup(buf)rstrdup((buf)); | |||
311 | else | |||
312 | fd->descr = rstrscat(NULL((void*)0), "[", buf, "]", NULL((void*)0)); | |||
313 | } | |||
314 | #endif | |||
315 | /* Still no description, base it on fdno which is always there */ | |||
316 | if (fd->descr == NULL((void*)0)) | |||
317 | rasprintf(&(fd->descr), "[fd %d]", fdno); | |||
318 | } | |||
319 | return fd->descr; | |||
320 | } | |||
321 | ||||
322 | FD_t fdLink(FD_t fd) | |||
323 | { | |||
324 | if (fd) | |||
325 | fd->nrefs++; | |||
326 | return fd; | |||
327 | } | |||
328 | ||||
329 | FD_t fdFree( FD_t fd) | |||
330 | { | |||
331 | if (fd) { | |||
332 | if (--fd->nrefs > 0) | |||
333 | return fd; | |||
334 | fd->stats = _free(fd->stats)rfree((fd->stats)); | |||
335 | if (fd->digests) { | |||
336 | fd->digests = rpmDigestBundleFree(fd->digests); | |||
337 | } | |||
338 | free(fd->fps); | |||
339 | free(fd->descr); | |||
340 | free(fd); | |||
341 | } | |||
342 | return NULL((void*)0); | |||
343 | } | |||
344 | ||||
345 | static FD_t fdNew(int fdno, const char *descr) | |||
346 | { | |||
347 | FD_t fd = xcalloc(1, sizeof(*fd))rcalloc((1), (sizeof(*fd))); | |||
348 | fd->nrefs = 0; | |||
349 | fd->flags = 0; | |||
350 | fd->magic = FDMAGIC0x04463138; | |||
351 | fd->urlType = URL_IS_UNKNOWN; | |||
352 | fd->stats = xcalloc(1, sizeof(*fd->stats))rcalloc((1), (sizeof(*fd->stats))); | |||
353 | fd->digests = NULL((void*)0); | |||
354 | fd->descr = descr ? xstrdup(descr)rstrdup((descr)) : NULL((void*)0); | |||
355 | ||||
356 | fdPush(fd, fdio, NULL((void*)0), fdno); | |||
357 | return fd; | |||
358 | } | |||
359 | ||||
360 | static ssize_t fdRead(FDSTACK_t fps, void * buf, size_t count) | |||
361 | { | |||
362 | return read(fps->fdno, buf, count); | |||
363 | } | |||
364 | ||||
365 | static ssize_t fdWrite(FDSTACK_t fps, const void * buf, size_t count) | |||
366 | { | |||
367 | if (count == 0) | |||
368 | return 0; | |||
369 | ||||
370 | return write(fps->fdno, buf, count); | |||
371 | } | |||
372 | ||||
373 | static int fdSeek(FDSTACK_t fps, off_t pos, int whence) | |||
374 | { | |||
375 | return lseek(fps->fdno, pos, whence); | |||
376 | } | |||
377 | ||||
378 | static int fdClose(FDSTACK_t fps) | |||
379 | { | |||
380 | int fdno = fps->fdno; | |||
381 | int rc; | |||
382 | ||||
383 | fps->fdno = -1; | |||
384 | ||||
385 | rc = ((fdno >= 0) ? close(fdno) : -2); | |||
386 | ||||
387 | return rc; | |||
388 | } | |||
389 | ||||
390 | static FD_t fdOpen(const char *path, int flags, mode_t mode) | |||
391 | { | |||
392 | FD_t fd; | |||
393 | int fdno; | |||
394 | ||||
395 | fdno = open(path, flags, mode); | |||
396 | if (fdno < 0) return NULL((void*)0); | |||
397 | if (fcntl(fdno, F_SETFD2, FD_CLOEXEC1)) { | |||
398 | (void) close(fdno); | |||
399 | return NULL((void*)0); | |||
400 | } | |||
401 | fd = fdNew(fdno, path); | |||
402 | fd->flags = flags; | |||
403 | return fd; | |||
404 | } | |||
405 | ||||
406 | static long fdTell(FDSTACK_t fps) | |||
407 | { | |||
408 | return lseek(fps->fdno, 0, SEEK_CUR1); | |||
409 | } | |||
410 | ||||
411 | static const struct FDIO_s fdio_s = { | |||
412 | "fdio", NULL((void*)0), | |||
413 | fdRead, fdWrite, fdSeek, fdClose, | |||
414 | fdOpen, NULL((void*)0), fdFlush, fdTell, fdError, fdStrerr, | |||
415 | }; | |||
416 | static const FDIO_t fdio = &fdio_s ; | |||
417 | ||||
418 | off_t ufdCopy(FD_t sfd, FD_t tfd) | |||
419 | { | |||
420 | char buf[BUFSIZ8192]; | |||
421 | ssize_t rdbytes, wrbytes; | |||
422 | off_t total = 0; | |||
423 | ||||
424 | while (1) { | |||
425 | rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd); | |||
426 | ||||
427 | if (rdbytes > 0) { | |||
428 | wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, tfd); | |||
429 | if (wrbytes != rdbytes) { | |||
430 | total = -1; | |||
431 | break; | |||
432 | } | |||
433 | total += wrbytes; | |||
434 | } else { | |||
435 | if (rdbytes < 0) | |||
436 | total = -1; | |||
437 | break; | |||
438 | } | |||
439 | } | |||
440 | ||||
441 | return total; | |||
442 | } | |||
443 | ||||
444 | /* | |||
445 | * Deal with remote url's by fetching them with a helper application | |||
446 | * and treat as local file afterwards. | |||
447 | * TODO: | |||
448 | * - better error checking + reporting | |||
449 | * - curl & friends don't know about hkp://, transform to http? | |||
450 | */ | |||
451 | ||||
452 | static FD_t urlOpen(const char * url, int flags, mode_t mode) | |||
453 | { | |||
454 | FD_t fd; | |||
455 | char *dest = NULL((void*)0); | |||
456 | int rc = 1; /* assume failure */ | |||
457 | ||||
458 | fd = rpmMkTempFile(NULL((void*)0), &dest); | |||
459 | if (fd == NULL((void*)0)) { | |||
460 | return NULL((void*)0); | |||
461 | } | |||
462 | Fclose(fd); | |||
463 | ||||
464 | rc = urlGetFile(url, dest); | |||
465 | if (rc == 0) { | |||
466 | fd = fdOpen(dest, flags, mode); | |||
467 | unlink(dest); | |||
468 | } else { | |||
469 | fd = NULL((void*)0); | |||
470 | } | |||
471 | dest = _free(dest)rfree((dest)); | |||
472 | ||||
473 | return fd; | |||
474 | ||||
475 | } | |||
476 | static FD_t ufdOpen(const char * url, int flags, mode_t mode) | |||
477 | { | |||
478 | FD_t fd = NULL((void*)0); | |||
479 | const char * path; | |||
480 | urltype urlType = urlPath(url, &path); | |||
481 | ||||
482 | if (_rpmio_debug) | |||
483 | fprintf(stderrstderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mode); | |||
484 | ||||
485 | switch (urlType) { | |||
486 | case URL_IS_FTP: | |||
487 | case URL_IS_HTTPS: | |||
488 | case URL_IS_HTTP: | |||
489 | case URL_IS_HKP: | |||
490 | fd = urlOpen(url, flags, mode); | |||
491 | /* we're dealing with local file when urlOpen() returns */ | |||
492 | urlType = URL_IS_UNKNOWN; | |||
493 | break; | |||
494 | case URL_IS_DASH: | |||
495 | if ((flags & O_ACCMODE0003) == O_RDWR02) { | |||
496 | fd = NULL((void*)0); | |||
497 | } else { | |||
498 | fd = fdDup((flags & O_ACCMODE0003) == O_WRONLY01 ? | |||
499 | STDOUT_FILENO1 : STDIN_FILENO0); | |||
500 | } | |||
501 | break; | |||
502 | case URL_IS_PATH: | |||
503 | case URL_IS_UNKNOWN: | |||
504 | default: | |||
505 | fd = fdOpen(path, flags, mode); | |||
506 | break; | |||
507 | } | |||
508 | ||||
509 | if (fd != NULL((void*)0)) { | |||
510 | fd->fps->io = ufdio; | |||
511 | fd->urlType = urlType; | |||
512 | } | |||
513 | return fd; | |||
514 | } | |||
515 | ||||
516 | static const struct FDIO_s ufdio_s = { | |||
517 | "ufdio", NULL((void*)0), | |||
518 | fdRead, fdWrite, fdSeek, fdClose, | |||
519 | ufdOpen, NULL((void*)0), fdFlush, fdTell, fdError, fdStrerr | |||
520 | }; | |||
521 | static const FDIO_t ufdio = &ufdio_s ; | |||
522 | ||||
523 | /* =============================================================== */ | |||
524 | /* Support for GZIP library. */ | |||
525 | #include <zlib.h> | |||
526 | ||||
527 | static FD_t gzdFdopen(FD_t fd, int fdno, const char *fmode) | |||
528 | { | |||
529 | gzFile gzfile = gzdopen(fdno, fmode); | |||
530 | ||||
531 | if (gzfile == NULL((void*)0)) | |||
532 | return NULL((void*)0); | |||
533 | ||||
534 | fdSetFdno(fd, -1); /* XXX skip the fdio close */ | |||
535 | fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */ | |||
536 | return fd; | |||
537 | } | |||
538 | ||||
539 | static int gzdFlush(FDSTACK_t fps) | |||
540 | { | |||
541 | gzFile gzfile = fps->fp; | |||
542 | if (gzfile == NULL((void*)0)) return -2; | |||
543 | return gzflush(gzfile, Z_SYNC_FLUSH2); /* XXX W2DO? */ | |||
544 | } | |||
545 | ||||
546 | static void gzdSetError(FDSTACK_t fps) | |||
547 | { | |||
548 | gzFile gzfile = fps->fp; | |||
549 | int zerror = 0; | |||
550 | fps->errcookie = gzerror(gzfile, &zerror); | |||
551 | if (zerror == Z_ERRNO(-1)) { | |||
552 | fps->syserrno = errno(*__errno_location ()); | |||
553 | fps->errcookie = strerror(fps->syserrno); | |||
554 | } | |||
555 | } | |||
556 | ||||
557 | static ssize_t gzdRead(FDSTACK_t fps, void * buf, size_t count) | |||
558 | { | |||
559 | gzFile gzfile = fps->fp; | |||
560 | ssize_t rc; | |||
561 | ||||
562 | if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */ | |||
563 | ||||
564 | rc = gzread(gzfile, buf, count); | |||
565 | if (rc < 0) | |||
566 | gzdSetError(fps); | |||
567 | return rc; | |||
568 | } | |||
569 | ||||
570 | static ssize_t gzdWrite(FDSTACK_t fps, const void * buf, size_t count) | |||
571 | { | |||
572 | gzFile gzfile; | |||
573 | ssize_t rc; | |||
574 | ||||
575 | gzfile = fps->fp; | |||
576 | if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */ | |||
577 | ||||
578 | rc = gzwrite(gzfile, (void *)buf, count); | |||
579 | if (rc < 0) | |||
580 | gzdSetError(fps); | |||
581 | return rc; | |||
582 | } | |||
583 | ||||
584 | /* XXX zlib-1.0.4 has not */ | |||
585 | static int gzdSeek(FDSTACK_t fps, off_t pos, int whence) | |||
586 | { | |||
587 | off_t p = pos; | |||
588 | int rc; | |||
589 | #if HAVE_GZSEEK1 | |||
590 | gzFile gzfile = fps->fp; | |||
591 | ||||
592 | if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */ | |||
593 | ||||
594 | rc = gzseek(gzfile, p, whence); | |||
595 | if (rc < 0) | |||
596 | gzdSetError(fps); | |||
597 | #else | |||
598 | rc = -2; | |||
599 | #endif | |||
600 | return rc; | |||
601 | } | |||
602 | ||||
603 | static int gzdClose(FDSTACK_t fps) | |||
604 | { | |||
605 | gzFile gzfile = fps->fp; | |||
606 | int rc; | |||
607 | ||||
608 | if (gzfile == NULL((void*)0)) return -2; /* XXX can't happen */ | |||
609 | ||||
610 | rc = gzclose(gzfile); | |||
611 | ||||
612 | return (rc != 0) ? -1 : 0; | |||
613 | } | |||
614 | ||||
615 | static long gzdTell(FDSTACK_t fps) | |||
616 | { | |||
617 | off_t pos = -1; | |||
618 | gzFile gzfile = fps->fp; | |||
619 | ||||
620 | if (gzfile != NULL((void*)0)) { | |||
621 | #if HAVE_GZSEEK1 | |||
622 | pos = gztell(gzfile); | |||
623 | if (pos < 0) | |||
624 | gzdSetError(fps); | |||
625 | #else | |||
626 | pos = -2; | |||
627 | #endif | |||
628 | } | |||
629 | return pos; | |||
630 | } | |||
631 | static const struct FDIO_s gzdio_s = { | |||
632 | "gzdio", "gzip", | |||
633 | gzdRead, gzdWrite, gzdSeek, gzdClose, | |||
634 | NULL((void*)0), gzdFdopen, gzdFlush, gzdTell, zfdError, zfdStrerr | |||
635 | }; | |||
636 | static const FDIO_t gzdio = &gzdio_s ; | |||
637 | ||||
638 | /* =============================================================== */ | |||
639 | /* Support for BZIP2 library. */ | |||
640 | #if HAVE_BZLIB_H1 | |||
641 | ||||
642 | #include <bzlib.h> | |||
643 | ||||
644 | static FD_t bzdFdopen(FD_t fd, int fdno, const char * fmode) | |||
645 | { | |||
646 | BZFILE *bzfile = BZ2_bzdopen(fdno, fmode); | |||
647 | ||||
648 | if (bzfile == NULL((void*)0)) | |||
649 | return NULL((void*)0); | |||
650 | ||||
651 | fdSetFdno(fd, -1); /* XXX skip the fdio close */ | |||
652 | fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */ | |||
653 | return fd; | |||
654 | } | |||
655 | ||||
656 | static int bzdFlush(FDSTACK_t fps) | |||
657 | { | |||
658 | return BZ2_bzflush(fps->fp); | |||
659 | } | |||
660 | ||||
661 | static ssize_t bzdRead(FDSTACK_t fps, void * buf, size_t count) | |||
662 | { | |||
663 | BZFILE *bzfile = fps->fp; | |||
664 | ssize_t rc = 0; | |||
665 | ||||
666 | if (bzfile) | |||
667 | rc = BZ2_bzread(bzfile, buf, count); | |||
668 | if (rc == -1) { | |||
669 | int zerror = 0; | |||
670 | if (bzfile) { | |||
671 | fps->errcookie = BZ2_bzerror(bzfile, &zerror); | |||
672 | } | |||
673 | } | |||
674 | return rc; | |||
675 | } | |||
676 | ||||
677 | static ssize_t bzdWrite(FDSTACK_t fps, const void * buf, size_t count) | |||
678 | { | |||
679 | BZFILE *bzfile = fps->fp; | |||
680 | ssize_t rc; | |||
681 | ||||
682 | rc = BZ2_bzwrite(bzfile, (void *)buf, count); | |||
683 | if (rc == -1) { | |||
684 | int zerror = 0; | |||
685 | fps->errcookie = BZ2_bzerror(bzfile, &zerror); | |||
686 | } | |||
687 | return rc; | |||
688 | } | |||
689 | ||||
690 | static int bzdClose(FDSTACK_t fps) | |||
691 | { | |||
692 | BZFILE *bzfile = fps->fp; | |||
693 | ||||
694 | if (bzfile == NULL((void*)0)) return -2; | |||
695 | ||||
696 | /* bzclose() doesn't return errors */ | |||
697 | BZ2_bzclose(bzfile); | |||
698 | ||||
699 | return 0; | |||
700 | } | |||
701 | ||||
702 | static const struct FDIO_s bzdio_s = { | |||
703 | "bzdio", "bzip2", | |||
704 | bzdRead, bzdWrite, NULL((void*)0), bzdClose, | |||
705 | NULL((void*)0), bzdFdopen, bzdFlush, NULL((void*)0), zfdError, zfdStrerr | |||
706 | }; | |||
707 | static const FDIO_t bzdio = &bzdio_s ; | |||
708 | ||||
709 | #endif /* HAVE_BZLIB_H */ | |||
710 | ||||
711 | /* =============================================================== */ | |||
712 | /* Support for LZMA library. */ | |||
713 | ||||
714 | #ifdef HAVE_LZMA_H1 | |||
715 | ||||
716 | #include <sys/types.h> | |||
717 | #include <inttypes.h> | |||
718 | #include <lzma.h> | |||
719 | /* Multithreading support in stable API since xz 5.2.0 */ | |||
720 | #if LZMA_VERSION(5 * 10000000U + 2 * 10000U + 3 * 10U + 2) >= 50020002 | |||
721 | #define HAVE_LZMA_MT | |||
722 | #endif | |||
723 | ||||
724 | #define kBufferSize(1 << 15) (1 << 15) | |||
725 | ||||
726 | typedef struct lzfile { | |||
727 | /* IO buffer */ | |||
728 | uint8_t buf[kBufferSize(1 << 15)]; | |||
729 | ||||
730 | lzma_stream strm; | |||
731 | ||||
732 | FILE *file; | |||
733 | ||||
734 | int encoding; | |||
735 | int eof; | |||
736 | ||||
737 | } LZFILE; | |||
738 | ||||
739 | static LZFILE *lzopen_internal(const char *mode, int fd, int xz) | |||
740 | { | |||
741 | int level = LZMA_PRESET_DEFAULT6U; | |||
742 | int encoding = 0; | |||
743 | FILE *fp; | |||
744 | LZFILE *lzfile; | |||
745 | lzma_ret ret; | |||
746 | 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 }; | |||
747 | uint64_t mem_limit = rpmExpandNumeric("%{_xz_memlimit}"); | |||
748 | #ifdef HAVE_LZMA_MT | |||
749 | int threads = 0; | |||
750 | #endif | |||
751 | for (; *mode; mode++) { | |||
752 | if (*mode == 'w') | |||
753 | encoding = 1; | |||
754 | else if (*mode == 'r') | |||
755 | encoding = 0; | |||
756 | else if (*mode >= '0' && *mode <= '9') | |||
757 | level = *mode - '0'; | |||
758 | else if (*mode == 'T') { | |||
759 | if (isdigit(*(mode+1))((*__ctype_b_loc ())[(int) ((*(mode+1)))] & (unsigned short int) _ISdigit)) { | |||
760 | #ifdef HAVE_LZMA_MT | |||
761 | threads = atoi(++mode); | |||
762 | #endif | |||
763 | /* skip past rest of digits in string that atoi() | |||
764 | * should've processed | |||
765 | * */ | |||
766 | while (isdigit(*++mode)((*__ctype_b_loc ())[(int) ((*++mode))] & (unsigned short int) _ISdigit)); | |||
767 | } | |||
768 | #ifdef HAVE_LZMA_MT | |||
769 | else | |||
770 | threads = -1; | |||
771 | #endif | |||
772 | } | |||
773 | } | |||
774 | fp = fdopen(fd, encoding ? "w" : "r"); | |||
775 | if (!fp) | |||
776 | return NULL((void*)0); | |||
777 | lzfile = calloc(1, sizeof(*lzfile)); | |||
778 | lzfile->file = fp; | |||
779 | lzfile->encoding = encoding; | |||
780 | lzfile->eof = 0; | |||
781 | lzfile->strm = init_strm; | |||
782 | if (encoding) { | |||
783 | if (xz) { | |||
784 | #ifdef HAVE_LZMA_MT | |||
785 | if (!threads) { | |||
786 | #endif | |||
787 | ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256); | |||
788 | #ifdef HAVE_LZMA_MT | |||
789 | } else { | |||
790 | if (threads == -1) | |||
791 | threads = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN); | |||
792 | lzma_mt mt_options = { | |||
793 | .flags = 0, | |||
794 | .threads = threads, | |||
795 | .block_size = 0, | |||
796 | .timeout = 0, | |||
797 | .preset = level, | |||
798 | .filters = NULL((void*)0), | |||
799 | .check = LZMA_CHECK_SHA256 }; | |||
800 | ||||
801 | #if __WORDSIZE64 == 32 | |||
802 | /* In 32 bit environment, required memory easily exceeds memory address | |||
803 | * space limit if compressing using multiple threads. | |||
804 | * By setting a memory limit, liblzma will automatically adjust number | |||
805 | * of threads to avoid exceeding memory. | |||
806 | */ | |||
807 | if (threads > 1) { | |||
808 | struct utsname u; | |||
809 | uint32_t memlimit = (SIZE_MAX(18446744073709551615UL)>>1) + (SIZE_MAX(18446744073709551615UL)>>3); | |||
810 | uint64_t memory_usage; | |||
811 | /* While a 32 bit linux kernel will have an address limit of 3GiB | |||
812 | * for processes (which is why set the memory limit to 2.5GiB as a safety | |||
813 | * margin), 64 bit kernels will have a limit of 4GiB for 32 bit binaries. | |||
814 | * Therefore the memory limit should be higher if running on a 64 bit | |||
815 | * kernel, so we increase it to 3,5GiB. | |||
816 | */ | |||
817 | uname(&u); | |||
818 | if (strstr(u.machine, "64") || strstr(u.machine, "s390x") | |||
819 | #if defined(__linux__1) | |||
820 | || ((personality(0xffffffff) & PER_MASK) == PER_LINUX32) | |||
821 | #endif | |||
822 | ) | |||
823 | memlimit += (SIZE_MAX(18446744073709551615UL)>>2); | |||
824 | ||||
825 | /* keep reducing the number of threads until memory usage gets below limit */ | |||
826 | while ((memory_usage = lzma_stream_encoder_mt_memusage(&mt_options)) > memlimit) { | |||
827 | /* number of threads shouldn't be able to hit zero with compression | |||
828 | * settings aailable to set through rpm... */ | |||
829 | assert(--mt_options.threads != 0)({ if (--mt_options.threads != 0) ; else __assert_fail ("--mt_options.threads != 0" , "rpmio.c", 829, __PRETTY_FUNCTION__); }); | |||
830 | } | |||
831 | lzma_memlimit_set(&lzfile->strm, memlimit); | |||
832 | ||||
833 | if (threads != (int)mt_options.threads) | |||
834 | rpmlog(RPMLOG_NOTICE, | |||
835 | "XZ: Adjusted the number of threads from %d to %d to not exceed the memory usage limit of %lu bytes", | |||
836 | threads, mt_options.threads, memlimit); | |||
837 | } | |||
838 | #endif | |||
839 | ||||
840 | ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options); | |||
841 | } | |||
842 | #endif | |||
843 | } else { | |||
844 | lzma_options_lzma options; | |||
845 | lzma_lzma_preset(&options, level); | |||
846 | ret = lzma_alone_encoder(&lzfile->strm, &options); | |||
847 | } | |||
848 | } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */ | |||
849 | ret = lzma_auto_decoder(&lzfile->strm, mem_limit ? mem_limit : 100<<20, 0); | |||
850 | } | |||
851 | if (ret != LZMA_OK) { | |||
852 | switch (ret) { | |||
853 | case LZMA_MEM_ERROR: | |||
854 | rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed"); | |||
855 | break; | |||
856 | ||||
857 | case LZMA_DATA_ERROR: | |||
858 | rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded"); | |||
859 | break; | |||
860 | ||||
861 | default: | |||
862 | rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret); | |||
863 | break; | |||
864 | } | |||
865 | fclose(fp); | |||
866 | free(lzfile); | |||
867 | return NULL((void*)0); | |||
868 | } | |||
869 | return lzfile; | |||
870 | } | |||
871 | ||||
872 | static int lzclose(LZFILE *lzfile) | |||
873 | { | |||
874 | lzma_ret ret; | |||
875 | size_t n; | |||
876 | int rc; | |||
877 | ||||
878 | if (!lzfile) | |||
879 | return -1; | |||
880 | if (lzfile->encoding) { | |||
881 | for (;;) { | |||
882 | lzfile->strm.avail_out = kBufferSize(1 << 15); | |||
883 | lzfile->strm.next_out = lzfile->buf; | |||
884 | ret = lzma_code(&lzfile->strm, LZMA_FINISH); | |||
885 | if (ret != LZMA_OK && ret != LZMA_STREAM_END) | |||
886 | return -1; | |||
887 | n = kBufferSize(1 << 15) - lzfile->strm.avail_out; | |||
888 | if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n) | |||
889 | return -1; | |||
890 | if (ret == LZMA_STREAM_END) | |||
891 | break; | |||
892 | } | |||
893 | } | |||
894 | lzma_end(&lzfile->strm); | |||
895 | rc = fclose(lzfile->file); | |||
896 | free(lzfile); | |||
897 | return rc; | |||
898 | } | |||
899 | ||||
900 | static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len) | |||
901 | { | |||
902 | lzma_ret ret; | |||
903 | int eof = 0; | |||
904 | ||||
905 | if (!lzfile || lzfile->encoding) | |||
906 | return -1; | |||
907 | if (lzfile->eof) | |||
908 | return 0; | |||
909 | lzfile->strm.next_out = buf; | |||
910 | lzfile->strm.avail_out = len; | |||
911 | for (;;) { | |||
912 | if (!lzfile->strm.avail_in) { | |||
913 | lzfile->strm.next_in = lzfile->buf; | |||
914 | lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize(1 << 15), lzfile->file); | |||
915 | if (!lzfile->strm.avail_in) | |||
916 | eof = 1; | |||
917 | } | |||
918 | ret = lzma_code(&lzfile->strm, LZMA_RUN); | |||
919 | if (ret == LZMA_STREAM_END) { | |||
920 | lzfile->eof = 1; | |||
921 | return len - lzfile->strm.avail_out; | |||
922 | } | |||
923 | if (ret != LZMA_OK) | |||
924 | return -1; | |||
925 | if (!lzfile->strm.avail_out) | |||
926 | return len; | |||
927 | if (eof) | |||
928 | return -1; | |||
929 | } | |||
930 | } | |||
931 | ||||
932 | static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len) | |||
933 | { | |||
934 | lzma_ret ret; | |||
935 | size_t n; | |||
936 | if (!lzfile || !lzfile->encoding) | |||
937 | return -1; | |||
938 | if (!len) | |||
939 | return 0; | |||
940 | lzfile->strm.next_in = buf; | |||
941 | lzfile->strm.avail_in = len; | |||
942 | for (;;) { | |||
943 | lzfile->strm.next_out = lzfile->buf; | |||
944 | lzfile->strm.avail_out = kBufferSize(1 << 15); | |||
945 | ret = lzma_code(&lzfile->strm, LZMA_RUN); | |||
946 | if (ret != LZMA_OK) | |||
947 | return -1; | |||
948 | n = kBufferSize(1 << 15) - lzfile->strm.avail_out; | |||
949 | if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n) | |||
950 | return -1; | |||
951 | if (!lzfile->strm.avail_in) | |||
952 | return len; | |||
953 | } | |||
954 | } | |||
955 | ||||
956 | static FD_t xzdFdopen(FD_t fd, int fdno, const char * fmode) | |||
957 | { | |||
958 | LZFILE *lzfile = lzopen_internal(fmode, fdno, 1); | |||
959 | ||||
960 | if (lzfile == NULL((void*)0)) | |||
961 | return NULL((void*)0); | |||
962 | ||||
963 | fdSetFdno(fd, -1); /* XXX skip the fdio close */ | |||
964 | fdPush(fd, xzdio, lzfile, fdno); | |||
965 | return fd; | |||
966 | } | |||
967 | ||||
968 | static FD_t lzdFdopen(FD_t fd, int fdno, const char * fmode) | |||
969 | { | |||
970 | LZFILE *lzfile = lzopen_internal(fmode, fdno, 0); | |||
971 | ||||
972 | if (lzfile == NULL((void*)0)) | |||
973 | return NULL((void*)0); | |||
974 | ||||
975 | fdSetFdno(fd, -1); /* XXX skip the fdio close */ | |||
976 | fdPush(fd, lzdio, lzfile, fdno); | |||
977 | return fd; | |||
978 | } | |||
979 | ||||
980 | static int lzdFlush(FDSTACK_t fps) | |||
981 | { | |||
982 | LZFILE *lzfile = fps->fp; | |||
983 | return fflush(lzfile->file); | |||
984 | } | |||
985 | ||||
986 | static ssize_t lzdRead(FDSTACK_t fps, void * buf, size_t count) | |||
987 | { | |||
988 | LZFILE *lzfile = fps->fp; | |||
989 | ssize_t rc = 0; | |||
990 | ||||
991 | if (lzfile) | |||
992 | rc = lzread(lzfile, buf, count); | |||
993 | if (rc == -1) { | |||
994 | fps->errcookie = "Lzma: decoding error"; | |||
995 | } | |||
996 | return rc; | |||
997 | } | |||
998 | ||||
999 | static ssize_t lzdWrite(FDSTACK_t fps, const void * buf, size_t count) | |||
1000 | { | |||
1001 | LZFILE *lzfile = fps->fp; | |||
1002 | ssize_t rc = 0; | |||
1003 | ||||
1004 | rc = lzwrite(lzfile, (void *)buf, count); | |||
1005 | if (rc < 0) { | |||
1006 | fps->errcookie = "Lzma: encoding error"; | |||
1007 | } | |||
1008 | return rc; | |||
1009 | } | |||
1010 | ||||
1011 | static int lzdClose(FDSTACK_t fps) | |||
1012 | { | |||
1013 | LZFILE *lzfile = fps->fp; | |||
1014 | int rc; | |||
1015 | ||||
1016 | if (lzfile == NULL((void*)0)) return -2; | |||
1017 | rc = lzclose(lzfile); | |||
1018 | ||||
1019 | return rc; | |||
1020 | } | |||
1021 | ||||
1022 | static struct FDIO_s xzdio_s = { | |||
1023 | "xzdio", "xz", | |||
1024 | lzdRead, lzdWrite, NULL((void*)0), lzdClose, | |||
1025 | NULL((void*)0), xzdFdopen, lzdFlush, NULL((void*)0), zfdError, zfdStrerr | |||
1026 | }; | |||
1027 | static const FDIO_t xzdio = &xzdio_s; | |||
1028 | ||||
1029 | static struct FDIO_s lzdio_s = { | |||
1030 | "lzdio", "lzma", | |||
1031 | lzdRead, lzdWrite, NULL((void*)0), lzdClose, | |||
1032 | NULL((void*)0), lzdFdopen, lzdFlush, NULL((void*)0), zfdError, zfdStrerr | |||
1033 | }; | |||
1034 | static const FDIO_t lzdio = &lzdio_s; | |||
1035 | ||||
1036 | #endif /* HAVE_LZMA_H */ | |||
1037 | ||||
1038 | /* =============================================================== */ | |||
1039 | ||||
1040 | #define FDIOVEC(_fps, _vec)((_fps) && (_fps)->io) ? (_fps)->io->_vec : ( (void*)0) \ | |||
1041 | ((_fps) && (_fps)->io) ? (_fps)->io->_vec : NULL((void*)0) | |||
1042 | ||||
1043 | const char *Fstrerror(FD_t fd) | |||
1044 | { | |||
1045 | const char *err = ""; | |||
1046 | ||||
1047 | if (fd != NULL((void*)0)) { | |||
1048 | FDSTACK_t fps = fdGetFps(fd); | |||
1049 | fdio_fstrerr_function_t _fstrerr = FDIOVEC(fps, _fstrerr)((fps) && (fps)->io) ? (fps)->io->_fstrerr : ((void*)0); | |||
1050 | if (_fstrerr) | |||
1051 | err = _fstrerr(fps); | |||
1052 | } else if (errno(*__errno_location ())){ | |||
1053 | err = strerror(errno(*__errno_location ())); | |||
1054 | } | |||
1055 | return err; | |||
1056 | } | |||
1057 | ||||
1058 | ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd) | |||
1059 | { | |||
1060 | ssize_t rc = -1; | |||
1061 | ||||
1062 | if (fd != NULL((void*)0)) { | |||
1063 | FDSTACK_t fps = fdGetFps(fd); | |||
1064 | fdio_read_function_t _read = FDIOVEC(fps, read)((fps) && (fps)->io) ? (fps)->io->read : ((void *)0); | |||
1065 | ||||
1066 | fdstat_enter(fd, FDSTAT_READ); | |||
1067 | do { | |||
1068 | rc = (_read ? (*_read) (fps, buf, size * nmemb) : -2); | |||
1069 | } while (rc == -1 && errno(*__errno_location ()) == EINTR4); | |||
1070 | fdstat_exit(fd, FDSTAT_READ, rc); | |||
1071 | ||||
1072 | if (fd->digests && rc > 0) | |||
1073 | fdUpdateDigests(fd, buf, rc); | |||
1074 | } | |||
1075 | ||||
1076 | 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)) | |||
1077 | 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)); | |||
1078 | ||||
1079 | return rc; | |||
1080 | } | |||
1081 | ||||
1082 | ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd) | |||
1083 | { | |||
1084 | ssize_t rc = -1; | |||
1085 | ||||
1086 | if (fd != NULL((void*)0)) { | |||
1087 | FDSTACK_t fps = fdGetFps(fd); | |||
1088 | fdio_write_function_t _write = FDIOVEC(fps, write)((fps) && (fps)->io) ? (fps)->io->write : (( void*)0); | |||
1089 | ||||
1090 | fdstat_enter(fd, FDSTAT_WRITE); | |||
1091 | do { | |||
1092 | rc = (_write ? _write(fps, buf, size * nmemb) : -2); | |||
1093 | } while (rc == -1 && errno(*__errno_location ()) == EINTR4); | |||
1094 | fdstat_exit(fd, FDSTAT_WRITE, rc); | |||
1095 | ||||
1096 | if (fd->digests && rc > 0) | |||
1097 | fdUpdateDigests(fd, buf, rc); | |||
1098 | } | |||
1099 | ||||
1100 | 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)) | |||
1101 | 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)); | |||
1102 | ||||
1103 | return rc; | |||
1104 | } | |||
1105 | ||||
1106 | int Fseek(FD_t fd, off_t offset, int whence) | |||
1107 | { | |||
1108 | int rc = -1; | |||
1109 | ||||
1110 | if (fd != NULL((void*)0)) { | |||
1111 | FDSTACK_t fps = fdGetFps(fd); | |||
1112 | fdio_seek_function_t _seek = FDIOVEC(fps, seek)((fps) && (fps)->io) ? (fps)->io->seek : ((void *)0); | |||
1113 | ||||
1114 | fdstat_enter(fd, FDSTAT_SEEK); | |||
1115 | rc = (_seek ? _seek(fps, offset, whence) : -2); | |||
1116 | fdstat_exit(fd, FDSTAT_SEEK, rc); | |||
1117 | } | |||
1118 | ||||
1119 | 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)) | |||
1120 | 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)); | |||
1121 | ||||
1122 | return rc; | |||
1123 | } | |||
1124 | ||||
1125 | int Fclose(FD_t fd) | |||
1126 | { | |||
1127 | int rc = 0, ec = 0; | |||
1128 | ||||
1129 | if (fd == NULL((void*)0)) | |||
1130 | return -1; | |||
1131 | ||||
1132 | fd = fdLink(fd); | |||
1133 | fdstat_enter(fd, FDSTAT_CLOSE); | |||
1134 | for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fdPop(fd)) { | |||
1135 | if (fps->fdno >= 0) { | |||
1136 | fdio_close_function_t _close = FDIOVEC(fps, close)((fps) && (fps)->io) ? (fps)->io->close : (( void*)0); | |||
1137 | rc = _close ? _close(fps) : -2; | |||
1138 | ||||
1139 | if (ec == 0 && rc) | |||
1140 | ec = rc; | |||
1141 | } | |||
1142 | ||||
1143 | /* Debugging stats for compresed types */ | |||
1144 | if ((_rpmio_debug || rpmIsDebug()(rpmlogSetMask(0) >= (1 << ((unsigned)(RPMLOG_DEBUG) )))) && fps->fdno == -1) | |||
1145 | fdstat_print(fd, fps->io->ioname, stderrstderr); | |||
1146 | ||||
1147 | /* Leave freeing the last one after stats */ | |||
1148 | if (fps->prev == NULL((void*)0)) | |||
1149 | break; | |||
1150 | } | |||
1151 | fdstat_exit(fd, FDSTAT_CLOSE, rc); | |||
1152 | 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)) | |||
1153 | (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)); | |||
1154 | fdPop(fd); | |||
1155 | ||||
1156 | fdFree(fd); | |||
1157 | return ec; | |||
1158 | } | |||
1159 | ||||
1160 | /** | |||
1161 | * Convert stdio fmode to open(2) mode, filtering out zlib/bzlib flags. | |||
1162 | * returns stdio[0] = NUL on error. | |||
1163 | * | |||
1164 | * - gzopen: [0-9] is compression level | |||
1165 | * - gzopen: 'f' is filtered (Z_FILTERED) | |||
1166 | * - gzopen: 'h' is Huffman encoding (Z_HUFFMAN_ONLY) | |||
1167 | * - bzopen: [1-9] is block size (modulo 100K) | |||
1168 | * - bzopen: 's' is smallmode | |||
1169 | * - HACK: '.' terminates, rest is type of I/O | |||
1170 | */ | |||
1171 | static void cvtfmode (const char *m, | |||
1172 | char *stdio, size_t nstdio, | |||
1173 | char *other, size_t nother, | |||
1174 | const char **end, int * f) | |||
1175 | { | |||
1176 | int flags = 0; | |||
1177 | char c; | |||
1178 | ||||
1179 | switch (*m) { | |||
1180 | case 'a': | |||
1181 | flags |= O_WRONLY01 | O_CREAT0100 | O_APPEND02000; | |||
1182 | if (--nstdio > 0) *stdio++ = *m; | |||
1183 | break; | |||
1184 | case 'w': | |||
1185 | flags |= O_WRONLY01 | O_CREAT0100 | O_TRUNC01000; | |||
1186 | if (--nstdio > 0) *stdio++ = *m; | |||
1187 | break; | |||
1188 | case 'r': | |||
1189 | flags |= O_RDONLY00; | |||
1190 | if (--nstdio > 0) *stdio++ = *m; | |||
1191 | break; | |||
1192 | default: | |||
1193 | *stdio = '\0'; | |||
1194 | return; | |||
1195 | break; | |||
1196 | } | |||
1197 | m++; | |||
1198 | ||||
1199 | while ((c = *m++) != '\0') { | |||
1200 | switch (c) { | |||
1201 | case '.': | |||
1202 | break; | |||
1203 | case '+': | |||
1204 | flags &= ~(O_RDONLY00|O_WRONLY01); | |||
1205 | flags |= O_RDWR02; | |||
1206 | if (--nstdio > 0) *stdio++ = c; | |||
1207 | continue; | |||
1208 | break; | |||
1209 | case 'b': | |||
1210 | if (--nstdio > 0) *stdio++ = c; | |||
1211 | continue; | |||
1212 | break; | |||
1213 | case 'x': | |||
1214 | flags |= O_EXCL0200; | |||
1215 | if (--nstdio > 0) *stdio++ = c; | |||
1216 | continue; | |||
1217 | break; | |||
1218 | default: | |||
1219 | if (--nother > 0) *other++ = c; | |||
1220 | continue; | |||
1221 | break; | |||
1222 | } | |||
1223 | break; | |||
1224 | } | |||
1225 | ||||
1226 | *stdio = *other = '\0'; | |||
1227 | if (end != NULL((void*)0)) | |||
1228 | *end = (*m != '\0' ? m : NULL((void*)0)); | |||
1229 | if (f != NULL((void*)0)) | |||
1230 | *f = flags; | |||
1231 | } | |||
1232 | ||||
1233 | static FDIO_t findIOT(const char *name) | |||
1234 | { | |||
1235 | static FDIO_t fdio_types[] = { | |||
1236 | &fdio_s, | |||
1237 | &ufdio_s, | |||
1238 | &gzdio_s, | |||
1239 | #if HAVE_BZLIB_H1 | |||
1240 | &bzdio_s, | |||
1241 | #endif | |||
1242 | #if HAVE_LZMA_H1 | |||
1243 | &xzdio_s, | |||
1244 | &lzdio_s, | |||
1245 | #endif | |||
1246 | NULL((void*)0) | |||
1247 | }; | |||
1248 | FDIO_t iot = NULL((void*)0); | |||
1249 | ||||
1250 | for (FDIO_t *t = fdio_types; t && *t; t++) { | |||
1251 | if (rstreq(name, (*t)->ioname) || | |||
1252 | ((*t)->name && rstreq(name, (*t)->name))) { | |||
1253 | iot = (*t); | |||
1254 | break; | |||
1255 | } | |||
1256 | } | |||
1257 | ||||
1258 | return iot; | |||
1259 | } | |||
1260 | ||||
1261 | FD_t Fdopen(FD_t ofd, const char *fmode) | |||
1262 | { | |||
1263 | char stdio[20], other[20], zstdio[40]; | |||
1264 | const char *end = NULL((void*)0); | |||
1265 | FDIO_t iot = NULL((void*)0); | |||
1266 | FD_t fd = ofd; | |||
1267 | int fdno = Fileno(ofd); | |||
1268 | ||||
1269 | if (_rpmio_debug) | |||
1270 | fprintf(stderrstderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd)); | |||
1271 | ||||
1272 | if (fd == NULL((void*)0) || fmode == NULL((void*)0) || fdno < 0) | |||
1273 | return NULL((void*)0); | |||
1274 | ||||
1275 | cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL((void*)0)); | |||
1276 | if (stdio[0] == '\0') | |||
1277 | return NULL((void*)0); | |||
1278 | zstdio[0] = '\0'; | |||
1279 | strncat(zstdio, stdio, sizeof(zstdio) - strlen(zstdio) - 1); | |||
1280 | strncat(zstdio, other, sizeof(zstdio) - strlen(zstdio) - 1); | |||
1281 | ||||
1282 | if (end == NULL((void*)0) && other[0] == '\0') | |||
1283 | return fd; | |||
1284 | ||||
1285 | if (end && *end) { | |||
1286 | iot = findIOT(end); | |||
1287 | } else if (other[0] != '\0') { | |||
1288 | for (end = other; *end && strchr("0123456789fh", *end); end++) | |||
1289 | {}; | |||
1290 | if (*end == '\0') | |||
1291 | iot = findIOT("gzdio"); | |||
1292 | } | |||
1293 | ||||
1294 | if (iot && iot->_fdopen) | |||
1295 | fd = iot->_fdopen(fd, fdno, zstdio); | |||
1296 | ||||
1297 | 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)); | |||
1298 | return fd; | |||
1299 | } | |||
1300 | ||||
1301 | FD_t Fopen(const char *path, const char *fmode) | |||
1302 | { | |||
1303 | char stdio[20], other[20]; | |||
1304 | const char *end = NULL((void*)0); | |||
1305 | mode_t perms = 0666; | |||
1306 | int flags = 0; | |||
1307 | FD_t fd = NULL((void*)0); | |||
1308 | ||||
1309 | if (path == NULL((void*)0) || fmode == NULL((void*)0)) | |||
1310 | return NULL((void*)0); | |||
1311 | ||||
1312 | stdio[0] = '\0'; | |||
1313 | cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, &flags); | |||
1314 | if (stdio[0] == '\0') | |||
1315 | return NULL((void*)0); | |||
1316 | ||||
1317 | if (end == NULL((void*)0) || rstreq(end, "fdio")) { | |||
1318 | if (_rpmio_debug) | |||
1319 | fprintf(stderrstderr, "*** Fopen fdio path %s fmode %s\n", path, fmode); | |||
1320 | fd = fdOpen(path, flags, perms); | |||
1321 | } else { | |||
1322 | if (_rpmio_debug) | |||
1323 | fprintf(stderrstderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode); | |||
1324 | fd = ufdOpen(path, flags, perms); | |||
1325 | } | |||
1326 | ||||
1327 | /* Open compressed stream if necessary */ | |||
1328 | if (fd) | |||
1329 | fd = Fdopen(fd, fmode); | |||
1330 | ||||
1331 | 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)) | |||
1332 | 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)); | |||
1333 | ||||
1334 | return fd; | |||
1335 | } | |||
1336 | ||||
1337 | int Fflush(FD_t fd) | |||
1338 | { | |||
1339 | int rc = -1; | |||
1340 | if (fd != NULL((void*)0)) { | |||
1341 | FDSTACK_t fps = fdGetFps(fd); | |||
1342 | fdio_fflush_function_t _fflush = FDIOVEC(fps, _fflush)((fps) && (fps)->io) ? (fps)->io->_fflush : ( (void*)0); | |||
1343 | ||||
1344 | rc = (_fflush ? _fflush(fps) : -2); | |||
1345 | } | |||
1346 | return rc; | |||
1347 | } | |||
1348 | ||||
1349 | off_t Ftell(FD_t fd) | |||
1350 | { | |||
1351 | off_t pos = -1; | |||
1352 | if (fd != NULL((void*)0)) { | |||
1353 | FDSTACK_t fps = fdGetFps(fd); | |||
1354 | fdio_ftell_function_t _ftell = FDIOVEC(fps, _ftell)((fps) && (fps)->io) ? (fps)->io->_ftell : ( (void*)0); | |||
1355 | ||||
1356 | pos = (_ftell ? _ftell(fps) : -2); | |||
1357 | } | |||
1358 | return pos; | |||
1359 | } | |||
1360 | ||||
1361 | int Ferror(FD_t fd) | |||
1362 | { | |||
1363 | int rc = 0; | |||
1364 | ||||
1365 | if (fd == NULL((void*)0)) return -1; | |||
1366 | for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) { | |||
1367 | fdio_ferror_function_t _ferror = FDIOVEC(fps, _ferror)((fps) && (fps)->io) ? (fps)->io->_ferror : ( (void*)0); | |||
1368 | rc = _ferror(fps); | |||
1369 | ||||
1370 | if (rc) | |||
1371 | break; | |||
1372 | } | |||
1373 | 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)); | |||
1374 | return rc; | |||
1375 | } | |||
1376 | ||||
1377 | int Fileno(FD_t fd) | |||
1378 | { | |||
1379 | int rc = -1; | |||
1380 | ||||
1381 | if (fd == NULL((void*)0)) return -1; | |||
1382 | for (FDSTACK_t fps = fd->fps; fps != NULL((void*)0); fps = fps->prev) { | |||
1383 | rc = fps->fdno; | |||
1384 | if (rc != -1) | |||
1385 | break; | |||
1386 | } | |||
1387 | ||||
1388 | 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)); | |||
1389 | return rc; | |||
1390 | } | |||
1391 | ||||
1392 | /* XXX this is naive */ | |||
1393 | int Fcntl(FD_t fd, int op, void *lip) | |||
1394 | { | |||
1395 | return fcntl(Fileno(fd), op, lip); | |||
1396 | } | |||
1397 | ||||
1398 | rpmop fdOp(FD_t fd, fdOpX opx) | |||
1399 | { | |||
1400 | rpmop op = NULL((void*)0); | |||
1401 | ||||
1402 | if (fd != NULL((void*)0) && fd->stats != NULL((void*)0) && opx >= 0 && opx < FDSTAT_MAX) | |||
1403 | op = fd->stats->ops + opx; | |||
1404 | return op; | |||
1405 | } | |||
1406 | ||||
1407 | int rpmioSlurp(const char * fn, uint8_t ** bp, ssize_t * blenp) | |||
1408 | { | |||
1409 | static const ssize_t blenmax = (32 * BUFSIZ8192); | |||
1410 | ssize_t blen = 0; | |||
1411 | uint8_t * b = NULL((void*)0); | |||
1412 | ssize_t size; | |||
1413 | FD_t fd; | |||
1414 | int rc = 0; | |||
1415 | ||||
1416 | fd = Fopen(fn, "r.ufdio"); | |||
1417 | if (fd == NULL((void*)0) || Ferror(fd)) { | |||
| ||||
1418 | rc = 2; | |||
1419 | goto exit; | |||
1420 | } | |||
1421 | ||||
1422 | size = fdSize(fd); | |||
1423 | blen = (size >= 0 ? size : blenmax); | |||
1424 | if (blen) { | |||
1425 | int nb; | |||
1426 | b = xmalloc(blen+1)rmalloc((blen+1)); | |||
1427 | b[0] = '\0'; | |||
1428 | nb = Fread(b, sizeof(*b), blen, fd); | |||
1429 | if (Ferror(fd) || (size > 0 && nb != blen)) { | |||
1430 | rc = 1; | |||
1431 | goto exit; | |||
1432 | } | |||
1433 | if (blen == blenmax && nb < blen) { | |||
1434 | blen = nb; | |||
1435 | b = xrealloc(b, blen+1)rrealloc((b), (blen+1)); | |||
1436 | } | |||
1437 | b[blen] = '\0'; | |||
1438 | } | |||
1439 | ||||
1440 | exit: | |||
1441 | if (fd) (void) Fclose(fd); | |||
1442 | ||||
1443 | if (rc) { | |||
1444 | if (b) free(b); | |||
1445 | b = NULL((void*)0); | |||
1446 | blen = 0; | |||
1447 | } | |||
1448 | ||||
1449 | if (bp) *bp = b; | |||
1450 | else if (b) free(b); | |||
1451 | ||||
1452 | if (blenp) *blenp = blen; | |||
1453 | ||||
1454 | return rc; | |||
1455 | } | |||
1456 | ||||
1457 | void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags) | |||
1458 | { | |||
1459 | return fdInitDigestID(fd, hashalgo, hashalgo, flags); | |||
1460 | } | |||
1461 | ||||
1462 | void fdInitDigestID(FD_t fd, int hashalgo, int id, rpmDigestFlags flags) | |||
1463 | { | |||
1464 | if (fd->digests == NULL((void*)0)) { | |||
1465 | fd->digests = rpmDigestBundleNew(); | |||
1466 | } | |||
1467 | fdstat_enter(fd, FDSTAT_DIGEST); | |||
1468 | rpmDigestBundleAddID(fd->digests, hashalgo, id, flags); | |||
1469 | fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0); | |||
1470 | } | |||
1471 | ||||
1472 | static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen) | |||
1473 | { | |||
1474 | if (fd && fd->digests) { | |||
1475 | fdstat_enter(fd, FDSTAT_DIGEST); | |||
1476 | rpmDigestBundleUpdate(fd->digests, buf, buflen); | |||
1477 | fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen); | |||
1478 | } | |||
1479 | } | |||
1480 | ||||
1481 | void fdFiniDigest(FD_t fd, int id, | |||
1482 | void ** datap, size_t * lenp, int asAscii) | |||
1483 | { | |||
1484 | if (fd && fd->digests) { | |||
1485 | fdstat_enter(fd, FDSTAT_DIGEST); | |||
1486 | rpmDigestBundleFinal(fd->digests, id, datap, lenp, asAscii); | |||
1487 | fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0); | |||
1488 | } | |||
1489 | } | |||
1490 | ||||
1491 | DIGEST_CTX fdDupDigest(FD_t fd, int id) | |||
1492 | { | |||
1493 | DIGEST_CTX ctx = NULL((void*)0); | |||
1494 | ||||
1495 | if (fd && fd->digests) | |||
1496 | ctx = rpmDigestBundleDupCtx(fd->digests, id); | |||
1497 | ||||
1498 | return ctx; | |||
1499 | } |