summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Buren <braewoods+rb@braewoods.net>2021-07-11 05:14:20 +0000
committerJames Buren <braewoods+rb@braewoods.net>2021-07-11 05:14:20 +0000
commit8846e087c09c28a2dfb731d7c873f113bc899940 (patch)
treec3b9f2196b12b75bad8fede2226f47188f944ea0
parenta1bcca645bbe10f74cb4888b0f22a0f33637c794 (diff)
downloadrockbox-8846e087c09c28a2dfb731d7c873f113bc899940.tar.gz
rockbox-8846e087c09c28a2dfb731d7c873f113bc899940.zip
zip: implement zip extraction support
This adds code sufficient to extract files to available storage given a suitable root directory to extract to. It works on an already open zip handle and also supports chain-loading a secondary callback in the event that integration into the process is desired. Change-Id: Id200d8f20d84a0cbd22906470de8bbd21d4525ef
-rw-r--r--firmware/common/zip.c178
-rw-r--r--firmware/include/zip.h4
2 files changed, 182 insertions, 0 deletions
diff --git a/firmware/common/zip.c b/firmware/common/zip.c
index c2e5da6651..84b94c4fb9 100644
--- a/firmware/common/zip.c
+++ b/firmware/common/zip.c
@@ -22,9 +22,12 @@
22#include "zip.h" 22#include "zip.h"
23#include <string.h> 23#include <string.h>
24#include "file.h" 24#include "file.h"
25#include "dir.h"
25#include "system.h" 26#include "system.h"
27#include "errno.h"
26#include "core_alloc.h" 28#include "core_alloc.h"
27#include "timefuncs.h" 29#include "timefuncs.h"
30#include "pathfuncs.h"
28#include "crc32.h" 31#include "crc32.h"
29#include "rbendian.h" 32#include "rbendian.h"
30 33
@@ -157,6 +160,16 @@ struct zip_mem {
157 off_t mem_size; 160 off_t mem_size;
158}; 161};
159 162
163struct zip_extract {
164 zip_callback cb;
165 void* ctx;
166 size_t name_offset;
167 size_t name_size;
168 char* name;
169 int file;
170 char path[MAX_PATH];
171};
172
160static int zip_read_ed(struct zip* z) { 173static int zip_read_ed(struct zip* z) {
161 const off_t file_size = z->size(z); 174 const off_t file_size = z->size(z);
162 const off_t max_size = sizeof(struct zip_ed_disk) + ZIP_MAX_LENGTH; 175 const off_t max_size = sizeof(struct zip_ed_disk) + ZIP_MAX_LENGTH;
@@ -606,6 +619,100 @@ static void zip_mem_init(struct zip_mem* z, int zip_handle, int mem_handle, cons
606 z->mem_size = mem_size; 619 z->mem_size = mem_size;
607} 620}
608 621
622static int zip_extract_start(const struct zip_args* args, struct zip_extract* ze) {
623 size_t name_length;
624 const char* dir;
625 size_t dir_length;
626
627 if ((name_length = strlcpy(ze->name, args->name, ze->name_size)) >= ze->name_size)
628 return 5;
629
630 if ((dir_length = path_dirname(ze->name, &dir)) > 0) {
631 char c = ze->name[dir_length];
632
633 ze->name[dir_length] = '\0';
634
635 if (!dir_exists(ze->path)) {
636 const char* path = ze->name;
637 const char* name;
638
639 while (parse_path_component(&path, &name) > 0) {
640 size_t offset = path - ze->name;
641 char c = ze->name[offset];
642
643 ze->name[offset] = '\0';
644
645 if (mkdir(ze->path) < 0 && errno != EEXIST)
646 return 6;
647
648 ze->name[offset] = c;
649 }
650 }
651
652 ze->name[dir_length] = c;
653 }
654
655 if (ze->name[name_length - 1] == PATH_SEPCH) {
656 if (mkdir(ze->path) < 0 && errno != EEXIST)
657 return 7;
658
659 return 0;
660 }
661
662 if ((ze->file = creat(ze->path, 0666)) < 0)
663 return 8;
664
665 return 0;
666}
667
668static int zip_extract_data(const struct zip_args* args, struct zip_extract* ze) {
669 if (write(ze->file, args->block, args->block_size) != (ssize_t) args->block_size) {
670 return 9;
671 }
672
673 return 0;
674}
675
676static int zip_extract_end(const struct zip_args* args, struct zip_extract* ze) {
677 int rv;
678
679 if (ze->file >= 0) {
680 rv = close(ze->file);
681
682 ze->file = -1;
683
684 if (rv < 0)
685 return 10;
686 }
687
688 if (modtime(ze->path, args->mtime) < 0)
689 return 11;
690
691 return 0;
692}
693
694static int zip_extract_callback(const struct zip_args* args, int pass, void* ctx) {
695 struct zip_extract* ze = ctx;
696 int rv;
697
698 if (ze->cb != NULL && (rv = ze->cb(args, pass, ze->ctx)) != 0)
699 return rv;
700
701 switch (pass) {
702 case ZIP_PASS_START:
703 return zip_extract_start(args, ze);
704
705 case ZIP_PASS_DATA:
706 return zip_extract_data(args, ze);
707
708 case ZIP_PASS_END:
709 return zip_extract_end(args, ze);
710
711 default:
712 return 1;
713 }
714}
715
609struct zip* zip_open(const char* name, bool try_mem) { 716struct zip* zip_open(const char* name, bool try_mem) {
610 int file = -1; 717 int file = -1;
611 int mem_handle = -1; 718 int mem_handle = -1;
@@ -692,6 +799,77 @@ read_entries:
692 return zip_read_entries(z); 799 return zip_read_entries(z);
693} 800}
694 801
802int zip_extract(struct zip* z, const char* root, zip_callback cb, void* ctx) {
803 int rv;
804 int ze_handle = -1;
805 struct zip_extract* ze;
806 char* path;
807 size_t size;
808 size_t length;
809
810 if (root == NULL || root[0] == '\0')
811 root = PATH_ROOTSTR;
812
813 if (root[0] != PATH_SEPCH) {
814 rv = -1;
815 goto bail;
816 }
817
818 if (!dir_exists(root)) {
819 rv = 1;
820 goto bail;
821 }
822
823 if ((ze_handle = zip_core_alloc(sizeof(struct zip_extract))) < 0) {
824 rv = 2;
825 goto bail;
826 }
827
828 ze = core_get_data(ze_handle);
829 ze->cb = cb;
830 ze->ctx = ctx;
831 ze->file = -1;
832
833 path = ze->path;
834 size = sizeof(ze->path);
835 length = strlcpy(path, root, size);
836
837 if (length >= size) {
838 rv = 3;
839 goto bail;
840 }
841
842 path += length;
843 size -= length;
844
845 if (path[-1] != PATH_SEPCH) {
846 length = strlcpy(path, PATH_SEPSTR, size);
847
848 if (length >= size) {
849 rv = 4;
850 goto bail;
851 }
852
853 path += length;
854 size -= length;
855 }
856
857 ze->name_offset = path - ze->path;
858 ze->name_size = size;
859 ze->name = path;
860
861 rv = zip_read_deep(z, zip_extract_callback, ze);
862
863bail:
864 if (ze_handle >= 0) {
865 if (ze->file >= 0)
866 close(ze->file);
867
868 core_free(ze_handle);
869 }
870 return rv;
871}
872
695void zip_close(struct zip* z) { 873void zip_close(struct zip* z) {
696 if (z == NULL) 874 if (z == NULL)
697 return; 875 return;
diff --git a/firmware/include/zip.h b/firmware/include/zip.h
index f6870a53d2..70d225cfd7 100644
--- a/firmware/include/zip.h
+++ b/firmware/include/zip.h
@@ -58,6 +58,10 @@ int zip_read_shallow(struct zip* z, zip_callback cb, void* ctx);
58// this can also pickup where a successful shallow read leftoff 58// this can also pickup where a successful shallow read leftoff
59int zip_read_deep(struct zip* z, zip_callback cb, void* ctx); 59int zip_read_deep(struct zip* z, zip_callback cb, void* ctx);
60 60
61// extract the contents to an existing directory
62// this can also pickup where a successful shallow read leftoff
63int zip_extract(struct zip* z, const char* root, zip_callback cb, void* ctx);
64
61// returns system resources 65// returns system resources
62void zip_close(struct zip* z); 66void zip_close(struct zip* z);
63 67