rpm
5.2.1
|
00001 00006 #include "system.h" 00007 00008 #if defined(NOTYET) || defined(__LCLINT__) 00009 #include <stdbool.h> 00010 #else 00011 typedef enum { true = 1, false = 0 } bool; 00012 #endif 00013 00014 #include "rpmio_internal.h" 00015 #include <rpmmacro.h> 00016 #include <rpmcb.h> 00017 00018 #if defined(WITH_ZLIB) 00019 00020 /*@-noparams@*/ 00021 #include <zlib.h> 00022 /*@=noparams@*/ 00023 00024 #include "debug.h" 00025 00026 /*@access FD_t @*/ 00027 00028 #define GZDONLY(fd) assert(fdGetIo(fd) == gzdio) 00029 00030 typedef struct cpio_state_s { 00031 rpmuint32_t n; /* byte progress in cpio header */ 00032 rpmuint32_t mode; /* file attributes */ 00033 rpmuint32_t nlnk; 00034 rpmuint32_t size; 00035 } * cpio_state; 00036 00037 #define RSYNC_WIN 4096 00038 00039 typedef struct rsync_state_s { 00040 rpmuint32_t n; /* number of elements in the window */ 00041 rpmuint32_t sum; /* current sum */ 00042 unsigned char win[RSYNC_WIN]; /* window elements */ 00043 } * rsync_state; 00044 00045 typedef struct rpmGZFILE_s { 00046 gzFile gz; /* gzFile is a pointer */ 00047 struct rsync_state_s rs; 00048 struct cpio_state_s cs; 00049 rpmuint32_t nb; /* bytes pending for sync */ 00050 } * rpmGZFILE; /* like FILE, to use with star */ 00051 00052 /* Should gzflush be called only after RSYNC_WIN boundaries? */ 00053 /*@unchecked@*/ 00054 static int enable_rsync = 1; 00055 00056 /* =============================================================== */ 00057 /* from ../lib/cpio.h */ 00058 #define CPIO_NEWC_MAGIC "070701" 00059 #define PHYS_HDR_SIZE 110 00060 00061 #define OFFSET_MODE (sizeof(CPIO_NEWC_MAGIC)-1 + 1*8) 00062 #define OFFSET_NLNK (sizeof(CPIO_NEWC_MAGIC)-1 + 4*8) 00063 #define OFFSET_SIZE (sizeof(CPIO_NEWC_MAGIC)-1 + 6*8) 00064 00065 static inline 00066 int hex(char c) 00067 /*@*/ 00068 { 00069 if (c >= '0' && c <= '9') 00070 return (int)(c - '0'); 00071 else if (c >= 'a' && c <= 'f') 00072 return (int)(c - 'a') + 10; 00073 else if (c >= 'A' && c <= 'F') 00074 return (int)(c - 'A') + 10; 00075 return -1; 00076 } 00077 00078 static inline 00079 bool cpio_next(cpio_state s, unsigned char c) 00080 /*@modifies s @*/ 00081 { 00082 if (s->n >= sizeof(CPIO_NEWC_MAGIC)-1) { 00083 int d = hex(c); 00084 if (d < 0) { 00085 s->n = 0; 00086 return false; 00087 } 00088 if (0){} /* indent */ 00089 else if (s->n >= OFFSET_MODE && s->n < OFFSET_MODE+8) { 00090 if (s->n == OFFSET_MODE) 00091 s->mode = 0; 00092 else 00093 s->mode <<= 4; 00094 s->mode |= d; 00095 } 00096 else if (s->n >= OFFSET_NLNK && s->n < OFFSET_NLNK+8) { 00097 if (s->n == OFFSET_NLNK) 00098 s->nlnk = 0; 00099 else 00100 s->nlnk <<= 4; 00101 s->nlnk |= d; 00102 } 00103 else if (s->n >= OFFSET_SIZE && s->n < OFFSET_SIZE+8) { 00104 if (s->n == OFFSET_SIZE) 00105 s->size = 0; 00106 else 00107 s->size <<= 4; 00108 s->size |= d; 00109 } 00110 s->n++; 00111 if (s->n >= PHYS_HDR_SIZE) { 00112 s->n = 0; 00113 if (!S_ISREG(s->mode) || s->nlnk != 1) 00114 /* no file data */ 00115 s->size = 0; 00116 return true; 00117 } 00118 } 00119 else if (CPIO_NEWC_MAGIC[s->n] == c) { 00120 s->n++; 00121 } 00122 else { 00123 s->n = 0; 00124 } 00125 return false; 00126 } 00127 00128 /* =============================================================== */ 00129 static inline 00130 bool rsync_next(rsync_state s, unsigned char c) 00131 /*@modifies s @*/ 00132 { 00133 rpmuint32_t i; 00134 00135 if (s->n < RSYNC_WIN) { /* not enough elements */ 00136 s->sum += (rpmuint32_t)c; /* update the sum */ 00137 s->win[s->n++] = c; /* remember the element */ 00138 return false; /* no match */ 00139 } 00140 i = s->n++ % RSYNC_WIN; /* wrap up */ 00141 s->sum -= (rpmuint32_t)s->win[i]; /* move the window on */ 00142 s->sum += (rpmuint32_t)c; 00143 s->win[i] = c; 00144 if (s->sum % RSYNC_WIN == 0) { /* match */ 00145 s->n = 0; /* reset */ 00146 s->sum = 0; 00147 return true; 00148 } 00149 return false; 00150 } 00151 00152 #define CHUNK 4096 00153 00154 static inline 00155 bool sync_hint(rpmGZFILE rpmgz, unsigned char c) 00156 /*@modifies rpmgz @*/ 00157 { 00158 bool cpio_hint; 00159 bool rsync_hint; 00160 00161 rpmgz->nb++; 00162 cpio_hint = cpio_next(&rpmgz->cs, c); 00163 if (cpio_hint) { 00164 /* cpio header/data boundary */ 00165 rpmgz->rs.n = rpmgz->rs.sum = 0; 00166 if (rpmgz->nb >= 2*CHUNK) 00167 /* better sync here */ 00168 goto cpio_sync; 00169 if (rpmgz->cs.size < CHUNK) 00170 /* file is too small */ 00171 return false; 00172 if (rpmgz->nb < CHUNK/2) 00173 /* not enough pending bytes */ 00174 return false; 00175 cpio_sync: 00176 rpmgz->nb = 0; 00177 return true; 00178 } 00179 rsync_hint = rsync_next(&rpmgz->rs, c); 00180 if (rsync_hint) { 00181 /* rolling checksum match */ 00182 assert(rpmgz->nb >= RSYNC_WIN); 00183 rpmgz->nb = 0; 00184 return true; 00185 } 00186 return false; 00187 } 00188 00189 static ssize_t 00190 rsyncable_gzwrite(rpmGZFILE rpmgz, const unsigned char *const buf, const size_t len) 00191 /*@modifies rpmgz @*/ 00192 { 00193 ssize_t rc; 00194 size_t n; 00195 ssize_t n_written = 0; 00196 const unsigned char *begin = buf; 00197 size_t i; 00198 00199 for (i = 0; i < len; i++) { 00200 if (!sync_hint(rpmgz, buf[i])) 00201 continue; 00202 n = i + 1 - (begin - buf); 00203 rc = gzwrite(rpmgz->gz, begin, (unsigned)n); 00204 if (rc < 0) 00205 return (n_written ? n_written : rc); 00206 n_written += rc; 00207 if (rc < (ssize_t)n) 00208 return n_written; 00209 begin += n; 00210 rc = gzflush(rpmgz->gz, Z_SYNC_FLUSH); 00211 if (rc < 0) 00212 return (n_written ? n_written : rc); 00213 } 00214 if (begin < buf + len) { 00215 n = len - (begin - buf); 00216 rc = gzwrite(rpmgz->gz, begin, (unsigned)n); 00217 if (rc < 0) 00218 return (n_written ? n_written : rc); 00219 n_written += rc; 00220 } 00221 return n_written; 00222 } 00223 00224 /* =============================================================== */ 00225 /*@-moduncon@*/ 00226 00227 static inline /*@dependent@*/ /*@null@*/ void * gzdFileno(FD_t fd) 00228 /*@*/ 00229 { 00230 void * rc = NULL; 00231 int i; 00232 00233 FDSANE(fd); 00234 for (i = fd->nfps; i >= 0; i--) { 00235 FDSTACK_t * fps = &fd->fps[i]; 00236 if (fps->io != gzdio) 00237 continue; 00238 rc = fps->fp; 00239 break; 00240 } 00241 00242 return rc; 00243 } 00244 00245 static /*@null@*/ 00246 FD_t gzdOpen(const char * path, const char * fmode) 00247 /*@globals fileSystem, internalState @*/ 00248 /*@modifies fileSystem, internalState @*/ 00249 { 00250 FD_t fd; 00251 rpmGZFILE rpmgz; 00252 mode_t mode = (fmode && fmode[0] == 'w' ? O_WRONLY : O_RDONLY); 00253 00254 rpmgz = xcalloc(1, sizeof(*rpmgz)); 00255 rpmgz->gz = gzopen(path, fmode); 00256 if (rpmgz->gz == NULL) { 00257 rpmgz = _free(rpmgz); 00258 return NULL; 00259 } 00260 fd = fdNew("open (gzdOpen)"); 00261 fdPop(fd); fdPush(fd, gzdio, rpmgz, -1); 00262 fdSetOpen(fd, path, -1, mode); 00263 00264 DBGIO(fd, (stderr, "==>\tgzdOpen(\"%s\", \"%s\") fd %p %s\n", path, fmode, (fd ? fd : NULL), fdbg(fd))); 00265 return fdLink(fd, "gzdOpen"); 00266 } 00267 00268 static /*@null@*/ FD_t gzdFdopen(void * cookie, const char *fmode) 00269 /*@globals fileSystem, internalState @*/ 00270 /*@modifies fileSystem, internalState @*/ 00271 { 00272 FD_t fd = c2f(cookie); 00273 int fdno; 00274 rpmGZFILE rpmgz; 00275 00276 if (fmode == NULL) return NULL; 00277 fdno = fdFileno(fd); 00278 fdSetFdno(fd, -1); /* XXX skip the fdio close */ 00279 if (fdno < 0) return NULL; 00280 rpmgz = xcalloc(1, sizeof(*rpmgz)); 00281 rpmgz->gz = gzdopen(fdno, fmode); 00282 if (rpmgz->gz == NULL) { 00283 rpmgz = _free(rpmgz); 00284 return NULL; 00285 } 00286 00287 fdPush(fd, gzdio, rpmgz, fdno); /* Push gzdio onto stack */ 00288 00289 return fdLink(fd, "gzdFdopen"); 00290 } 00291 00292 static int gzdFlush(void * cookie) 00293 /*@*/ 00294 { 00295 FD_t fd = c2f(cookie); 00296 rpmGZFILE rpmgz; 00297 rpmgz = gzdFileno(fd); 00298 if (rpmgz == NULL) return -2; 00299 return gzflush(rpmgz->gz, Z_SYNC_FLUSH); /* XXX W2DO? */ 00300 } 00301 00302 /* =============================================================== */ 00303 /*@-mustmod@*/ 00304 static ssize_t gzdRead(void * cookie, /*@out@*/ char * buf, size_t count) 00305 /*@globals fileSystem, internalState @*/ 00306 /*@modifies buf, fileSystem, internalState @*/ 00307 { 00308 FD_t fd = c2f(cookie); 00309 rpmGZFILE rpmgz; 00310 ssize_t rc; 00311 00312 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */ 00313 00314 rpmgz = gzdFileno(fd); 00315 if (rpmgz == NULL) return -2; /* XXX can't happen */ 00316 00317 fdstat_enter(fd, FDSTAT_READ); 00318 rc = gzread(rpmgz->gz, buf, (unsigned)count); 00319 DBGIO(fd, (stderr, "==>\tgzdRead(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd))); 00320 if (rc < 0) { 00321 int zerror = 0; 00322 fd->errcookie = gzerror(rpmgz->gz, &zerror); 00323 if (zerror == Z_ERRNO) { 00324 fd->syserrno = errno; 00325 fd->errcookie = strerror(fd->syserrno); 00326 } 00327 } else { 00328 fdstat_exit(fd, FDSTAT_READ, (rc > 0 ? rc : 0)); 00329 if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc); 00330 } 00331 return rc; 00332 } 00333 /*@=mustmod@*/ 00334 00335 static ssize_t gzdWrite(void * cookie, const char * buf, size_t count) 00336 /*@globals fileSystem, internalState @*/ 00337 /*@modifies fileSystem, internalState @*/ 00338 { 00339 FD_t fd = c2f(cookie); 00340 rpmGZFILE rpmgz; 00341 ssize_t rc; 00342 00343 if (fd == NULL || fd->bytesRemain == 0) return 0; /* XXX simulate EOF */ 00344 00345 if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count); 00346 00347 rpmgz = gzdFileno(fd); 00348 if (rpmgz == NULL) return -2; /* XXX can't happen */ 00349 00350 fdstat_enter(fd, FDSTAT_WRITE); 00351 if (enable_rsync) 00352 rc = rsyncable_gzwrite(rpmgz, (void *)buf, (unsigned)count); 00353 else 00354 rc = gzwrite(rpmgz->gz, (void *)buf, (unsigned)count); 00355 DBGIO(fd, (stderr, "==>\tgzdWrite(%p,%p,%u) rc %lx %s\n", cookie, buf, (unsigned)count, (unsigned long)rc, fdbg(fd))); 00356 if (rc < (ssize_t)count) { 00357 int zerror = 0; 00358 fd->errcookie = gzerror(rpmgz->gz, &zerror); 00359 if (zerror == Z_ERRNO) { 00360 fd->syserrno = errno; 00361 fd->errcookie = strerror(fd->syserrno); 00362 } 00363 } 00364 if (rc > 0) 00365 fdstat_exit(fd, FDSTAT_WRITE, rc); 00366 return rc; 00367 } 00368 00369 /* XXX zlib-1.0.4 has not */ 00370 #define HAVE_GZSEEK /* XXX autoFu doesn't set this anymore. */ 00371 static inline int gzdSeek(void * cookie, _libio_pos_t pos, int whence) 00372 /*@globals fileSystem, internalState @*/ 00373 /*@modifies fileSystem, internalState @*/ 00374 { 00375 int rc; 00376 #if defined(HAVE_GZSEEK) 00377 #ifdef USE_COOKIE_SEEK_POINTER 00378 _IO_off64_t p = *pos; 00379 #else 00380 off_t p = pos; 00381 #endif 00382 FD_t fd = c2f(cookie); 00383 rpmGZFILE rpmgz; 00384 00385 if (fd == NULL) return -2; 00386 assert(fd->bytesRemain == -1); /* XXX FIXME */ 00387 00388 rpmgz = gzdFileno(fd); 00389 if (rpmgz == NULL) return -2; /* XXX can't happen */ 00390 00391 fdstat_enter(fd, FDSTAT_SEEK); 00392 rc = gzseek(rpmgz->gz, (long)p, whence); 00393 DBGIO(fd, (stderr, "==>\tgzdSeek(%p,%ld,%d) rc %lx %s\n", cookie, (long)p, whence, (unsigned long)rc, fdbg(fd))); 00394 if (rc < 0) { 00395 int zerror = 0; 00396 fd->errcookie = gzerror(rpmgz->gz, &zerror); 00397 if (zerror == Z_ERRNO) { 00398 fd->syserrno = errno; 00399 fd->errcookie = strerror(fd->syserrno); 00400 } 00401 } 00402 if (rc > 0) 00403 fdstat_exit(fd, FDSTAT_SEEK, rc); 00404 #else 00405 rc = -2; 00406 #endif 00407 return rc; 00408 } 00409 00410 static int gzdClose( /*@only@*/ void * cookie) 00411 /*@globals fileSystem, internalState @*/ 00412 /*@modifies fileSystem, internalState @*/ 00413 { 00414 FD_t fd = c2f(cookie); 00415 rpmGZFILE rpmgz; 00416 int rc; 00417 00418 rpmgz = gzdFileno(fd); 00419 if (rpmgz == NULL) return -2; /* XXX can't happen */ 00420 00421 fdstat_enter(fd, FDSTAT_CLOSE); 00422 /*@-dependenttrans@*/ 00423 rc = gzclose(rpmgz->gz); 00424 /*@=dependenttrans@*/ 00425 rpmgz->gz = NULL; 00426 /*@-dependenttrans@*/ 00427 rpmgz = _free(rpmgz); 00428 /*@=dependenttrans@*/ 00429 00430 /* XXX TODO: preserve fd if errors */ 00431 00432 if (fd) { 00433 DBGIO(fd, (stderr, "==>\tgzdClose(%p) zerror %d %s\n", cookie, rc, fdbg(fd))); 00434 if (rc < 0) { 00435 fd->errcookie = "gzclose error"; 00436 if (rc == Z_ERRNO) { 00437 fd->syserrno = errno; 00438 fd->errcookie = strerror(fd->syserrno); 00439 } 00440 } else if (rc >= 0) { 00441 fdstat_exit(fd, FDSTAT_CLOSE, rc); 00442 } 00443 } 00444 00445 DBGIO(fd, (stderr, "==>\tgzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd))); 00446 00447 if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr); 00448 if (rc == 0) 00449 fd = fdFree(fd, "open (gzdClose)"); 00450 return rc; 00451 } 00452 00453 /*@-type@*/ /* LCL: function typedefs */ 00454 static struct FDIO_s gzdio_s = { 00455 gzdRead, gzdWrite, gzdSeek, gzdClose, gzdOpen, gzdFdopen, gzdFlush, 00456 }; 00457 /*@=type@*/ 00458 00459 FDIO_t gzdio = /*@-compmempass@*/ &gzdio_s /*@=compmempass@*/ ; 00460 00461 /*@=moduncon@*/ 00462 #endif /* WITH_ZLIB */