Skip to content

Commit

Permalink
archive extract move to C
Browse files Browse the repository at this point in the history
  • Loading branch information
sulincix committed Nov 11, 2023
1 parent 48cdb38 commit 6e6e0f1
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 75 deletions.
7 changes: 7 additions & 0 deletions src/ccode.vala
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ public extern void skeleton_daemon ();
public extern void write_archive (string output, string[] files);
public extern void set_archive_type (string filt, string form);

//DOC: ### archive-extract.c
//DOC: `int archive_extract_all (string path, string output):`
//DOC: extract archive file
//this functions and values used by util/archive.vala
public extern int extract_archive_all (string path, string output);
public extern int extract_archive_file (string path, string output, string file);

//DOC: ### file.c
//DOC: `int filesize (string path):`
//DOC: calculate file size
Expand Down
124 changes: 124 additions & 0 deletions src/ccode/archive-extract.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include <stdio.h>
#include <stdlib.h>
#include <archive.h>
#include <archive_entry.h>
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int r;

int extract_archive_all(const char *archive_path, const char *extract_path) {

/* Open the archive file */
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_filter_all(a);

if ((r = archive_read_open_filename(a, archive_path, 10240))) {
return r;
}

/* Create the extraction archive */
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
archive_write_disk_set_standard_lookup(ext);

/* Extract each entry in the archive */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
const char *entry_path = archive_entry_pathname(entry);
archive_entry_set_pathname(entry, entry_path); /* Ensure path consistency */

/* Set the destination path for extraction */
char dest_path[256];
snprintf(dest_path, sizeof(dest_path), "%s/%s", extract_path, entry_path);
archive_entry_set_pathname(entry, dest_path);

/* Extract the entry */
archive_write_header(ext, entry);

/* Open the file for writing */
FILE *dest_file = fopen(dest_path, "wb");
if (!dest_file) {
fprintf(stderr, "Failed to open destination file: %s\n", dest_path);
return 1;
}

/* Read and write data to the file */
char buffer[4096];
size_t len;
while ((r = archive_read_data(a, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, 1, r, dest_file);
}

fclose(dest_file);

archive_write_finish_entry(ext);
}

/* Close and free resources */
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);

return 0;
}

int extract_archive_file(const char *archive_path, const char *extract_path, const char* file_path) {

/* Open the archive file */
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_filter_all(a);

if ((r = archive_read_open_filename(a, archive_path, 10240))) {
return r;
}

/* Create the extraction archive */
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
archive_write_disk_set_standard_lookup(ext);

/* Extract each entry in the archive */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
const char *entry_path = archive_entry_pathname(entry);
if (entry_path != file_path)
continue;
archive_entry_set_pathname(entry, entry_path); /* Ensure path consistency */

/* Set the destination path for extraction */
char dest_path[256];
snprintf(dest_path, sizeof(dest_path), "%s/%s", extract_path, entry_path);
archive_entry_set_pathname(entry, dest_path);

/* Extract the entry */
archive_write_header(ext, entry);

/* Open the file for writing */
FILE *dest_file = fopen(dest_path, "wb");
if (!dest_file) {
fprintf(stderr, "Failed to open destination file: %s\n", dest_path);
return 1;
}

/* Read and write data to the file */
char buffer[4096];
size_t len;
while ((r = archive_read_data(a, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, 1, r, dest_file);
}

fclose(dest_file);

archive_write_finish_entry(ext);
}

/* Close and free resources */
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);

return 0;
}
4 changes: 4 additions & 0 deletions src/operations/utility/extract.vala
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
public int extract_main (string[] args) {
var tar = new archive ();
tar.load (args[0]);
string target = get_value("target");
if(target != ""){
tar.set_target(srealpath(target));
}
if (get_bool ("list")) {
foreach (string file in tar.list_files ()) {
print (file);
Expand Down
88 changes: 13 additions & 75 deletions src/util/archive.vala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ public class archive {
public void load (string path) {
archive_path = srealpath (path);
set_archive_type ("zip", "none");
if ( target_path == null) {
target_path = pwd();
}
}
private void load_archive (string path) {
debug (_ ("Load archive : %s").printf (path));
Expand Down Expand Up @@ -143,50 +146,6 @@ public class archive {
write_archive (archive_path, archive_add_list);
}

//DOC: `void archive.extract (string path):`
//DOC: Extract **path** file to target directory
public void extract (string path) {
debug (_ ("Extract archve: %s").printf (path));
load_archive (archive_path);
Archive.ExtractFlags flags;
flags = Archive.ExtractFlags.TIME;
flags |= Archive.ExtractFlags.PERM;
flags |= Archive.ExtractFlags.ACL;
flags |= Archive.ExtractFlags.FFLAGS;

Archive.WriteDisk extractor = new Archive.WriteDisk ();
extractor.set_options (flags);
extractor.set_standard_lookup ();

unowned Archive.Entry entry;
Archive.Result last_result;
while ( (last_result = archive.next_header (out entry)) == Archive.Result.OK) {
if (entry.pathname () != path) {
continue;
}
debug ("Extracting: %s".printf (path));

if (target_path == null) {
target_path = "./";
}
entry.set_pathname (target_path + "/" + path);

if (extractor.write_header (entry) != Archive.Result.OK) {
error_add ("Failed to write file: %s".printf (entry.pathname ()));
continue;
}

uint8[] buffer = null;
Posix.off_t offset;
while (archive.read_data_block (out buffer, out offset) == Archive.Result.OK) {
if (extractor.write_data_block (buffer, offset) != Archive.Result.OK) {
break;
}
}
}
fs_sync ();
error (3);
}
//DOC: `string archive.readfile (string path):`
//DOC: Read **path** file to target directory
public string readfile (string path) {
Expand All @@ -213,42 +172,21 @@ public class archive {
return ret;
}

//DOC: `void archive.extract (string path):`
//DOC: Extract **path** file to target directory
public void extract (string path) {
debug (_ ("Extract archve: %s").printf (path));
load_archive (archive_path);
extract_archive_file(archive_path, target_path, path);
fs_sync ();
error (3);
}

//DOC: `void archive.extract_all ()`
//DOC: Extract all files to target
public void extract_all () {
load_archive (archive_path);
Archive.ExtractFlags flags;
flags = Archive.ExtractFlags.TIME;
flags |= Archive.ExtractFlags.PERM;
flags |= Archive.ExtractFlags.ACL;
flags |= Archive.ExtractFlags.FFLAGS;

Archive.WriteDisk extractor = new Archive.WriteDisk ();
extractor.set_options (flags);
extractor.set_standard_lookup ();

unowned Archive.Entry entry;
Archive.Result last_result;
while ( (last_result = archive.next_header (out entry)) == Archive.Result.OK) {
if (target_path == null) {
target_path = "./";
}
info ("Extracting: " + entry.pathname ());
entry.set_pathname (target_path + "/" + entry.pathname ());
if (extractor.write_header (entry) != Archive.Result.OK) {
error_add ("Failed to write file: %s".printf (entry.pathname ()));
continue;
}

uint8[] buffer = null;
Posix.off_t offset;
while (archive.read_data_block (out buffer, out offset) == Archive.Result.OK) {
if (extractor.write_data_block (buffer, offset) != Archive.Result.OK) {
break;
}
}
}
extract_archive_all(archive_path, target_path);
fs_sync ();
error (3);
}
Expand Down

0 comments on commit 6e6e0f1

Please sign in to comment.