diff options
Diffstat (limited to 'zip/zip.cpp')
| -rw-r--r-- | zip/zip.cpp | 980 |
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 +* +*/ + + + |
