X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fzip-reader.c;h=679bdc69ebca1aee79beceae7767f1bb92f2695d;hb=6c8b13da57b074620495a0543bd7944bca574a42;hp=b84a411fe04710c19ff71c6798c20327ac807627;hpb=c39f02a7c1d95a2c7474a8b86c33e609a01c66e1;p=pspp diff --git a/src/libpspp/zip-reader.c b/src/libpspp/zip-reader.c index b84a411fe0..679bdc69eb 100644 --- a/src/libpspp/zip-reader.c +++ b/src/libpspp/zip-reader.c @@ -40,6 +40,8 @@ struct zip_member { + char *file_name; /* File name. */ + char *member_name; /* Member name. */ FILE *fp; /* The stream from which the data is read */ uint32_t offset; /* Starting offset in file. */ uint32_t comp_size; /* Length of member file data, in bytes. */ @@ -81,10 +83,11 @@ get_decompressor (uint16_t c) struct zip_reader { - char *filename; /* The name of the file from which the data is read */ + char *file_name; /* The name of the file from which the data is read */ uint16_t n_entries; /* Number of directory entries. */ struct zip_entry *entries; /* Directory entries. */ - struct string *errs; + struct string *errs; /* A string to hold error messages. This + string is NOT owned by this object. */ }; struct zip_entry @@ -100,6 +103,8 @@ zip_member_finish (struct zip_member *zm) { if (zm) { + free (zm->file_name); + free (zm->member_name); ds_clear (zm->errmsgs); zm->decompressor->finish (zm); fclose (zm->fp); @@ -115,7 +120,7 @@ zip_reader_destroy (struct zip_reader *zr) if (zr == NULL) return; - free (zr->filename); + free (zr->file_name); for (i = 0; i < zr->n_entries; ++i) { @@ -184,7 +189,8 @@ get_u16 (FILE *f, uint16_t *v) /* Read 32 bit integer and compare it with EXPECTED. place an error string in ERR if necessary. */ static bool -check_magic (FILE *f, uint32_t expected, struct string *err) +check_magic (FILE *f, const char *file_name, + uint32_t expected, struct string *err) { uint32_t magic; @@ -193,8 +199,11 @@ check_magic (FILE *f, uint32_t expected, struct string *err) if ((expected != magic)) { ds_put_format (err, - _("Corrupt file at 0x%llx: Expected %"PRIx32"; got %"PRIx32), - (long long int) ftello (f) - sizeof (uint32_t), expected, magic); + _("%s: corrupt archive at 0x%llx: " + "expected %#"PRIx32" but got %#"PRIx32), + file_name, + (long long int) ftello (f) - sizeof (uint32_t), + expected, magic); return false; } @@ -211,11 +220,11 @@ zip_member_read (struct zip_member *zm, void *buf, size_t bytes) ds_clear (zm->errmsgs); - if ( bytes > zm->bytes_unread) + if (bytes > zm->bytes_unread) bytes = zm->bytes_unread; bytes_read = zm->decompressor->read (zm, buf, bytes); - if ( bytes_read < 0) + if (bytes_read < 0) return bytes_read; zm->bytes_unread -= bytes_read; @@ -223,12 +232,46 @@ zip_member_read (struct zip_member *zm, void *buf, size_t bytes) return bytes_read; } +/* Read all of ZM into memory, storing the data in *DATAP and its size in *NP. + Returns NULL if successful, otherwise an error string that the caller + must eventually free(). */ +char * WARN_UNUSED_RESULT +zip_member_read_all (struct zip_reader *zr, const char *member_name, + void **datap, size_t *np) +{ + struct zip_member *zm = zip_member_open (zr, member_name); + if (!zm) + { + *datap = NULL; + *np = 0; + return ds_steal_cstr (zr->errs); + } + + *datap = xmalloc (zm->ucomp_size); + *np = zm->ucomp_size; + + uint8_t *data = *datap; + while (zm->bytes_unread) + if (zip_member_read (zm, data + (zm->ucomp_size - zm->bytes_unread), + zm->bytes_unread) == -1) + { + zip_member_finish (zm); + free (*datap); + *datap = NULL; + *np = 0; + return ds_steal_cstr (zr->errs); + } + + zip_member_finish (zm); + return NULL; +} /* Read a central directory header from FILE and initializes ZE with it. Returns true if successful, false otherwise. On error, appends error messages to ERRS. */ static bool -zip_header_read_next (FILE *file, struct zip_entry *ze, struct string *errs) +zip_header_read_next (FILE *file, const char *file_name, + struct zip_entry *ze, struct string *errs) { uint16_t v, nlen, extralen; uint16_t gp, time, date; @@ -238,7 +281,7 @@ zip_header_read_next (FILE *file, struct zip_entry *ze, struct string *errs) uint32_t eattr; uint16_t comp_type; - if ( ! check_magic (file, MAGIC_SOCD, errs)) + if (! check_magic (file, file_name, MAGIC_SOCD, errs)) return false; if (! get_u16 (file, &v)) return false; @@ -267,9 +310,9 @@ zip_header_read_next (FILE *file, struct zip_entry *ze, struct string *errs) } -/* Create a reader from the zip called FILENAME */ +/* Create a reader from the zip called FILE_NAME */ struct zip_reader * -zip_reader_create (const char *filename, struct string *errs) +zip_reader_create (const char *file_name, struct string *errs) { uint16_t disknum, n_members, total_members; off_t offset = 0; @@ -277,43 +320,45 @@ zip_reader_create (const char *filename, struct string *errs) struct zip_reader *zr = xzalloc (sizeof *zr); zr->errs = errs; - if ( zr->errs) + if (zr->errs) ds_init_empty (zr->errs); - FILE *file = fopen (filename, "rb"); + FILE *file = fopen (file_name, "rb"); if (!file) { - ds_put_cstr (zr->errs, strerror (errno)); + ds_put_format (zr->errs, _("%s: open failed (%s)"), + file_name, strerror (errno)); free (zr); return NULL; } - if ( ! check_magic (file, MAGIC_LHDR, zr->errs)) + if (! check_magic (file, file_name, MAGIC_LHDR, zr->errs)) { fclose (file); free (zr); return NULL; } - if ( ! find_eocd (file, &offset)) + if (! find_eocd (file, &offset)) { - ds_put_format (zr->errs, _("Cannot find central directory")); + ds_put_format (zr->errs, _("%s: cannot find central directory"), + file_name); fclose (file); free (zr); return NULL; } - if ( 0 != fseeko (file, offset, SEEK_SET)) + if (0 != fseeko (file, offset, SEEK_SET)) { - const char *mm = strerror (errno); - ds_put_format (zr->errs, _("Failed to seek to end of central directory record: %s"), mm); + ds_put_format (zr->errs, _("%s: seek failed (%s)"), + file_name, strerror (errno)); fclose (file); free (zr); return NULL; } - if ( ! check_magic (file, MAGIC_EOCD, zr->errs)) + if (! check_magic (file, file_name, MAGIC_EOCD, zr->errs)) { fclose (file); free (zr); @@ -334,21 +379,22 @@ zip_reader_create (const char *filename, struct string *errs) return NULL; } - if ( 0 != fseeko (file, central_dir_start, SEEK_SET)) + if (0 != fseeko (file, central_dir_start, SEEK_SET)) { - const char *mm = strerror (errno); - ds_put_format (zr->errs, _("Failed to seek to central directory: %s"), mm); + ds_put_format (zr->errs, _("%s: seek failed (%s)"), + file_name, strerror (errno)); fclose (file); free (zr); return NULL; } - zr->filename = xstrdup (filename); + zr->file_name = xstrdup (file_name); zr->entries = xcalloc (n_members, sizeof *zr->entries); for (int i = 0; i < n_members; i++) { - if (!zip_header_read_next (file, &zr->entries[zr->n_entries], errs)) + if (!zip_header_read_next (file, file_name, + &zr->entries[zr->n_entries], errs)) { fclose (file); zip_reader_destroy (zr); @@ -361,7 +407,7 @@ zip_reader_create (const char *filename, struct string *errs) } static struct zip_entry * -zip_entry_find (struct zip_reader *zr, const char *member) +zip_entry_find (const struct zip_reader *zr, const char *member) { for (int i = 0; i < zr->n_entries; ++i) { @@ -378,25 +424,36 @@ zip_reader_get_member_name(const struct zip_reader *zr, size_t idx) return idx < zr->n_entries ? zr->entries[idx].name : NULL; } +/* Returns true if ZR contains a member named MEMBER, false otherwise. */ +bool +zip_reader_contains_member (const struct zip_reader *zr, const char *member) +{ + return zip_entry_find (zr, member) != NULL; +} + /* Return the member called MEMBER from the reader ZR */ struct zip_member * zip_member_open (struct zip_reader *zr, const char *member) { struct zip_entry *ze = zip_entry_find (zr, member); - if ( ze == NULL) + if (ze == NULL) { - ds_put_format (zr->errs, _("%s: unknown member"), member); + ds_put_format (zr->errs, _("%s: unknown member \"%s\""), + zr->file_name, member); return NULL; } - FILE *fp = fopen (zr->filename, "rb"); + FILE *fp = fopen (zr->file_name, "rb"); if (!fp) { - ds_put_cstr (zr->errs, strerror (errno)); + ds_put_format (zr->errs, _("%s: open failed (%s)"), + zr->file_name, strerror (errno)); return NULL; } struct zip_member *zm = xmalloc (sizeof *zm); + zm->file_name = xstrdup (zr->file_name); + zm->member_name = xstrdup (member); zm->fp = fp; zm->offset = ze->offset; zm->comp_size = ze->comp_size; @@ -406,14 +463,14 @@ zip_member_open (struct zip_reader *zr, const char *member) zm->errmsgs = zr->errs; zm->aux = NULL; - if ( 0 != fseeko (zm->fp, zm->offset, SEEK_SET)) + if (0 != fseeko (zm->fp, zm->offset, SEEK_SET)) { - ds_put_format (zr->errs, _("Failed to seek to start of member `%s': %s"), + ds_put_format (zr->errs, _("%s: seek failed (%s)"), ze->name, strerror (errno)); goto error; } - if ( ! check_magic (zm->fp, MAGIC_LHDR, zr->errs)) + if (! check_magic (zm->fp, zr->file_name, MAGIC_LHDR, zr->errs)) goto error; uint16_t v, nlen, extra_len; @@ -443,9 +500,9 @@ zip_member_open (struct zip_reader *zr, const char *member) if (strcmp (name, ze->name) != 0) { ds_put_format (zm->errmsgs, - _("Name mismatch in zip archive. Central directory " - "says `%s'; local file header says `%s'"), - ze->name, name); + _("%s: name mismatch between central directory (%s) " + "and local file header (%s)"), + zm->file_name, ze->name, name); free (name); goto error; } @@ -453,13 +510,15 @@ zip_member_open (struct zip_reader *zr, const char *member) skip_bytes (zm->fp, extra_len); - if (!zm->decompressor->init (zm) ) + if (!zm->decompressor->init (zm)) goto error; return zm; error: fclose (zm->fp); + free (zm->file_name); + free (zm->member_name); free (zm); return NULL; } @@ -484,7 +543,7 @@ find_eocd (FILE *fp, off_t *off) because that is the minimum length of the EndOfCentralDirectory record. */ - if ( 0 > fseeko (fp, -22, SEEK_END)) + if (0 > fseeko (fp, -22, SEEK_END)) { return false; } @@ -494,12 +553,12 @@ find_eocd (FILE *fp, off_t *off) { found = probe_magic (fp, magic, start, stop, off); /* FIXME: For extra confidence lookup the directory start record here*/ - if ( start == 0) + if (start == 0) break; stop = start + sizeof (magic); start >>= 1; } - while (!found ); + while (!found); return found; } @@ -518,7 +577,7 @@ probe_magic (FILE *fp, uint32_t magic, off_t start, off_t stop, off_t *off) unsigned char seq[4]; unsigned char byte; - if ( 0 > fseeko (fp, start, SEEK_SET)) + if (0 > fseeko (fp, start, SEEK_SET)) { return -1; } @@ -533,18 +592,18 @@ probe_magic (FILE *fp, uint32_t magic, off_t start, off_t stop, off_t *off) if (1 != fread (&byte, 1, 1, fp)) break; - if ( byte == seq[state]) + if (byte == seq[state]) state++; else state = 0; - if ( state == 4) + if (state == 4) { *off = ftello (fp) - 4; return true; } start++; - if ( start >= stop) + if (start >= stop) break; } while (!feof (fp)); @@ -618,7 +677,7 @@ inflate_init (struct zip_member *zm) cmf |= cinfo << 4; /* Put cinfo into the high nibble */ /* make these into a 16 bit word */ - inf->cmf_flg = (cmf << 8 ) | flg; + inf->cmf_flg = (cmf << 8) | flg; /* Set the check bits */ inf->cmf_flg += 31 - (inf->cmf_flg % 31); @@ -631,9 +690,11 @@ inflate_init (struct zip_member *zm) inf->zss.opaque = Z_NULL; r = inflateInit (&inf->zss); - if ( Z_OK != r) + if (Z_OK != r) { - ds_put_format (zm->errmsgs, _("Cannot initialize inflator: %s"), zError (r)); + ds_put_format (zm->errmsgs, + _("%s: cannot initialize inflator (%s)"), + zm->file_name, zError (r)); return false; } @@ -654,7 +715,7 @@ inflate_read (struct zip_member *zm, void *buf, size_t n) int bytes_to_read; int pad = 0; - if ( inf->state == 0) + if (inf->state == 0) { inf->ucomp[1] = inf->cmf_flg ; inf->ucomp[0] = inf->cmf_flg >> 8 ; @@ -682,12 +743,13 @@ inflate_read (struct zip_member *zm, void *buf, size_t n) inf->zss.next_out = buf; r = inflate (&inf->zss, Z_NO_FLUSH); - if ( Z_OK == r) + if (Z_OK == r) { return n - inf->zss.avail_out; } - ds_put_format (zm->errmsgs, _("Error inflating: %s"), zError (r)); + ds_put_format (zm->errmsgs, _("%s: error inflating \"%s\" (%s)"), + zm->file_name, zm->member_name, zError (r)); return -1; }