rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

gzdio.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #if defined(NOTYET) || defined(__LCLINT__)
9 #include <stdbool.h>
10 #else
11 typedef enum { true = 1, false = 0 } bool;
12 #endif
13
14 #include "rpmio_internal.h"
15 #include <rpmmacro.h>
16 #include <rpmcb.h>
17
18 #if defined(WITH_ZLIB)
19
20 /*@-noparams@*/
21 #include <zlib.h>
22 /*@=noparams@*/
23
24 #include "debug.h"
25
26 /*@access FD_t @*/
27
28 #define GZDONLY(fd) assert(fdGetIo(fd) == gzdio)
29
30 typedef struct cpio_state_s {
31 rpmuint32_t n; /* byte progress in cpio header */
32 rpmuint32_t mode; /* file attributes */
33 rpmuint32_t nlnk;
34 rpmuint32_t size;
35 } * cpio_state;
36
37 #define RSYNC_WIN 4096
38
39 typedef struct rsync_state_s {
40 rpmuint32_t n; /* number of elements in the window */
41 rpmuint32_t sum; /* current sum */
42 unsigned char win[RSYNC_WIN]; /* window elements */
43 } * rsync_state;
44
45 typedef struct rpmGZFILE_s {
46 gzFile gz; /* gzFile is a pointer */
47 struct rsync_state_s rs;
48 struct cpio_state_s cs;
49 rpmuint32_t nb; /* bytes pending for sync */
50 } * rpmGZFILE; /* like FILE, to use with star */
51
52 /* Should gzflush be called only after RSYNC_WIN boundaries? */
53 /*@unchecked@*/
54 static int enable_rsync = 1;
55
56 /* =============================================================== */
57 /* from ../lib/cpio.h */
58 #define CPIO_NEWC_MAGIC "070701"
59 #define PHYS_HDR_SIZE 110
60
61 #define OFFSET_MODE (sizeof(CPIO_NEWC_MAGIC)-1 + 1*8)
62 #define OFFSET_NLNK (sizeof(CPIO_NEWC_MAGIC)-1 + 4*8)
63 #define OFFSET_SIZE (sizeof(CPIO_NEWC_MAGIC)-1 + 6*8)
64
65 static inline
66 int hex(char c)
67 /*@*/
68 {
69 if (c >= '0' && c <= '9')
70 return (int)(c - '0');
71 else if (c >= 'a' && c <= 'f')
72 return (int)(c - 'a') + 10;
73 else if (c >= 'A' && c <= 'F')
74 return (int)(c - 'A') + 10;
75 return -1;
76 }
77
78 static inline
79 bool cpio_next(cpio_state s, unsigned char c)
80 /*@modifies s @*/
81 {
82 if (s->n >= sizeof(CPIO_NEWC_MAGIC)-1) {
83 int d = hex(c);
84 if (d < 0) {
85 s->n = 0;
86 return false;
87 }
88 if (0){} /* indent */
89 else if (s->n >= OFFSET_MODE && s->n < OFFSET_MODE+8) {
90 if (s->n == OFFSET_MODE)
91 s->mode = 0;
92 else
93 s->mode <<= 4;
94 s->mode |= d;
95 }
96 else if (s->n >= OFFSET_NLNK && s->n < OFFSET_NLNK+8) {
97 if (s->n == OFFSET_NLNK)
98 s->nlnk = 0;
99 else
100 s->nlnk <<= 4;
101 s->nlnk |= d;
102 }
103 else if (s->n >= OFFSET_SIZE && s->n < OFFSET_SIZE+8) {
104 if (s->n == OFFSET_SIZE)
105 s->size = 0;
106 else
107 s->size <<= 4;
108 s->size |= d;
109 }
110 s->n++;
111 if (s->n >= PHYS_HDR_SIZE) {
112 s->n = 0;
113 if (!S_ISREG(s->mode) || s->nlnk != 1)
114 /* no file data */
115 s->size = 0;
116 return true;
117 }
118 }
119 else if (CPIO_NEWC_MAGIC[s->n] == c) {
120 s->n++;
121 }
122 else {
123 s->n = 0;
124 }
125 return false;
126 }
127
128 /* =============================================================== */
129 static inline
130 bool rsync_next(rsync_state s, unsigned char c)
131 /*@modifies s @*/
132 {
133 rpmuint32_t i;
134
135 if (s->n < RSYNC_WIN) { /* not enough elements */
136 s->sum += (rpmuint32_t)c; /* update the sum */
137 s->win[s->n++] = c; /* remember the element */
138 return false; /* no match */
139 }
140 i = s->n++ % RSYNC_WIN; /* wrap up */
141 s->sum -= (rpmuint32_t)s->win[i]; /* move the window on */
142 s->sum += (rpmuint32_t)c;
143 s->win[i] = c;
144 if (s->sum % RSYNC_WIN == 0) { /* match */
145 s->n = 0; /* reset */
146 s->sum = 0;
147 return true;
148 }
149 return false;
150 }
151
152 #define CHUNK 4096
153
154 static inline
155 bool sync_hint(rpmGZFILE rpmgz, unsigned char c)
156 /*@modifies rpmgz @*/
157 {
158 bool cpio_hint;
159 bool rsync_hint;
160
161 rpmgz->nb++;
162 cpio_hint = cpio_next(&rpmgz->cs, c);
163 if (cpio_hint) {
164 /* cpio header/data boundary */
165 rpmgz->rs.n = rpmgz->rs.sum = 0;
166 if (rpmgz->nb >= 2*CHUNK)
167 /* better sync here */
168 goto cpio_sync;
169 if (rpmgz->cs.size < CHUNK)
170 /* file is too small */
171 return false;
172 if (rpmgz->nb < CHUNK/2)
173 /* not enough pending bytes */
174 return false;
175 cpio_sync:
176 rpmgz->nb = 0;
177 return true;
178 }
179 rsync_hint = rsync_next(&rpmgz->rs, c);
180 if (rsync_hint) {
181 /* rolling checksum match */
182 assert(rpmgz->nb >= RSYNC_WIN);
183 rpmgz->nb = 0;
184 return true;
185 }
186 return false;
187 }
188
189 static ssize_t
190 rsyncable_gzwrite(rpmGZFILE rpmgz, const unsigned char *const buf, const size_t len)
191 /*@modifies rpmgz @*/
192 {
193 ssize_t rc;
194 size_t n;
195 ssize_t n_written = 0;
196 const unsigned char *begin = buf;
197 size_t i;
198
199 for (i = 0; i < len; i++) {
200 if (!sync_hint(rpmgz, buf[i]))
201 continue;
202 n = i + 1 - (begin - buf);
203 rc = gzwrite(rpmgz->gz, begin, (unsigned)n);
204 if (rc < 0)
205 return (n_written ? n_written : rc);
206 n_written += rc;
207 if (rc < (ssize_t)n)
208 return n_written;
209 begin += n;
210 rc = gzflush(rpmgz->gz, Z_SYNC_FLUSH);
211 if (rc < 0)
212 return (n_written ? n_written : rc);
213 }
214 if (begin < buf + len) {
215 n = len - (begin - buf);
216 rc = gzwrite(rpmgz->gz, begin, (unsigned)n);
217 if (rc < 0)
218 return (n_written ? n_written : rc);
219 n_written += rc;
220 }
221 return n_written;
222 }
223
224 /* =============================================================== */
225 /*@-moduncon@*/
226
227 static inline /*@dependent@*/ /*@null@*/ void * gzdFileno(FD_t fd)
228 /*@*/
229 {
230 void * rc = NULL;
231 int i;
232
233 FDSANE(fd);
234 for (i = fd->nfps; i >= 0; i--) {
235 FDSTACK_t * fps = &fd->fps[i];
236 if (fps->io != gzdio)
237 continue;
238 rc = fps->fp;
239 break;
240 }
241
242 return rc;
243 }
244
245 static /*@null@*/
246 FD_t gzdOpen(const char * path, const char * fmode)
247 /*@globals fileSystem, internalState @*/
248 /*@modifies fileSystem, internalState @*/
249 {
250 FD_t fd;
251 rpmGZFILE rpmgz;
252 mode_t mode = (fmode && fmode[0] == 'w' ? O_WRONLY : O_RDONLY);
253
254 rpmgz = xcalloc(1, sizeof(*rpmgz));
255 rpmgz->gz = gzopen(path, fmode);
256 if (rpmgz->gz == NULL) {
257 rpmgz = _free(rpmgz);
258 return NULL;
259 }
260 fd = fdNew("open (gzdOpen)");
261 fdPop(fd); fdPush(fd, gzdio, rpmgz, -1);
262 fdSetOpen(fd, path, -1, mode);
263
264 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd)));
265 return fdLink(fd, "gzdOpen");
266 }
267
268 static /*@null@*/ FD_t gzdFdopen(void * cookie, const char *fmode)
269 /*@globals fileSystem, internalState @*/
270 /*@modifies fileSystem, internalState @*/
271 {
272 FD_t fd = c2f(cookie);
273 int fdno;
274 rpmGZFILE rpmgz;
275
276 if (fmode == NULL) return NULL;
277 fdno = fdFileno(fd);
278 fdSetFdno(fd, -1); /* XXX skip the fdio close */
279 if (fdno < 0) return NULL;
280 rpmgz = xcalloc(1, sizeof(*rpmgz));
281 rpmgz->gz = gzdopen(fdno, fmode);
282 if (rpmgz->gz == NULL) {
283 rpmgz = _free(rpmgz);
284 return NULL;
285 }
286
287 fdPush(fd, gzdio, rpmgz, fdno); /* Push gzdio onto stack */
288
289 return fdLink(fd, "gzdFdopen");
290 }
291
292 static int gzdFlush(void * cookie)
293 /*@*/
294 {
295 FD_t fd = c2f(cookie);
296 rpmGZFILE rpmgz;
297 rpmgz = gzdFileno(fd);
298 if (rpmgz == NULL) return -2;
299 return gzflush(rpmgz->gz, Z_SYNC_FLUSH); /* XXX W2DO? */
300 }
301
302 /* =============================================================== */
303 /*@-mustmod@*/
304 static ssize_t gzdRead(void * cookie, /*@out@*/ char * buf, size_t count)
305 /*@globals fileSystem, internalState @*/
306 /*@modifies buf, fileSystem, internalState @*/
307 {
308 FD_t fd = c2f(cookie);
309 rpmGZFILE rpmgz;
310 ssize_t rc;
311
312 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
313
314 rpmgz = gzdFileno(fd);
315 if (rpmgz == NULL) return -2; /* XXX can't happen */
316
317 fdstat_enter(fd, FDSTAT_READ);
318 rc = gzread(rpmgz->gz, buf, (unsigned)count);
319 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
320 if (rc < 0) {
321 int zerror = 0;
322 fd->errcookie = gzerror(rpmgz->gz, &zerror);
323 if (zerror == Z_ERRNO) {
324 fd->syserrno = errno;
325 fd->errcookie = strerror(fd->syserrno);
326 }
327 } else {
328 fdstat_exit(fd, FDSTAT_READ, (rc > 0 ? rc : 0));
329 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
330 }
331 return rc;
332 }
333 /*@=mustmod@*/
334
335 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count)
336 /*@globals fileSystem, internalState @*/
337 /*@modifies fileSystem, internalState @*/
338 {
339 FD_t fd = c2f(cookie);
340 rpmGZFILE rpmgz;
341 ssize_t rc;
342
343 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
344
345 if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
346
347 rpmgz = gzdFileno(fd);
348 if (rpmgz == NULL) return -2; /* XXX can't happen */
349
350 fdstat_enter(fd, FDSTAT_WRITE);
351 if (enable_rsync)
352 rc = rsyncable_gzwrite(rpmgz, (void *)buf, (unsigned)count);
353 else
354 rc = gzwrite(rpmgz->gz, (void *)buf, (unsigned)count);
355 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd)));
356 if (rc < (ssize_t)count) {
357 int zerror = 0;
358 fd->errcookie = gzerror(rpmgz->gz, &zerror);
359 if (zerror == Z_ERRNO) {
360 fd->syserrno = errno;
361 fd->errcookie = strerror(fd->syserrno);
362 }
363 }
364 if (rc > 0)
365 fdstat_exit(fd, FDSTAT_WRITE, rc);
366 return rc;
367 }
368
369 /* XXX zlib-1.0.4 has not */
370 #define HAVE_GZSEEK /* XXX autoFu doesn't set this anymore. */
371 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence)
372 /*@globals fileSystem, internalState @*/
373 /*@modifies fileSystem, internalState @*/
374 {
375 int rc;
376 #if defined(HAVE_GZSEEK)
377 #ifdef USE_COOKIE_SEEK_POINTER
378 _IO_off64_t p = *pos;
379 #else
380 off_t p = pos;
381 #endif
382 FD_t fd = c2f(cookie);
383 rpmGZFILE rpmgz;
384
385 if (fd == NULL) return -2;
386 assert(fd->bytesRemain == -1); /* XXX FIXME */
387
388 rpmgz = gzdFileno(fd);
389 if (rpmgz == NULL) return -2; /* XXX can't happen */
390
391 fdstat_enter(fd, FDSTAT_SEEK);
392 rc = gzseek(rpmgz->gz, (long)p, whence);
393 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd)));
394 if (rc < 0) {
395 int zerror = 0;
396 fd->errcookie = gzerror(rpmgz->gz, &zerror);
397 if (zerror == Z_ERRNO) {
398 fd->syserrno = errno;
399 fd->errcookie = strerror(fd->syserrno);
400 }
401 }
402 if (rc > 0)
403 fdstat_exit(fd, FDSTAT_SEEK, rc);
404 #else
405 rc = -2;
406 #endif
407 return rc;
408 }
409
410 static int gzdClose( /*@only@*/ void * cookie)
411 /*@globals fileSystem, internalState @*/
412 /*@modifies fileSystem, internalState @*/
413 {
414 FD_t fd = c2f(cookie);
415 rpmGZFILE rpmgz;
416 int rc;
417
418 rpmgz = gzdFileno(fd);
419 if (rpmgz == NULL) return -2; /* XXX can't happen */
420
421 fdstat_enter(fd, FDSTAT_CLOSE);
422 /*@-dependenttrans@*/
423 rc = gzclose(rpmgz->gz);
424 /*@=dependenttrans@*/
425 rpmgz->gz = NULL;
426 /*@-dependenttrans@*/
427 rpmgz = _free(rpmgz);
428 /*@=dependenttrans@*/
429
430 /* XXX TODO: preserve fd if errors */
431
432 if (fd) {
433 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd)));
434 if (rc < 0) {
435 fd->errcookie = "gzclose error";
436 if (rc == Z_ERRNO) {
437 fd->syserrno = errno;
438 fd->errcookie = strerror(fd->syserrno);
439 }
440 } else if (rc >= 0) {
441 fdstat_exit(fd, FDSTAT_CLOSE, rc);
442 }
443 }
444
445 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
446
447 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
448 if (rc == 0)
449 fd = fdFree(fd, "open (gzdClose)");
450 return rc;
451 }
452
453 /*@-type@*/ /* LCL: function typedefs */
454 static struct FDIO_s gzdio_s = {
455 gzdRead, gzdWrite, gzdSeek, gzdClose, gzdOpen, gzdFdopen, gzdFlush,
456 };
457 /*@=type@*/
458
459 FDIO_t gzdio = /*@-compmempass@*/ &gzdio_s /*@=compmempass@*/ ;
460
461 /*@=moduncon@*/
462 #endif /* WITH_ZLIB */