Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

delete by index #321

Merged
merged 2 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions src/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,62 @@ static ssize_t zip_entry_mark(struct zip_t *zip,
return err;
}

static ssize_t zip_entry_markbyindex(struct zip_t *zip,
struct zip_entry_mark_t *entry_mark,
const ssize_t n, size_t entries[],
const size_t len) {
ssize_t i = 0;
ssize_t err = 0;
if (!zip || !entry_mark || !entries) {
return ZIP_ENOINIT;
}

mz_zip_archive_file_stat file_stat;
mz_uint64 d_pos = UINT64_MAX;
for (i = 0; i < n; ++i) {
if ((err = zip_entry_openbyindex(zip, i))) {
return (ssize_t)err;
}

mz_bool matches = MZ_FALSE;
{
size_t j;
for (j = 0; j < len; ++j) {
if ((size_t)i == entries[j]) {
matches = MZ_TRUE;
break;
}
}
}
if (matches) {
entry_mark[i].type = MZ_DELETE;
} else {
entry_mark[i].type = MZ_KEEP;
}

if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) {
return ZIP_ENOENT;
}

zip_entry_close(zip);

entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs;
entry_mark[i].file_index = (ssize_t)-1;
entry_mark[i].lf_length = 0;
if ((entry_mark[i].type) == MZ_DELETE &&
(d_pos > entry_mark[i].m_local_header_ofs)) {
d_pos = entry_mark[i].m_local_header_ofs;
}
}

for (i = 0; i < n; ++i) {
if ((entry_mark[i].m_local_header_ofs > d_pos) &&
(entry_mark[i].type != MZ_DELETE)) {
entry_mark[i].type = MZ_MOVE;
}
}
return err;
}
static ssize_t zip_index_next(mz_uint64 *local_header_ofs_array,
ssize_t cur_index) {
ssize_t new_index = 0, i;
Expand Down Expand Up @@ -583,6 +639,20 @@ static ssize_t zip_entry_set(struct zip_t *zip,
return 0;
}

static ssize_t zip_entry_setbyindex(struct zip_t *zip,
struct zip_entry_mark_t *entry_mark, ssize_t n,
size_t entries[], const size_t len) {
ssize_t err = 0;

if ((err = zip_entry_markbyindex(zip, entry_mark, n, entries, len)) < 0) {
return err;
}
if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) {
return err;
}
return 0;
}

static ssize_t zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to,
const mz_uint64 from, const size_t length,
mz_uint8 *move_buf, const size_t capacity_size) {
Expand Down Expand Up @@ -1633,6 +1703,41 @@ ssize_t zip_entries_delete(struct zip_t *zip, char *const entries[],
return err;
}

ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[], size_t len)
{
ssize_t n = 0;
ssize_t err = 0;
struct zip_entry_mark_t *entry_mark = NULL;

if (zip == NULL || (entries == NULL && len != 0)) {
return ZIP_ENOINIT;
}

if (entries == NULL && len == 0) {
return 0;
}

n = zip_entries_total(zip);

entry_mark = (struct zip_entry_mark_t *)calloc(
(size_t)n, sizeof(struct zip_entry_mark_t));
if (!entry_mark) {
return ZIP_EOOMEM;
}

zip->archive.m_zip_mode = MZ_ZIP_MODE_READING;

err = zip_entry_setbyindex(zip, entry_mark, n, entries, len);
if (err < 0) {
CLEANUP(entry_mark);
return err;
}

err = zip_entries_delete_mark(zip, entry_mark, (int)n);
CLEANUP(entry_mark);
return err;
}

int zip_stream_extract(const char *stream, size_t size, const char *dir,
int (*on_extract)(const char *filename, void *arg),
void *arg) {
Expand Down
10 changes: 10 additions & 0 deletions src/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,16 @@ extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip);
extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip,
char *const entries[], size_t len);

/**
* Deletes zip archive entries.
*
* @param zip zip archive handler.
* @param entries array of zip archive entries indices to be deleted.
* @param len the number of entries to be deleted.
* @return the number of deleted entries, or negative number (< 0) on error.
*/
extern ZIP_EXPORT ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[], size_t len);

/**
* Extracts a zip archive stream into directory.
*
Expand Down
101 changes: 101 additions & 0 deletions test/test_entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,106 @@ MU_TEST(test_list_entries) {
zip_close(zip);
}

MU_TEST(test_entries_deletebyindex) {
size_t entries[] = {5, 6, 7, 9, 8};

struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
mu_check(zip != NULL);

mu_assert_int_eq(5, zip_entries_deletebyindex(zip, entries, 5));

zip_close(zip);

zip = zip_open(ZIPNAME, 0, 'r');
mu_check(zip != NULL);

mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me"));
mu_assert_int_eq(0, zip_entry_close(zip));
fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT));

mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_"));
mu_assert_int_eq(0, zip_entry_close(zip));
fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT));

mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1"));
mu_assert_int_eq(0, zip_entry_close(zip));
fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT));

mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3"));
mu_assert_int_eq(0, zip_entry_close(zip));
fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT));

mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2"));
mu_assert_int_eq(0, zip_entry_close(zip));
fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT));

mu_assert_int_eq(total_entries - 5, zip_entries_total(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));

size_t buftmp = 0;
char *buf = NULL;
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);

mu_assert_int_eq(bufsize, strlen(TESTDATA2));
mu_assert_int_eq((size_t)bufsize, buftmp);
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
mu_assert_int_eq(0, zip_entry_close(zip));

free(buf);
buf = NULL;

zip_close(zip);
}


MU_TEST(test_entries_deleteinvalid) {
size_t entries[] = {111, 222, 333, 444};

struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
mu_check(zip != NULL);

mu_assert_int_eq(0, zip_entries_deletebyindex(zip, entries, 4));

zip_close(zip);

zip = zip_open(ZIPNAME, 0, 'r');
mu_check(zip != NULL);

mu_assert_int_eq(0, zip_entry_open(zip, "delete.me"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "_"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.1"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "deleteme/file.3"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.2"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(total_entries, zip_entries_total(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));

size_t buftmp = 0;
char *buf = NULL;
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);

mu_assert_int_eq(bufsize, strlen(TESTDATA2));
mu_assert_int_eq((size_t)bufsize, buftmp);
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
mu_assert_int_eq(0, zip_entry_close(zip));

free(buf);
buf = NULL;

zip_close(zip);
}

MU_TEST(test_entries_delete) {
char *entries[] = {"delete.me", "_", "delete/file.1", "deleteme/file.3",
"delete/file.2"};
Expand Down Expand Up @@ -282,6 +382,7 @@ MU_TEST_SUITE(test_entry_suite) {
MU_RUN_TEST(test_entry_openbyindex);
MU_RUN_TEST(test_entry_read);
MU_RUN_TEST(test_list_entries);
MU_RUN_TEST(test_entries_deletebyindex);
MU_RUN_TEST(test_entries_delete);
}

Expand Down
Loading