summaryrefslogtreecommitdiff
path: root/zip/zip.cpp
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-08 11:04:43 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-08 11:04:43 +0200
commit16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d (patch)
tree3d22f54f7298f81b18ed66d05a62fa8bfab359ab /zip/zip.cpp
downloadtuxcmd-modules-16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d.tar.xz
Diffstat (limited to 'zip/zip.cpp')
-rw-r--r--zip/zip.cpp980
1 files changed, 980 insertions, 0 deletions
diff --git a/zip/zip.cpp b/zip/zip.cpp
new file mode 100644
index 0000000..76e2513
--- /dev/null
+++ b/zip/zip.cpp
@@ -0,0 +1,980 @@
+/* ZIP plugin for Tux Commander
+ * version 0.4.5, designed for ZipArchive v3.2.0
+ * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ * Check for updates on tuxcmd.sourceforge.net
+ *
+ * Uses ZipArchive library
+ * Copyright (C) 2000 - 2007 Artpol Software - Tadeusz Dracz
+ * http://www.artpol-software.com/ZipArchive/
+ *
+
+
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "vfs_types.h"
+#include "strutils.h"
+#include "vfsutils.h"
+#include "treepathutils.h"
+#include "treepath_vfs.h"
+
+#include "ZipArchive.h"
+#include "ZipPlatform.h"
+#include "ZipCallback.h"
+
+
+
+#define VERSION "0.4.5"
+#define BUILD_DATE "2008-02-09"
+#define DEFAULT_BLOCK_SIZE 65536
+
+
+using namespace std;
+extern "C" {
+
+
+/******************************************************************************************************/
+/** Utilities */
+/************** ****************/
+
+TVFSResult get_vfs_errorcode(int m_iCause)
+{
+ switch (m_iCause) {
+ case 13: return cVFS_WriteErr; // Permission denied
+ case CZipException::noError: return cVFS_WriteErr; // No error.
+ case CZipException::genericError: return cVFS_WriteErr; // An unknown error.
+ case CZipException::badZipFile: return cVFS_ReadErr; // Damaged or not a zip file.
+ case CZipException::badCrc: return cVFS_ReadErr; // Crc is mismatched.
+ case CZipException::noCallback: return cVFS_Failed; // There is no spanned archive callback object set.
+ case CZipException::aborted: return cVFS_Failed; // The disk change callback method returned false.
+ case CZipException::abortedAction: return cVFS_Failed; // The action callback method returned false.
+ case CZipException::abortedSafely: return cVFS_Failed; // The action callback method returned false, but the data is not corrupted.
+ case CZipException::nonRemovable: return cVFS_WriteErr; // The device selected for the spanned archive is not removable.
+ case CZipException::tooManyVolumes: return cVFS_WriteErr; // The limit of the maximum volumes reached.
+ case CZipException::tooManyFiles: return cVFS_ReadErr; // The limit of the maximum files in an archive reached.
+ case CZipException::tooLongData: return cVFS_ReadErr; // The filename, the comment or the local or central extra field of the file added to the archive is too long.
+ case CZipException::tooBigSize: return cVFS_ReadErr; // The file size is too large to be supported.
+ case CZipException::badPassword: return cVFS_ReadErr; // An incorrect password set for the file being decrypted.
+ case CZipException::dirWithSize: return cVFS_ReadErr; // The directory with a non-zero size found while testing.
+ case CZipException::internalError: return cVFS_WriteErr; // An internal error.
+ case CZipException::notRemoved: return cVFS_WriteErr; // Error while removing a file
+ case CZipException::notRenamed: return cVFS_WriteErr; // Error while renaming a file (under Windows call GetLastError() to find out more).
+ case CZipException::platfNotSupp: return cVFS_WriteErr; // Cannot create a file for the specified platform.
+ case CZipException::cdirNotFound: return cVFS_ReadErr; // The central directory was not found in the archive (or you were trying to open not the last disk of a segmented archive).
+// case CZipException::cdir64NotFound: return cVFS_ReadErr; // The Zip64 central directory signature was not found in the archive where expected.
+// case CZipException::noBBZInZip64: return cVFS_ReadErr; // The number of bytes before a zip archive must be zero in the Zip64 format.
+// case CZipException::badAesAuthCode: return cVFS_ReadErr; // Mismatched authentication code in WinZip AEC decrypted data.
+ case CZipException::noZip64: return cVFS_ReadErr; // The Zip64 format has not been enabled for the library, but is required to open the archive.
+ case CZipException::noAES: return cVFS_ReadErr; // WinZip AES encryption has not been enabled for the library, but is required to decompress the archive.
+ case CZipException::outOfBounds: return cVFS_ReadErr; // The collection is empty and the bounds do not exist.
+// case CZipException::mutexError: return cVFS_ReadErr; // Locking or unlocking resources access was unsuccessful.
+ case CZipException::streamEnd: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::needDict: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::errNo: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::streamError: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::dataError: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::memError: return cVFS_ReadErr; // Zlib library or CZipMemFile error.
+ case CZipException::bufError: return cVFS_ReadErr; // Zlib library error.
+ case CZipException::versionError: return cVFS_ReadErr; // Zlib library error.
+// case CZipException::bzSequenceError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzParamError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzMemError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzDataError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzDataErrorMagic: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzIoError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzUnexpectedEof: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzOutbuffFull: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzConfigError: return cVFS_ReadErr; // Bzlib library error.
+// case CZipException::bzInternalError: return cVFS_ReadErr; // Internal Bzlib library error.
+ default: return cVFS_WriteErr;
+ }
+ return cVFS_Failed; // Default error
+}
+
+
+
+/******************************************************************************************************/
+/** Auxiliary classes */
+/************** ****************/
+
+// Define the progress class and the class methods
+struct ZIP_API CVFSZipActionCallback : public CZipActionCallback
+{
+ CVFSZipActionCallback()
+ {
+ m_uTotalToProcess = 0;
+ m_uProcessed = 0;
+ pCallBackProgress = NULL;
+ data = NULL;
+ }
+
+ TVFSCopyCallBackFunc pCallBackProgress;
+ void *data;
+
+ virtual bool Callback(ZIP_SIZE_TYPE uProgress)
+ {
+ fprintf(stderr, "(II) Callback called, position = %lu; m_uTotalToProcess = %lu; m_uProcessed = %lu\n",
+ uProgress, m_uTotalToProcess, m_uProcessed);
+ bool ret = true;
+ try {
+ if (pCallBackProgress != NULL) ret = pCallBackProgress(m_uProcessed, m_uTotalToProcess, data);
+ }
+ catch (...) {
+ fprintf(stderr, "(EE) extract_callback: Fatal error occured when calling pCallBackProgress\n");
+ }
+ return ret;
+ }
+};
+
+
+struct TVFSGlobs {
+ TVFSLogFunc log_func;
+ char *curr_dir;
+ char *archive_path;
+
+ gboolean need_password;
+
+ CZipArchive *zip;
+ CVFSZipActionCallback *extract_callback;
+
+ bool archive_opened;
+ unsigned long block_size;
+ bool archive_modified;
+
+ struct PathTree *files;
+ struct VfsFilelistData *vfs_filelist;
+};
+
+
+
+/***********************************************************************************************************************
+* Internal tree functions
+********/
+
+void build_global_filelist(struct TVFSGlobs *globs)
+{
+ int iCount = globs->zip->GetCount();
+ // Ensure the filelist is freed
+ if (globs->files) filelist_tree_free(globs->files);
+
+ globs->files = filelist_tree_new();
+ vfs_filelist_set_files(globs->vfs_filelist, globs->files);
+
+ // list files in archive
+ for (int i = 0; i < iCount; i++) {
+ CZipFileHeader *fh = globs->zip->GetFileInfo(i);
+ if (fh != NULL)
+ printf(" No: %i, '%s', IsDir: %i, Size: %lu, SystemAttr = 0x%lX, OriginalAttr = 0x%lX, encrypted = %d\n",
+ i, (LPCTSTR)fh->GetFileName(), fh->IsDirectory(), fh->m_uUncomprSize, fh->GetSystemAttr(), fh->GetOriginalAttributes(), fh->IsEncrypted());
+ }
+ printf("\n\n");
+
+ for (int i = 0; i < iCount; i++) {
+ CZipFileHeader *fh = globs->zip->GetFileInfo(i);
+ if (fh != NULL) {
+ // Create a TVFSItem entry and fill all info
+ struct TVFSItem *item = (struct TVFSItem*)malloc(sizeof(struct TVFSItem));
+ memset(item, 0, sizeof(struct TVFSItem));
+
+ item->iSize = (u_int64_t)fh->m_uUncomprSize;
+ if (fh->IsDirectory())
+ item->ItemType = vDirectory;
+ else item->ItemType = vRegular;
+ item->iMode = fh->GetSystemAttr();
+ item->iUID = geteuid();
+ item->iGID = getegid();
+ item->m_time = (__time_t)fh->GetTime();
+ item->c_time = item->m_time;
+ item->a_time = item->m_time;
+
+ if (fh->IsEncrypted()) globs->need_password = TRUE;
+
+ // Add item to the global list and continue with next file
+ filelist_tree_add_item(globs->files, (LPCTSTR)fh->GetFileName(), item, i + 1);
+ printf("\n");
+ }
+ }
+
+ if (globs->need_password) printf("Password present.\n");
+
+ printf("\n\n\n\nPrinting the contents of the global filelist:\n\n");
+ filelist_tree_print(globs->files);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Basic initialization functions
+
+int VFSAllocNeeded()
+{
+ return sizeof(struct TVFSGlobs);
+}
+
+void VFSInit(struct TVFSGlobs *globs, TVFSLogFunc log_func)
+{
+ globs->archive_opened = false;
+ globs->block_size = DEFAULT_BLOCK_SIZE;
+ globs->archive_modified = false;
+ globs->need_password = FALSE;
+
+ globs->log_func = log_func;
+ if (globs->log_func != NULL) globs->log_func((char*)"zip plugin: VFSInit");
+}
+
+void VFSDestroy(struct TVFSGlobs *globs)
+{
+ if (globs->log_func != NULL) globs->log_func((char*)"zip plugin: VFSDestroy");
+}
+
+int VFSVersion()
+{
+ return 3;
+}
+
+TVFSInfo VFSGetInfo()
+{
+ TVFSInfo module_info;
+ module_info.Name = "ZIP plugin";
+ module_info.Description = "ZIP archiving plugin";
+ char *s = (char*)malloc(255);
+ snprintf(s, 255, "version %s, build date: %s\nusing ZipArchive library v%s\n", VERSION, BUILD_DATE, CZipArchive::m_gszVersion);
+ module_info.About = strdup(s);
+ free(s);
+ s = (char*)malloc(255);
+ snprintf(s, 255, "Plugin Copyright (C) 2008 Tomáš Bžatek\n%s", CZipArchive::m_gszCopyright);
+ module_info.Copyright = strdup(s);
+ return module_info;
+}
+
+char *VFSGetPrefix(struct TVFSGlobs *globs)
+{
+// return "zip";
+ return globs->archive_path;
+}
+
+char *VFSGetExts()
+{
+ return (char*)"zip";
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+TVFSResult VFSOpen(struct TVFSGlobs *globs, char *sName)
+{
+ // Initialize the objects
+ globs->files = NULL;
+ globs->vfs_filelist = vfs_filelist_new(NULL);
+
+ globs->curr_dir = NULL;
+ globs->zip = new CZipArchive;
+
+ try
+ {
+ fprintf(stderr, "(--) VFSOpen: trying to open the file...\n");
+
+ try {
+ if (! globs->zip->Open(sName, CZipArchive::zipOpen, 0)) {
+ printf("(EE) VFSOpen: error opening zip archive\n");
+ return cVFS_Failed;
+ }
+ }
+ catch (...) {
+ printf("(!!) VFSOpen: error opening readwrite zip, trying readonly...\n");
+ try {
+ // try to open in read only mode (required if there's no write access on the media)
+ if (! globs->zip->Open(sName, CZipArchive::zipOpenReadOnly, 0)) {
+ printf("(EE) VFSOpen: error opening readonly zip archive\n");
+ return cVFS_Failed;
+ }
+ }
+ catch (...) {
+ printf("(EE) VFSOpen: error opening readonly zip\n");
+ return cVFS_Failed;
+ }
+ }
+ int iCount = globs->zip->GetCount(false);
+ printf("(II) VFSOpen: %i records found, %i files.\n", iCount, globs->zip->GetCount(true));
+ if (iCount < 1) return cVFS_Failed;
+
+ // Build the global file list
+ build_global_filelist(globs);
+
+ // Set the progress callback
+ globs->extract_callback = new CVFSZipActionCallback;
+ globs->zip->SetCallback(globs->extract_callback, CZipActionCallback::cbExtract);
+ globs->zip->SetCallback(globs->extract_callback, CZipActionCallback::cbAdd);
+
+ // Set automatic flushing of changes to disk
+ globs->zip->SetAutoFlush(true);
+ }
+ catch (CZipException e) {
+ printf ("(EE) VFSOpen: Error while processing archive %s\n%s\n", (LPCTSTR) sName, (LPCTSTR)e.GetErrorDescription());
+ if (e.m_szFileName.IsEmpty()) printf("\n");
+ else printf("(EE) VFSOpen: Filename in error object: %s\n\n", (LPCTSTR)e.m_szFileName);
+ globs->zip->Close(true);
+ return cVFS_Failed;
+ }
+ catch (...) {
+ printf ("(EE) VFSOpen: Unknown error while processing archive %s\n\n", (LPCTSTR) sName);
+ globs->zip->Close(true);
+ return cVFS_Failed;
+ }
+
+ globs->archive_path = strdup(sName);
+ globs->archive_modified = false;
+ return cVFS_OK;
+}
+
+
+TVFSResult VFSClose(struct TVFSGlobs *globs)
+{
+ if (globs) {
+ // Closing the archive...
+ fprintf(stderr, "(II) VFSClose: Closing the archive...\n");
+ try {
+ if (globs->archive_modified) globs->zip->Flush();
+ globs->zip->Close(CZipArchive::afNoException, false);
+ //*** In case of inconsistency, try using afWriteDir value
+ // (Use when an exception was thrown. The Close method writes the
+ // central directory structure to the archive, so that the archive should be usable.)
+ }
+ catch (CZipException e) {
+ fprintf(stderr, "(EE) VFSClose: Error while closing archive: %s\n", (LPCTSTR)e.GetErrorDescription());
+ return cVFS_Failed;
+ }
+
+
+ // Freeing the ZIP objects...
+ fprintf(stderr, "(II) VFSClose: Freeing ZipArchive objects...\n");
+ try {
+ delete globs->extract_callback;
+ delete globs->zip;
+ }
+ catch (...) {
+ fprintf(stderr, "(EE) VFSClose: Error freeing ZipArchive objects\n");
+ return cVFS_Failed;
+ }
+
+ // Freeing the filelist
+ fprintf(stderr, "(II) VFSClose: Freeing filelist...\n");
+ if (globs->vfs_filelist) vfs_filelist_free(globs->vfs_filelist);
+ if (globs->files) filelist_tree_free(globs->files);
+
+ // Free the rest...
+ free(globs->archive_path);
+ }
+ return cVFS_OK;
+}
+
+char *VFSGetPath(struct TVFSGlobs *globs)
+{
+ return globs->curr_dir;
+}
+
+u_int64_t VFSGetFileSystemFree(struct TVFSGlobs *globs, char *APath)
+{
+ return 0;
+}
+
+u_int64_t VFSGetFileSystemSize(struct TVFSGlobs *globs, char *APath)
+{
+ return globs->zip->GetOccupiedSpace();
+}
+
+
+
+
+/******************************************************************************************************/
+
+TVFSResult VFSChangeDir(struct TVFSGlobs *globs, char *NewPath)
+{
+ if (NewPath == NULL) {
+ printf("(EE) VFSChangeDir: NewPath is NULL!\n");
+ return cVFS_Failed;
+ }
+
+ globs->curr_dir = vfs_filelist_change_dir(globs->vfs_filelist, NewPath);
+ if (globs->curr_dir) return cVFS_OK;
+ else return cVFS_Failed;
+}
+
+int VFSLogin(struct TVFSGlobs *globs, char *user, char *pass)
+{
+ return cVFS_Not_Supported;
+}
+
+int VFSSetPassword(struct TVFSGlobs *globs, char *pass)
+{
+ printf ("(II) VFSSetPassword: Going to set the password...\n");
+ try {
+ globs->zip->SetPassword(pass);
+ }
+ catch (...)
+ {
+ printf ("(EE) VFSSetPassword: Changing password failed. Maybe closed archive ?\n");
+ return cVFS_Failed;
+ }
+ return cVFS_OK;
+}
+
+int VFSGetPasswordRequired(struct TVFSGlobs *globs)
+{
+ if (globs) return globs->need_password;
+ return FALSE;
+}
+
+
+/******************************************************************************************************/
+
+TVFSResult VFSListFirst(struct TVFSGlobs *globs, char *sDir, struct TVFSItem *Item)
+{
+ if (sDir == NULL) {
+ printf("(EE) VFSListFirst: sDir is NULL!\n");
+ return cVFS_Failed;
+ }
+ printf ("(--) VFSListFirst: Going to list all items in '%s'\n", sDir);
+
+ return vfs_filelist_list_first(globs->vfs_filelist, sDir, Item);
+}
+
+TVFSResult VFSListNext(struct TVFSGlobs *globs, char *sDir, struct TVFSItem *Item)
+{
+ return vfs_filelist_list_next(globs->vfs_filelist, sDir, Item);
+}
+
+TVFSResult VFSListClose(struct TVFSGlobs *globs)
+{
+ return vfs_filelist_list_close(globs->vfs_filelist);
+}
+
+
+/******************************************************************************************************/
+long VFSFileExists(struct TVFSGlobs *globs, const char *FileName, const long Use_lstat)
+{
+ if (! globs) return FALSE;
+ return vfs_filelist_file_exists(globs->vfs_filelist, FileName, Use_lstat);
+}
+
+TVFSResult VFSFileInfo(struct TVFSGlobs *globs, char *AFileName, struct TVFSItem *Item)
+{
+ printf("(--) VFSFileInfo: requested info for object '%s'\n", AFileName);
+ if (!globs) return cVFS_Failed;
+ return vfs_filelist_file_info(globs->vfs_filelist, AFileName, Item);
+}
+
+/******************************************************************************************************/
+/** Recursive tree size counting */
+/************** ****************/
+
+u_int64_t VFSGetDirSize(struct TVFSGlobs *globs, char *APath)
+{
+ if (! globs) return 0;
+ return vfs_filelist_get_dir_size(globs->vfs_filelist, APath);
+}
+
+void VFSBreakGetDirSize(struct TVFSGlobs *globs)
+{
+ printf("(WW) VFSBreakGetDirSize: calling break\n");
+ if (globs) vfs_filelist_get_dir_size_break(globs->vfs_filelist);
+}
+
+
+/******************************************************************************************************/
+/** Methods modifying the archive */
+/************** ****************/
+
+TVFSResult VFSMkDir(struct TVFSGlobs *globs, const char *sDirName)
+{
+ if ((sDirName == NULL) || (strlen(sDirName) < 1)) {
+ printf("(EE) VFSMkDir: The value of 'sDirName' is NULL or empty\n");
+ return cVFS_Failed;
+ }
+ if ((strlen(sDirName) < 1) || (strcmp(sDirName, "/") == 0)) {
+ printf("(EE) VFSMkDir: Invalid value '%s' (duplicate root entry?)\n", sDirName);
+ return cVFS_Failed;
+ }
+ printf ("(II) VFSMkDir: Going to create new directory '%s'...\n", sDirName);
+
+ try {
+ try {
+ CZipFileHeader header;
+// globs->zip->SetFileHeaderAttr(header, 0x41ED0010); // alternatively use ZipPlatform::GetDefaultAttributes();
+ globs->zip->SetFileHeaderAttr(header, 0x41ED); // alternatively use ZipPlatform::GetDefaultAttributes();
+ char *s = exclude_leading_path_sep(sDirName);
+ header.SetFileName(s);
+ free(s);
+ header.SetTime(time(NULL));
+ bool bRet = globs->zip->OpenNewFile(header, 0, NULL);
+ globs->zip->CloseNewFile();
+ if (! bRet) {
+ printf("(EE) VFSMkDir: Error creating new directory '%s'\n", sDirName);
+ return cVFS_Failed;
+ }
+ globs->archive_modified = true;
+ build_global_filelist(globs);
+ return cVFS_OK;
+ }
+ catch (CZipException e) {
+ globs->zip->CloseNewFile(true);
+ fprintf(stderr, "(EE) VFSMkDir: Error creating new directory '%s': [%d] %s, archive closed = %d.\n",
+ sDirName, e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ printf("(EE) VFSMkDir: Error creating new directory '%s'\n", sDirName);
+ return cVFS_Failed;
+ }
+}
+
+TVFSResult VFSRemove(struct TVFSGlobs *globs, const char *APath)
+{
+ printf("(II) VFSRemove: Going to remove the file '%s'...\n", APath);
+
+ char *AFile = exclude_trailing_path_sep(APath);
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, AFile) - 1;
+ free(AFile);
+
+ if (file_no < 0) {
+ printf("(EE) VFSRemove: can't find the file specified: '%s'\n", APath);
+ return cVFS_Failed;
+ }
+
+ try {
+ try {
+ if (! globs->zip->RemoveFile(file_no)) {
+ printf("(EE) VFSRemove: Delete file '%s' failed.\n", APath);
+ return cVFS_Failed;
+ }
+ build_global_filelist(globs);
+ globs->archive_modified = true;
+ printf("(II) VFSRemove OK.\n");
+
+ // Test for the sparse ZIP central directory
+ char *AFile1 = exclude_trailing_path_sep(APath);
+ char *AFile2 = g_path_get_dirname(AFile1);
+ char *AFile3 = exclude_trailing_path_sep(AFile2);
+ if ((strlen(AFile3) > 0) && (strcmp(AFile3, "/") != 0)) {
+ printf("(II) VFSRemove: AFile1: '%s', AFile2: '%s', AFile3: '%s'\n", AFile1, AFile2, AFile3);
+ file_no = filelist_find_index_by_path(globs->files, AFile2) - 1;
+ printf("(II) VFSRemove: deleted: '%s', parent: '%s', file_no = %ld\n", APath, AFile3, file_no);
+ if (file_no < 0) {
+ printf("(WW) VFSRemove: sparse ZIP archive detected, adding empty directory: '%s'\n", AFile3);
+ VFSMkDir(globs, AFile3);
+ }
+ }
+ free(AFile1); free(AFile2); free(AFile3);
+
+ return cVFS_OK;
+ }
+ catch (CZipException e) {
+ fprintf(stderr, "(EE) VFSRemove: Delete file '%s' failed: [%d] %s, archive closed = %d.\n",
+ APath, e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ printf("(EE) VFSRemove: Delete file '%s' failed.\n", APath);
+ return cVFS_Failed;
+ }
+}
+
+TVFSResult VFSRename(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName)
+{
+ printf ("(II) VFSRename: Going to rename/move the file '%s' to '%s'...\n", sSrcName, sDstName);
+
+ char *AFile = exclude_trailing_path_sep(sSrcName);
+ char *ADestFile = exclude_trailing_path_sep(sDstName);
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, AFile) - 1;
+ free(AFile);
+
+ if (file_no < 0) {
+ printf("(EE) VFSRename: can't find the file specified: '%s'\n", sSrcName);
+ return cVFS_Failed;
+ }
+
+ try {
+ try {
+ if (! globs->zip->RenameFile(file_no, ADestFile)) {
+ printf ("(EE) VFSRename: Rename/move file '%s' failed.\n", sSrcName);
+ return cVFS_Failed;
+ }
+ free(ADestFile);
+ build_global_filelist(globs);
+ globs->archive_modified = true;
+ return cVFS_OK;
+ }
+ catch (CZipException e) {
+ fprintf(stderr, "(EE) VFSRename: Rename/move file '%s' failed: [%d] %s, archive closed = %d.\n",
+ sSrcName, e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ printf ("(EE) VFSRename: Rename/move file failed.\n");
+ return cVFS_Failed;
+ }
+}
+
+TVFSResult VFSMakeSymLink(struct TVFSGlobs *globs, const char *NewFileName, const char *PointTo)
+{
+ fprintf(stderr, "(EE) VFSMakeSymLink: Symbolic links not supported in ZIP archives.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChmod(struct TVFSGlobs *globs, const char *FileName, const uint Mode)
+{
+ printf("(II) VFSChmod: Going to change permissions of the file '%s'...\n", FileName);
+
+ char *AFile = exclude_trailing_path_sep(FileName);
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, AFile) - 1;
+ free(AFile);
+
+ if (file_no < 0) {
+ printf("(EE) VFSChmod: can't find the file specified: '%s'\n", FileName);
+ return cVFS_Failed;
+ }
+
+ try {
+ try {
+ // Set system compatibility first
+ if (! globs->zip->SetSystemCompatibility(ZipCompatibility::zcUnix)) {
+ printf("(EE) VFSChmod: Unable to set system compatibility\n");
+ }
+
+ // Change the header data
+ globs->zip->ReadLocalHeader(file_no);
+ CZipFileHeader *header = globs->zip->GetFileInfo(file_no);
+ if (! header) {
+ printf("(EE) VFSChmod: Permissions modification of the file '%s' failed: NULL returned by GetFileInfo()\n", FileName);
+ return cVFS_Failed;
+ }
+ // We need to change only 0xF000FFFF mask
+ // The 0xF_______ bits represents file/directory type, the 0x____FFFF represents ZIP attributes and 0x_FFF____ represents unix permissions
+
+// printf("(II) VFSChmod: Current permissions: %lX, stripped: %lX, setting to: %X, modified: %lX\n",
+// header->GetSystemAttr(), header->GetSystemAttr() & 0xF000FFFF, Mode & 0xFFF, (header->GetSystemAttr() & 0xF000FFFF) + ((Mode & 0xFFF) << 16));
+// globs->zip->SetFileHeaderAttr(*header, (header->GetSystemAttr() & 0xF000FFFF) + ((Mode & 0xFFF) << 16));
+
+ printf("(II) VFSChmod: Current permissions: 0x%lX, stripped: 0x%lX, setting to: 0x%X, modified: 0x%lX\n",
+ header->GetSystemAttr(), header->GetSystemAttr() & 0xFFFFF000,
+ Mode & 0xFFF, (header->GetSystemAttr() & 0xFFFFF000) + (Mode & 0xFFF));
+ globs->zip->SetFileHeaderAttr(*header, (header->GetSystemAttr() & 0xFFFFF000) + (Mode & 0xFFF));
+
+ // write the local header information
+ globs->zip->OverwriteLocalHeader(file_no);
+
+/*
+ // Re-encrypt the file
+ if (header->IsEncrypted()) {
+ printf("(II) VFSChmod: Re-encrypting the file...\n");
+ if (! globs->zip->EncryptFile(file_no))
+ printf("(EE) VFSChmod: Unable to encrypt the file\n");
+ }
+*/
+ globs->zip->RemoveCentralDirectoryFromArchive();
+ globs->zip->Flush();
+
+
+ printf("(II) VFSChmod OK.\n");
+ build_global_filelist(globs);
+ globs->archive_modified = true;
+ return cVFS_OK;
+ }
+ catch (CZipException e) {
+ globs->zip->CloseNewFile(true);
+ fprintf(stderr, "(EE) VFSChmod: permissions modification of the file '%s' failed: [%d] %s, archive closed = %d.\n",
+ FileName, e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ printf("(EE) VFSChmod: permissions modification of the file '%s' failed.\n", FileName);
+ return cVFS_Failed;
+ }
+}
+
+TVFSResult VFSChown(struct TVFSGlobs *globs, const char *FileName, const uint UID, const uint GID)
+{
+ fprintf(stderr, "(EE) VFSChown: Owner changing is not supported in ZIP archives.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChangeTimes(struct TVFSGlobs *globs, char *APath, long mtime, long atime)
+{
+ printf ("(II) VFSChangeTimes: Going to change date/times of the file '%s'...\n", APath);
+
+ char *AFile = exclude_trailing_path_sep(APath);
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, AFile) - 1;
+ free(AFile);
+
+ if (file_no < 0) {
+ printf("(EE) VFSChangeTimes: can't find the file specified: '%s'\n", APath);
+ return cVFS_Failed;
+ }
+
+ try {
+ try {
+ // read the local header information
+ globs->zip->ReadLocalHeader(file_no);
+ CZipFileHeader *header = globs->zip->GetFileInfo(file_no);
+ if (! header) {
+ printf("(EE) VFSChangeTimes: DateTime modification of the file '%s' failed: NULL returned by GetFileInfo()\n", APath);
+ return cVFS_Failed;
+ }
+ // Change the header data
+ header->SetTime(mtime);
+
+/* // Re-encrypt the file
+ if (header->IsEncrypted()) {
+ printf("(II) VFSChangeTimes: Re-encrypting the file...\n");
+ if (! globs->zip->EncryptFile(file_no))
+ printf("(EE) VFSChangeTimes: Unable to encrypt the file\n");
+ }
+*/
+ // write the local header information
+ globs->zip->OverwriteLocalHeader(file_no);
+ globs->zip->RemoveCentralDirectoryFromArchive();
+
+ printf("(II) VFSChangeTimes OK.\n");
+ build_global_filelist(globs);
+ globs->archive_modified = true;
+ return cVFS_OK;
+ }
+ catch (CZipException e) {
+ globs->zip->CloseNewFile(true);
+ fprintf(stderr, "(EE) VFSChangeTimes: DateTime modification of the file '%s' failed: [%d] %s, archive closed = %d.\n",
+ APath, e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ printf("(EE) VFSChangeTimes: DateTime modification of the file '%s' failed.\n", APath);
+ return cVFS_Failed;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+TVFSFileDes VFSOpenFile(struct TVFSGlobs *globs, const char *APath, int Mode, int *Error)
+{
+ *Error = cVFS_Not_Supported;
+ return (TVFSFileDes)0;
+}
+
+TVFSResult VFSCloseFile(struct TVFSGlobs *globs, TVFSFileDes FileDescriptor)
+{
+ return cVFS_Not_Supported;
+}
+
+u_int64_t VFSFileSeek(struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, u_int64_t AbsoluteOffset, int *Error)
+{
+ *Error = cVFS_Not_Supported;
+ return 0;
+}
+
+int VFSReadFile(struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, void *Buffer, int ABlockSize, int *Error)
+{
+ *Error = cVFS_Not_Supported;
+ return 0;
+}
+
+int VFSWriteFile(struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, void *Buffer, int BytesCount, int *Error)
+{
+ *Error = cVFS_Not_Supported;
+ return 0;
+}
+
+void VFSSetBlockSize(struct TVFSGlobs *globs, int Value)
+{
+ globs->block_size = Value;
+}
+
+int VFSIsOnSameFS(struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ printf("(II) VFSIsOnSameFS: Not supported in ZIP archives.\n");
+ return true;
+}
+
+int VFSTwoSameFiles(struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ printf("(II) VFSTwoSameFiles: Not supported in ZIP archives, comparing by paths.\n");
+ return compare_two_same_files(Path1, Path2);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+
+// Known issues: - crashes when no space left on NFS mounts, probably unhandled exception in further ZipArchive code (repro: Gentoo, Ubuntu)
+TVFSResult VFSCopyOut(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, TVFSCopyCallBackFunc pCallBackProgress, void *data, int Append)
+{
+ if ((sSrcName == NULL) || (sDstName == NULL) || (strlen(sSrcName) < 1) || (strlen(sDstName) < 1)) {
+ printf("(EE) VFSCopyOut: The value of 'sSrcName' or 'sDstName' is NULL or empty\n");
+ return cVFS_Failed;
+ }
+
+ printf("(II) VFSCopyOut: copying file '%s' out to '%s'\n", sSrcName, sDstName);
+
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, sSrcName) - 1;
+ if (file_no < 0) {
+ printf("(EE) VFSCopyOut: can't find source file '%s'\n", sSrcName);
+ return cVFS_ReadErr;
+ }
+
+ char *s = exclude_trailing_path_sep(sDstName);
+ char *dest_path = extract_file_path(s);
+ char *dest_filename = extract_file_name(s);
+ free(s);
+
+ // Set callback data
+ globs->extract_callback->data = data;
+ globs->extract_callback->pCallBackProgress = pCallBackProgress;
+
+ // Perform extract
+ try {
+ try {
+ if (! globs->zip->ExtractFile(file_no, dest_path, false, dest_filename, globs->block_size)) {
+ globs->zip->CloseFile(NULL, true);
+ fprintf(stderr, "(EE) VFSCopyOut: Error while copying out, archive closed = %d.\n", globs->zip->IsClosed());
+ return cVFS_WriteErr;
+ }
+ fprintf(stderr, "(II) VFSCopyOut: copy OK, archive closed = %d.\n", globs->zip->IsClosed());
+ }
+ catch (CZipException e) {
+ globs->zip->CloseFile(NULL, true);
+ fprintf(stderr, "(EE) VFSCopyOut: Error while copying out: [%d] %s, archive closed = %d.\n",
+ e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ fprintf(stderr, "(EE) VFSCopyOut: Fatal error while copying out..., archive closed = %d.\n", globs->zip->IsClosed());
+ return cVFS_WriteErr;
+ }
+
+ free(dest_path);
+ free(dest_filename);
+ return cVFS_OK;
+}
+
+// Known issues: - archive corruption when no space left on device
+// - encrypted files are unreadable after copy in
+TVFSResult VFSCopyIn(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, TVFSCopyCallBackFunc pCallBackProgress, void *data, int Append)
+{
+ if ((sSrcName == NULL) || (sDstName == NULL) || (strlen(sSrcName) < 1) || (strlen(sDstName) < 1)) {
+ printf("(EE) VFSCopyIn: The value of 'sSrcName' or 'sDstName' is NULL or empty\n");
+ return cVFS_Failed;
+ }
+
+ printf("(II) VFSCopyIn: copying file '%s' in to '%s'\n", sSrcName, sDstName);
+
+ // Set callback data
+ globs->extract_callback->data = data;
+ globs->extract_callback->pCallBackProgress = pCallBackProgress;
+
+ try {
+ try {
+ char *s = exclude_leading_path_sep(sDstName);
+ if (! globs->zip->AddNewFile(sSrcName, s, -1, CZipArchive::zipsmSafeSmart, globs->block_size)) {
+ globs->zip->CloseNewFile(true);
+ globs->zip->CloseFile(NULL, true);
+ build_global_filelist(globs);
+ fprintf(stderr, "(EE) VFSCopyIn: Error while copying in, archive closed = %d.\n", globs->zip->IsClosed());
+ return cVFS_WriteErr;
+ }
+
+ globs->zip->Flush();
+ printf("(II) VFSCopyIn: copy OK, archive closed = %d.\n", globs->zip->IsClosed());
+ build_global_filelist(globs);
+ globs->archive_modified = true;
+
+/*
+ // Encrypt the file if archive contains any encrypted files
+ if (globs->need_password) {
+ unsigned long int file_no = filelist_find_index_by_path(globs->files, s) - 1;
+ if (file_no < 0) {
+ printf("(EE) VFSCopyIn: unable to find index for newly written file '%s'\n", sSrcName);
+ return cVFS_WriteErr;
+ }
+ printf("(II) VFSCopyIn: Encrypting the newly written file...\n");
+ if (! globs->zip->EncryptFile(file_no))
+ printf("(EE) VFSCopyIn: Unable to encrypt the newly written file\n");
+ }
+ */
+
+ free(s);
+ }
+ catch (CZipException e) {
+ globs->zip->CloseNewFile(true);
+ globs->zip->CloseFile(NULL, true);
+ build_global_filelist(globs);
+ fprintf(stderr, "(EE) VFSCopyIn: Error while copying in: [%d] %s, archive closed = %d.\n",
+ e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ return get_vfs_errorcode(e.m_iCause);
+ }
+ }
+ catch (...)
+ {
+ fprintf(stderr, "(EE) VFSCopyIn: Fatal error while copying in..., archive closed = %d.\n", globs->zip->IsClosed());
+ return cVFS_WriteErr;
+ }
+
+ return cVFS_OK;
+}
+
+
+///////////////////////////////
+// end of extern "C"
+}
+
+
+
+
+/***
+* Todo:
+*
+* - implement an "opened" flag - is it really needed? + add tests to all functions
+* - readonly checking IsReadOnly() + add tests to all functions modifying the archive
+* - after VFS API update implement archive testing, compression level setting, retrieving compression info for each file and archive, readonly flags, begin-action, end-action (no refresh, faster operations) ...
+* - moving files from one directory to another within the archive
+*
+*/
+
+
+