#include #include #include #include #include "unzip_tool.h" #include "zip.h" #include "unzip.h" enum UnzipResult { UNZIP_OK, OPEN_ZIP_FILE_FAILED, GET_ZIP_INFO_FAILED, GET_FILE_INFO_FAILED, GO_TO_NEXT_FILE_FAILED, CREATE_DIRECTORY_FAILED, PATH_TOO_LONG, OPEN_ZIP_ENTRY_FAILED, READ_ZIP_ENTRY_FAILED, CLOSE_ZIP_ENTRY_FAILED, CLOSE_ZIP_FILE_FAILED, OTHER_ERROR, }; const int MAX_FILENAME_LEN = 8192; const int BUFFER_SIZE = 8192; int mkdirs(const char *dir); int dump_entry(unzFile file, const char *filename, const char *target_path) { int err = unzOpenCurrentFile(file); if (err != UNZ_OK) { printf("error: open zip entry %s failed\n", filename); return OPEN_ZIP_ENTRY_FAILED; } FILE *fp = fopen(target_path, "w"); if (fp == NULL) { printf("error: open file %s failed\n", target_path); return OTHER_ERROR; } char buf[BUFFER_SIZE]; while (true) { int size = unzReadCurrentFile(file, buf, BUFFER_SIZE); if (size > 0) { if (fwrite(buf, size, 1, fp) != 1) { printf("error: write to file %s failed\n", target_path); return OTHER_ERROR; } } else if (size == 0) { break; } else { printf("error: read zip entry %s failed\n", filename); return READ_ZIP_ENTRY_FAILED; } } if (fclose(fp) != 0) { printf("error: close file %s failed\n", target_path); return OTHER_ERROR; } if (unzCloseCurrentFile(file) != UNZ_OK) { printf("error: close zip entry %s failed\n", filename); return CLOSE_ZIP_ENTRY_FAILED; } return 0; } int unzip(const char *zip_path, const char *target_path) { unzFile file = unzOpen64(zip_path); if (file == NULL) { printf("error: open zip file %s failed\n", zip_path); return OPEN_ZIP_FILE_FAILED; } unz_global_info64 global_info; int err = unzGetGlobalInfo64(file, &global_info); if (err != UNZ_OK) { return GET_ZIP_INFO_FAILED; } char filename[MAX_FILENAME_LEN]; char path_buf[MAX_FILENAME_LEN]; int len = strlen(target_path); strncpy(path_buf, target_path, len); if (path_buf[len-1] != '/') { path_buf[len++] = '/'; } for (int i = 0; i < global_info.number_entry; ++i) { memset(filename, 0, sizeof(filename)); unz_file_info64 file_info; err = unzGetCurrentFileInfo64(file, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0); if (err != UNZ_OK) { return GET_FILE_INFO_FAILED; } int l = (int)strlen(filename); strncpy(path_buf + len, filename, l); path_buf[len+l] = '\0'; if (filename[l-1] == '/') { // this file is a directory err = mkdirs(path_buf); if (err != 0) { printf("error: create dir %s failed!!!\n", path_buf); return err; } } else { for (int i = len + l - 1; i > 0; --i) { if (path_buf[i] == '/') { path_buf[i] = '\0'; err = mkdirs(path_buf); if (err != 0) { printf("error: create dir %s failed!!!\n", path_buf); return err; } path_buf[i] = '/'; break; } } err = dump_entry(file, filename, path_buf); if (err != 0) { return err; } } err = unzGoToNextFile(file); if (err == UNZ_END_OF_LIST_OF_FILE) { break; } else if (err != UNZ_OK) { return GO_TO_NEXT_FILE_FAILED; } } if (unzClose(file) != UNZ_OK) { return CLOSE_ZIP_FILE_FAILED; } return UNZIP_OK; } int create_dir(const char *dir) { return mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); } int mkdirs(const char *dir) { DIR* d = opendir(dir); if (d != NULL) { return closedir(d); } char buf[MAX_FILENAME_LEN]; int len = (int)strlen(dir); if (len >= MAX_FILENAME_LEN) { printf("error: len of path %s exceed MAX_FILENAME_LEN %d\n", dir, MAX_FILENAME_LEN); return PATH_TOO_LONG; } strncpy(buf, dir, len); if (buf[len - 1] != '/') { buf[len++] = '/'; } buf[len] = '\0'; for (int i = 1; i < len; ++i) { if (buf[i] == '/') { buf[i] = '\0'; d = opendir(buf); if (d == NULL) { if (create_dir(buf) != 0) { return CREATE_DIRECTORY_FAILED; } } else { closedir(d); } buf[i] = '/'; } } return 0; }