summaryrefslogtreecommitdiff
path: root/app/bin/archive.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/archive.c')
-rw-r--r--app/bin/archive.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/app/bin/archive.c b/app/bin/archive.c
new file mode 100644
index 0000000..4e82bd3
--- /dev/null
+++ b/app/bin/archive.c
@@ -0,0 +1,454 @@
+/** \file archive.c
+ * ARCHIVE PROCESSING
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 Adam Richards and Martin Fischer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <zip.h>
+
+#ifdef WINDOWS
+ #include "include/dirent.h"
+ #include <direct.h>
+ #include <io.h>
+ #include <process.h>
+ #define unlink(a) _unlink((a))
+ #define rmdir(a) _rmdir((a))
+ #define open(name, flag, mode) _open((name), (flag), (mode))
+ #define write(file, buffer, count) _write((file),(buffer), (count))
+ #define close(file) _close((file))
+ #define getpid() _getpid()
+#else
+ #include <dirent.h>
+ #include <unistd.h>
+#endif
+
+#include <wlib.h>
+#include "archive.h"
+#include "directory.h"
+#include "dynstring.h"
+#include "i18n.h"
+#include "messages.h"
+#include "misc.h"
+#include "misc2.h"
+#include "paths.h"
+#include "include/utf8convert.h"
+
+int log_zip = 0;
+
+//char *
+//NativeToUtf8(const char *nativeString)
+//{
+//
+//#ifdef WINDOWS
+//
+// int cnt = 2 * (strlen(nativeString) + 1);
+// char *tempBuffer = MyMalloc( cnt );
+// char *destBuffer = MyMalloc( cnt );
+//
+// //// find the
+// //cnt = MultiByteToWideChar(CP_ACP,
+// // 0,
+// // nativeString,
+// // -1,
+// // tempBuffer,
+// // 0);
+//
+// //tempBuffer = realloc(tempBuffer, cnt * 2 + 4);
+//
+// // convert to wide character (UTF16)
+// MultiByteToWideChar(CP_ACP,
+// 0,
+// nativeString,
+// -1,
+// (LPWSTR)tempBuffer,
+// cnt);
+//
+// // convert from wide char to UTF-8
+// WideCharToMultiByte(CP_UTF8,
+// 0,
+// (LPCWCH)tempBuffer,
+// -1,
+// (LPSTR)destBuffer,
+// cnt,
+// NULL,
+// NULL);
+//
+// MyFree(tempBuffer);
+//#else
+// char * destBuffer = MyStrdup(nativeString);
+//#endif
+//
+// return(destBuffer);
+//}
+
+/**
+ * Create the full path for temporary directories used in zip archive operations
+ *
+ * \param archive operation
+ * \return pointer to full path, must be free'd by caller
+ */
+
+char *
+GetZipDirectoryName(enum ArchiveOps op)
+{
+ char *opDesc;
+ char *directory;
+ DynString zipDirectory;
+
+ DynStringMalloc(&zipDirectory, 0);
+
+ switch (op) {
+ case ARCHIVE_READ:
+ opDesc = "in";
+ break;
+ case ARCHIVE_WRITE:
+ opDesc = "out";
+ break;
+ default:
+ opDesc = "err";
+ break;
+ }
+
+ DynStringPrintf(&zipDirectory,
+ "%s" FILE_SEP_CHAR "zip_%s.%d",
+ workingDir,
+ opDesc,
+ getpid());
+
+ directory = strdup(DynStringToCStr(&zipDirectory));
+ DynStringFree(&zipDirectory);
+ return (directory);
+}
+
+/*****************************************************************************
+ * Add directory to archive
+ *
+ * \param IN zip The open zip archive handle
+ * \param IN dir_path The path to add
+ * \param IN prefix The prefix in the archive
+ *
+ * \returns TRUE if OK
+ */
+
+BOOL_T AddDirectoryToArchive(
+ struct zip * za,
+ const char * dir_path,
+ const char * prefix)
+{
+
+ char *full_path;
+ char *arch_path;
+ DIR *dir;
+ const char * buf;
+ struct stat stat_path, stat_entry;
+ struct dirent *entry;
+
+ zip_source_t * zt;
+
+ // stat for the path
+ stat(dir_path, &stat_path);
+
+ // if path does not exists or is not dir - exit with status -1
+ if (S_ISDIR(stat_path.st_mode) == 0) {
+ NoticeMessage(MSG_NOT_DIR_FAIL,
+ _("Continue"), NULL, dir_path);
+ return FALSE;
+ }
+
+ // if not possible to read the directory for this user
+ if ((dir = opendir(dir_path)) == NULL) {
+ NoticeMessage(MSG_OPEN_DIR_FAIL,
+ _("Continue"), NULL, dir_path);
+ return FALSE;
+ }
+
+ // iteration through entries in the directory
+ while ((entry = readdir(dir)) != NULL) {
+ // skip entries "." and ".."
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
+ continue;
+ }
+
+ // determinate a full path of an entry
+ MakeFullpath(&full_path, dir_path, entry->d_name, NULL);
+
+ // stat for the entry
+ stat(full_path, &stat_entry);
+
+ if (prefix && prefix[0]) {
+ MakeFullpath(&arch_path, prefix, entry->d_name, NULL);
+ } else {
+ MakeFullpath(&arch_path, entry->d_name, NULL);
+ }
+
+ // recursively add a nested directory
+ if (S_ISDIR(stat_entry.st_mode) != 0) {
+ if (zip_dir_add(za, arch_path, 0) < 0) {
+ zip_error_t *ziperr = zip_get_error(za);
+ buf = zip_error_strerror(ziperr);
+ NoticeMessage(MSG_ZIP_DIR_ADD_FAIL,
+ _("Continue"), NULL, arch_path, buf);
+#if DEBUG
+ printf("Added Directory %s \n", arch_path);
+#endif
+ }
+
+ if (AddDirectoryToArchive(za, full_path, arch_path) != TRUE) {
+ free(full_path);
+ free(arch_path);
+ return FALSE;
+ }
+ free(arch_path);
+ continue;
+ } else {
+ char *archPathUtf8 = MyStrdup(arch_path);
+ char *fullPathUtf8 = MyStrdup(full_path);
+#ifdef WINDOWS
+ archPathUtf8 = Convert2UTF8(archPathUtf8);
+ fullPathUtf8 = Convert2UTF8(fullPathUtf8);
+ ConvertPathForward(archPathUtf8);
+#endif // WINDOWS
+ zt = zip_source_file(za, fullPathUtf8, 0, -1);
+ if (zip_file_add(za, archPathUtf8, zt, ZIP_FL_ENC_UTF_8) == -1) {
+ zip_error_t *ziperr = zip_get_error(za);
+ buf = zip_error_strerror(ziperr);
+ NoticeMessage(MSG_ZIP_FILE_ADD_FAIL, _("Continue"), NULL, full_path, arch_path,
+ buf);
+ free(full_path);
+ free(arch_path);
+ MyFree(fullPathUtf8);
+ MyFree(archPathUtf8);
+ return FALSE;
+ }
+ MyFree(fullPathUtf8);
+ MyFree(archPathUtf8);
+#if DEBUG
+ printf("Added File %s", full_path);
+#endif
+ }
+ free(arch_path);
+ free(full_path);
+ }
+
+ closedir(dir);
+ return TRUE;
+}
+
+/***********************************************************************
+ * Create Archive
+ *
+ * \param IN dir_path The place to create the archive
+ * \param IN fileName The name of the archive
+ *
+ * \return TRUE if ok
+ */
+
+BOOL_T CreateArchive(
+ const char * dir_path,
+ const char * fileName)
+{
+ struct zip *za;
+ int err;
+ char buf[100];
+
+ char * archive = MyStrdup(fileName); // Because of const char
+ char * archive_name = FindFilename(archive);
+ char * archive_path;
+ char * archiveUtf8;
+
+ MakeFullpath(&archive_path, workingDir, archive_name, NULL);
+
+ archiveUtf8 = MyStrdup(archive_path);
+#ifdef WINDOWS
+ archiveUtf8 = Convert2UTF8(archiveUtf8);
+#endif // WINDOWS
+
+ MyFree(archive);
+
+ if ((za = zip_open(archiveUtf8, ZIP_CREATE, &err)) == NULL) {
+ zip_error_to_str(buf, sizeof(buf), err, errno);
+ NoticeMessage(MSG_ZIP_CREATE_FAIL, _("Continue"), NULL, archiveUtf8, buf);
+ MyFree(archiveUtf8);
+ return FALSE;
+ }
+#if DEBUG
+ printf("====================== \n");
+ printf("Started Archive %s", archive_path);
+#endif
+
+ AddDirectoryToArchive(za, dir_path, "");
+
+ if (zip_close(za) == -1) {
+ zip_error_to_str(buf, sizeof(buf), err, errno);
+ NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, archiveUtf8, buf);
+ free(archive_path);
+ MyFree(archiveUtf8);
+ return FALSE;
+ }
+
+ unlink(fileName); //Delete Old
+ if (rename(archive_path, fileName) == -1) { //Move zip into place
+ NoticeMessage(MSG_ZIP_RENAME_FAIL, _("Continue"), NULL, archiveUtf8, fileName,
+ strerror(errno));
+ free(archive_path);
+ MyFree(archiveUtf8);
+ return FALSE;
+ }
+ free(archive_path);
+ MyFree(archiveUtf8);
+
+#if DEBUG
+ printf("Moved Archive to %s", fileName);
+ printf("====================== \n");
+#endif
+ return TRUE;
+}
+
+/**************************************************************************
+ * Unpack_Archive_for
+ *
+ * \param IN pathName the name of the archive
+ * \param IN fileName just the filename and extension of the layout
+ * \param IN tempDir The directory to use to unpack into
+ *
+ * \returns TRUE if all worked
+ */
+BOOL_T UnpackArchiveFor(
+ const char * pathName, /*Full name of archive*/
+ const char * fileName, /*Layout name and extension */
+ const char * tempDir, /*Directory to unpack into */
+ BOOL_T file_only)
+{
+ char *dirName;
+ struct zip *za;
+ struct zip_file *zf;
+ struct zip_stat sb;
+ char buf[100];
+ int err;
+ int i;
+ int64_t len;
+ FILE *fd;
+ long long sum;
+
+ char *destBuffer = MyStrdup(pathName);
+#ifdef WINDOWS
+ destBuffer = Convert2UTF8(destBuffer);
+#endif // WINDOWS
+
+
+ if ((za = zip_open(destBuffer, 0, &err)) == NULL) {
+ zip_error_to_str(buf, sizeof(buf), err, errno);
+ NoticeMessage(MSG_ZIP_OPEN_FAIL, _("Continue"), NULL, pathName, buf);
+ fprintf(stderr, "xtrkcad: can't open xtrkcad zip archive `%s': %s \n",
+ pathName, buf);
+
+ MyFree(destBuffer);
+ return FALSE;
+ }
+
+ for (i = 0; i < zip_get_num_entries(za, 0); i++) {
+ if (zip_stat_index(za, i, 0, &sb) == 0) {
+ len = strlen(sb.name);
+
+#if DEBUG
+ printf("==================\n");
+ printf("Name: [%s], ", sb.name);
+ printf("Size: [%llu], ", sb.size);
+ printf("mtime: [%u]\n", (unsigned int)sb.mtime);
+ printf("mtime: [%u]\n", (unsigned int)sb.mtime);
+#endif
+
+ LOG(log_zip, 1, ("================= \n"))
+ LOG(log_zip, 1, ("Zip-Name [%s] \n", sb.name))
+ LOG(log_zip, 1, ("Zip-Size [%llu] \n", sb.size))
+ LOG(log_zip, 1, ("Zip-mtime [%u] \n", (unsigned int)sb.mtime))
+
+ if (sb.name[len - 1] == '/' && !file_only) {
+ MakeFullpath(&dirName, tempDir, &sb.name[0], NULL);
+ if (SafeCreateDir(dirName) != TRUE) {
+ free(dirName);
+ return FALSE;
+ }
+ free(dirName);
+ } else {
+ zf = zip_fopen_index(za, i, 0);
+ if (!zf) {
+ NoticeMessage(MSG_ZIP_INDEX_FAIL, _("Continue"), NULL);
+ fprintf(stderr, "xtrkcad zip archive open index error \n");
+ return FALSE;
+ }
+
+ if (file_only) {
+ if (strncmp(sb.name, fileName, strlen(fileName)) != 0) {
+ continue; /* Ignore any other files than the one we asked for */
+ }
+ }
+ MakeFullpath(&dirName, tempDir, &sb.name[0], NULL);
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(dirName);
+#endif // WINDOWS
+ fd = fopen(dirName, "wb");
+ if (!fd) {
+ NoticeMessage(MSG_ZIP_FILE_OPEN_FAIL, _("Continue"), NULL, dirName,
+ strerror(errno));
+ free(dirName);
+ return FALSE;
+ }
+
+ sum = 0;
+ while (sum != sb.size) {
+ len = zip_fread(zf, buf, 100);
+ if (len < 0) {
+ NoticeMessage(MSG_ZIP_READ_FAIL, _("Continue"), NULL, dirName, &sb.name[0]);
+ free(dirName);
+ fclose(fd);
+ return FALSE;
+ }
+ fwrite(buf, 1, (unsigned int)len, fd);
+ sum += len;
+ }
+ fclose(fd);
+ free(dirName);
+ zip_fclose(zf);
+ }
+ } else {
+ LOG(log_zip, 1, ("Zip-Unknown File[%s] Line[%d] \n", __FILE__, __LINE__))
+#if DEBUG
+ printf("File[%s] Line[%d]\n", __FILE__, __LINE__);
+#endif
+ }
+ }
+
+ MyFree(destBuffer);
+
+ if (zip_close(za) == -1) {
+ NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, dirName, &sb.name[0]);
+ return FALSE;
+ }
+ return TRUE;
+}
+