123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #include "platform.h"
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include "chunks.h"
- #include "crypto.h"
- #include "ctassert.h"
- #include "storage.h"
- #include "sysendian.h"
- #include "warnp.h"
- #include "multitape_internal.h"
- /*
- * The buffer management logic requires that a struct chunkdata and a
- * maximum-size chunk fit into a buffer.
- */
- CTASSERT(MAXCHUNK < SIZE_MAX - sizeof(struct chunkheader));
- /**
- * multitape_chunkiter_tmd(S, C, tmd, func, cookie, quiet):
- * Call ${func} on ${cookie} and each struct chunkheader involved in the
- * archive associated with the metadata ${tmd}. If ${C} is non-NULL, call
- * chunks_stats_extrastats on ${C} and the length of each metadata fragment.
- * If ${quiet}, don't print any warnings about corrupt or missing files.
- * Return 0 (success), 1 (a required file is missing), 2 (a required file is
- * corrupt), -1 (error), or the first non-zero value returned by ${func}.
- */
- int
- multitape_chunkiter_tmd(STORAGE_R * S, CHUNKS_S * C,
- const struct tapemetadata * tmd,
- int func(void *, struct chunkheader *), void * cookie, int quiet)
- {
- CHUNKS_R * CR; /* Chunk layer read cookie. */
- struct tapemetaindex tmi; /* Metaindex. */
- size_t hindexpos; /* Header stream index position. */
- size_t cindexpos; /* Chunk index stream index position. */
- size_t tindexpos; /* Trailer stream index position. */
- uint8_t * ibuf; /* Contains a tape index chunk. */
- size_t ibufpos; /* Position within ibuf. */
- size_t ibuflen; /* Length of valid data in ibuf. */
- struct chunkheader * ch; /* Chunk header being processed. */
- size_t chunklen, chunkzlen; /* Decoded chunk parameters. */
- int rc;
- /* Obtain a chunk layer read cookie. */
- if ((CR = chunks_read_init(S, MAXCHUNK)) == NULL) {
- rc = -1;
- goto err0;
- }
- /* Read the tape metaindex. */
- if ((rc = multitape_metaindex_get(S, C, &tmi, tmd, quiet)) != 0)
- goto err1;
- /* Allocate a buffer for holding chunks of index. */
- if ((ibuf = malloc(MAXCHUNK + sizeof(struct chunkheader))) == NULL) {
- rc = -1;
- goto err2;
- }
- ibuflen = 0;
- /* Iterate through the header stream index. */
- for (hindexpos = 0;
- hindexpos + sizeof(struct chunkheader) <= tmi.hindexlen;
- hindexpos += sizeof(struct chunkheader)) {
- ch = (struct chunkheader *)(&tmi.hindex[hindexpos]);
- if ((rc = func(cookie, ch)) != 0)
- goto err3;
- }
- /* Iterate through the chunk index stream index. */
- for (cindexpos = 0;
- cindexpos + sizeof(struct chunkheader) <= tmi.cindexlen;
- cindexpos += sizeof(struct chunkheader)) {
- /* Call func on the next chunk from the stream. */
- ch = (struct chunkheader *)(&tmi.cindex[cindexpos]);
- if ((rc = func(cookie, ch)) != 0)
- goto err3;
- /* Decode chunk header. */
- chunklen = le32dec(ch->len);
- chunkzlen = le32dec(ch->zlen);
- /* Sanity check. */
- if (chunklen > MAXCHUNK) {
- if (quiet == 0)
- warn0("Chunk exceeds maximum size");
- rc = 2;
- goto err3;
- }
- /* We want to cache this chunk after reading it. */
- if (chunks_read_cache(CR, ch->hash))
- goto err3;
- /* Read the chunk into buffer. */
- if ((rc = chunks_read_chunk(CR, ch->hash, chunklen, chunkzlen,
- ibuf + ibuflen, quiet)) != 0)
- goto err3;
- ibuflen += chunklen;
- /* Handle any chunk headers within ibuf. */
- for (ibufpos = 0;
- ibufpos + sizeof(struct chunkheader) <= ibuflen;
- ibufpos += sizeof(struct chunkheader)) {
- /* Deal with a chunk header. */
- ch = (struct chunkheader *)(&ibuf[ibufpos]);
- if ((rc = func(cookie, ch)) != 0)
- goto err3;
- }
- /* Move buffered data to the start of the buffer. */
- memmove(ibuf, ibuf + ibufpos, ibuflen - ibufpos);
- ibuflen -= ibufpos;
- }
- /* Iterate through the trailer stream index. */
- for (tindexpos = 0;
- tindexpos + sizeof(struct chunkheader) <= tmi.tindexlen;
- tindexpos += sizeof(struct chunkheader)) {
- ch = (struct chunkheader *)(&tmi.tindex[tindexpos]);
- if ((rc = func(cookie, ch)) != 0)
- goto err3;
- }
- /* Free index chunk buffer. */
- free(ibuf);
- /* Free metaindex buffers. */
- multitape_metaindex_free(&tmi);
- /* Close handles. */
- chunks_read_free(CR);
- /* Success! */
- return (0);
- err3:
- free(ibuf);
- err2:
- multitape_metaindex_free(&tmi);
- err1:
- chunks_read_free(CR);
- err0:
- /* Failure! */
- return (rc);
- }
|