/* * Create an ARCHIVE_MATCH object. */ struct archive * archive_match_new(void) { struct archive_match *a; a = (struct archive_match *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); a->archive.magic = ARCHIVE_MATCH_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; match_list_init(&(a->inclusions)); match_list_init(&(a->exclusions)); __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); entry_list_init(&(a->exclusion_entry_list)); match_list_init(&(a->inclusion_unames)); match_list_init(&(a->inclusion_gnames)); time(&a->now); return (&(a->archive)); }
static int slurp_central_directory(struct archive_read *a, struct zip *zip) { unsigned i; int64_t correction; static const struct archive_rb_tree_ops rb_ops = { &cmp_node, &cmp_key }; static const struct archive_rb_tree_ops rb_rsrc_ops = { &rsrc_cmp_node, &rsrc_cmp_key }; /* * Consider the archive file we are reading may be SFX. * So we have to calculate a SFX header size to revise * ZIP header offsets. */ correction = zip->end_of_central_directory_offset - (zip->central_directory_offset + zip->central_directory_size); /* The central directory offset is relative value, and so * we revise this offset for SFX. */ zip->central_directory_offset += correction; __archive_read_seek(a, zip->central_directory_offset, SEEK_SET); zip->offset = zip->central_directory_offset; __archive_rb_tree_init(&zip->tree, &rb_ops); __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops); zip->zip_entries = calloc(zip->central_directory_entries, sizeof(struct zip_entry)); for (i = 0; i < zip->central_directory_entries; ++i) { struct zip_entry *zip_entry = &zip->zip_entries[i]; size_t filename_length, extra_length, comment_length; uint32_t external_attributes; const char *name, *p, *r; if ((p = __archive_read_ahead(a, 46, NULL)) == NULL) return ARCHIVE_FATAL; if (memcmp(p, "PK\001\002", 4) != 0) { archive_set_error(&a->archive, -1, "Invalid central directory signature"); return ARCHIVE_FATAL; } zip->have_central_directory = 1; /* version = p[4]; */ zip_entry->system = p[5]; /* version_required = archive_le16dec(p + 6); */ zip_entry->flags = archive_le16dec(p + 8); zip_entry->compression = (char)archive_le16dec(p + 10); zip_entry->mtime = zip_time(p + 12); zip_entry->crc32 = archive_le32dec(p + 16); zip_entry->compressed_size = archive_le32dec(p + 20); zip_entry->uncompressed_size = archive_le32dec(p + 24); filename_length = archive_le16dec(p + 28); extra_length = archive_le16dec(p + 30); comment_length = archive_le16dec(p + 32); /* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */ /* internal_attributes = archive_le16dec(p + 36); */ /* text bit */ external_attributes = archive_le32dec(p + 38); zip_entry->local_header_offset = archive_le32dec(p + 42) + correction; /* If we can't guess the mode, leave it zero here; when we read the local file header we might get more information. */ zip_entry->mode = 0; if (zip_entry->system == 3) { zip_entry->mode = external_attributes >> 16; } /* * Mac resource fork files are stored under the * "__MACOSX/" directory, so we should check if * it is. */ /* Make sure we have the file name. */ if ((p = __archive_read_ahead(a, 46 + filename_length, NULL)) == NULL) return ARCHIVE_FATAL; name = p + 46; r = rsrc_basename(name, filename_length); if (filename_length >= 9 && strncmp("__MACOSX/", name, 9) == 0) { /* If this file is not a resource fork nor * a directory. We should treat it as a non * resource fork file to expose it. */ if (name[filename_length-1] != '/' && (r - name < 3 || r[0] != '.' || r[1] != '_')) { __archive_rb_tree_insert_node(&zip->tree, &zip_entry->node); /* Expose its parent directories. */ expose_parent_dirs(zip, name, filename_length); } else { /* This file is a resource fork file or * a directory. */ archive_strncpy(&(zip_entry->rsrcname), name, filename_length); __archive_rb_tree_insert_node(&zip->tree_rsrc, &zip_entry->node); } } else { /* Generate resource fork name to find its resource * file at zip->tree_rsrc. */ archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/"); archive_strncat(&(zip_entry->rsrcname), name, r - name); archive_strcat(&(zip_entry->rsrcname), "._"); archive_strncat(&(zip_entry->rsrcname), name + (r - name), filename_length - (r - name)); /* Register an entry to RB tree to sort it by * file offset. */ __archive_rb_tree_insert_node(&zip->tree, &zip_entry->node); } /* We don't read the filename until we get to the local file header. Reading it here would speed up table-of-contents operations (removing the need to find and read local file header to get the filename) at the cost of requiring a lot of extra space. */ /* We don't read the extra block here. We assume it will be duplicated at the local file header. */ __archive_read_consume(a, 46 + filename_length + extra_length + comment_length); }