/* ZIP plugin for Tux Commander * version 0.5.6, designed for ZipArchive v3.2.0 * Copyright (C) 2008 Tomas Bzatek * 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 #include #include #include #include #include #include #include #include #include #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.5.6" #define BUILD_DATE "2009-10-25" #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 */ /************** ****************/ struct ZIP_API CVFSZipActionCallback; 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; TVFSAskQuestionCallback callback_ask_question; TVFSAskPasswordCallback callback_ask_password; TVFSProgressCallback callback_progress; void *callback_data; }; // Define the progress class and the class methods struct ZIP_API CVFSZipActionCallback : public CZipActionCallback { CVFSZipActionCallback() { m_uTotalToProcess = 0; m_uProcessed = 0; globs = NULL; } struct TVFSGlobs *globs; 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 (globs && globs->callback_progress) ret = globs->callback_progress (m_uProcessed, m_uTotalToProcess, globs->callback_data); } catch (...) { fprintf(stderr, "(EE) extract_callback: Fatal error occured when calling pCallBackProgress\n"); } return ret; } }; /*********************************************************************************************************************** * 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 = (int64_t)fh->m_uUncomprSize; item->iPackedSize = (int64_t)fh->m_uComprSize; 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; char *s; s = g_filename_display_name ((LPCTSTR)fh->GetFileName()); // Add item to the global list and continue with next file filelist_tree_add_item(globs->files, s, s, item, i + 1); g_free (s); 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 struct TVFSGlobs * VFSNew (TVFSLogFunc log_func) { struct TVFSGlobs * globs; globs = (struct TVFSGlobs *) malloc (sizeof (struct TVFSGlobs)); memset (globs, 0, sizeof (struct TVFSGlobs)); globs->archive_opened = false; globs->block_size = DEFAULT_BLOCK_SIZE; globs->archive_modified = false; globs->need_password = FALSE; globs->callback_data = NULL; globs->callback_ask_question = NULL; globs->callback_ask_password = NULL; globs->callback_progress = NULL; globs->log_func = log_func; if (globs->log_func != NULL) globs->log_func("zip plugin: VFSInit"); return globs; } void VFSSetCallbacks (struct TVFSGlobs *globs, TVFSAskQuestionCallback ask_question_callback, TVFSAskPasswordCallback ask_password_callback, TVFSProgressCallback progress_func, void *data) { globs->callback_ask_question = ask_question_callback; globs->callback_ask_password = ask_password_callback; globs->callback_progress = progress_func; globs->callback_data = data; } void VFSFree (struct TVFSGlobs *globs) { if (globs->log_func != NULL) globs->log_func("zip plugin: VFSDestroy"); free (globs); } int VFSVersion() { return cVFSVersion; } struct TVFSInfo * VFSGetInfo() { struct TVFSInfo *module_info = (TVFSInfo*) g_malloc0 (sizeof (struct TVFSInfo)); module_info->ID = g_strdup ("zip_plugin"); module_info->Name = g_strdup ("ZIP plugin"); module_info->About = g_strdup_printf ("version %s, build date: %s\nusing ZipArchive library v%s\n", VERSION, BUILD_DATE, CZipArchive::m_gszVersion); module_info->Copyright = g_strdup_printf ("Plugin Copyright (C) 2004-2009 Tomáš Bžatek\n%s", CZipArchive::m_gszCopyright); return module_info; } char * VFSGetArchiveExts() { return g_strdup ("zip"); } /**************************************************************************************************************************************/ /**************************************************************************************************************************************/ TVFSResult VFSOpenArchive(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, "(--) VFSOpenArchive: trying to open the file...\n"); try { if (! globs->zip->Open(sName, CZipArchive::zipOpen, 0)) { printf("(EE) VFSOpenArchive: error opening zip archive\n"); return cVFS_Failed; } } catch (...) { printf("(!!) VFSOpenArchive: 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) VFSOpenArchive: error opening readonly zip archive\n"); return cVFS_Failed; } } catch (...) { printf("(EE) VFSOpenArchive: error opening readonly zip\n"); return cVFS_Failed; } } int iCount = globs->zip->GetCount(false); printf("(II) VFSOpenArchive: %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->extract_callback->globs = globs; 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) VFSOpenArchive: Error while processing archive %s\n%s\n", (LPCTSTR) sName, (LPCTSTR)e.GetErrorDescription()); if (e.m_szFileName.IsEmpty()) printf("\n"); else printf("(EE) VFSOpenArchive: Filename in error object: %s\n\n", (LPCTSTR)e.m_szFileName); globs->zip->Close(true); return cVFS_Failed; } catch (...) { printf ("(EE) VFSOpenArchive: 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 g_strdup (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 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; } void VFSResetPassword(struct TVFSGlobs *globs) { if (globs) globs->zip->SetPassword(NULL); } /******************************************************************************************************/ 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 VFSCopyToLocal(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, int Append) { gboolean try_again; if ((sSrcName == NULL) || (sDstName == NULL) || (strlen(sSrcName) < 1) || (strlen(sDstName) < 1)) { printf("(EE) VFSCopyToLocal: The value of 'sSrcName' or 'sDstName' is NULL or empty\n"); return cVFS_Failed; } printf("(II) VFSCopyToLocal: 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) VFSCopyToLocal: 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); // Perform extract try { do { try { try_again = FALSE; if (! globs->zip->ExtractFile(file_no, dest_path, false, dest_filename, globs->block_size)) { globs->zip->CloseFile(NULL, true); fprintf(stderr, "(EE) VFSCopyToLocal: Error while copying out, archive closed = %d.\n", globs->zip->IsClosed()); return cVFS_WriteErr; } fprintf(stderr, "(II) VFSCopyToLocal: copy OK, archive closed = %d.\n", globs->zip->IsClosed()); } catch (CZipException e) { globs->zip->CloseFile(NULL, true); fprintf(stderr, "(EE) VFSCopyToLocal: Error while copying out: [%d] %s, archive closed = %d.\n", e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed()); switch (e.m_iCause) { case CZipException::badPassword: if (globs->callback_ask_password) { char *passwd = NULL; int res = globs->callback_ask_password ("The archive is encrypted and requires password", NULL, NULL, NULL, (TVFSAskPasswordFlags)(VFS_ASK_PASSWORD_NEED_PASSWORD | VFS_ASK_PASSWORD_ARCHIVE_MODE), NULL, &passwd, NULL, NULL, NULL, globs->callback_data); if (res && passwd) { fprintf(stderr, " (II) VFSCopyToLocal: setting password to '%s'\n", passwd); globs->zip->SetPassword(passwd); try_again = TRUE; break; } else return cVFS_Cancelled; } default: return get_vfs_errorcode(e.m_iCause); } } } while (try_again); } catch (...) { fprintf(stderr, "(EE) VFSCopyToLocal: 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 VFSCopyFromLocal(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, int Append) { gboolean try_again; if ((sSrcName == NULL) || (sDstName == NULL) || (strlen(sSrcName) < 1) || (strlen(sDstName) < 1)) { printf("(EE) VFSCopyFromLocal: The value of 'sSrcName' or 'sDstName' is NULL or empty\n"); return cVFS_Failed; } printf("(II) VFSCopyFromLocal: copying file '%s' in to '%s'\n", sSrcName, sDstName); try { do { try { try_again = FALSE; 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) VFSCopyFromLocal: Error while copying in, archive closed = %d.\n", globs->zip->IsClosed()); return cVFS_WriteErr; } globs->zip->Flush(); printf("(II) VFSCopyFromLocal: 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) VFSCopyFromLocal: unable to find index for newly written file '%s'\n", sSrcName); return cVFS_WriteErr; } printf("(II) VFSCopyFromLocal: Encrypting the newly written file...\n"); if (! globs->zip->EncryptFile(file_no)) printf("(EE) VFSCopyFromLocal: 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) VFSCopyFromLocal: Error while copying in: [%d] %s, archive closed = %d.\n", e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed()); switch (e.m_iCause) { case CZipException::badPassword: if (globs->callback_ask_password) { char *passwd = NULL; int res = globs->callback_ask_password ("The archive is encrypted and requires password", NULL, NULL, NULL, (TVFSAskPasswordFlags)(VFS_ASK_PASSWORD_NEED_PASSWORD | VFS_ASK_PASSWORD_ARCHIVE_MODE), NULL, &passwd, NULL, NULL, NULL, globs->callback_data); if (res && passwd) { fprintf(stderr, " (II) VFSCopyFromLocal: setting password to '%s'\n", passwd); globs->zip->SetPassword(passwd); try_again = TRUE; break; } else return cVFS_Cancelled; } default: return get_vfs_errorcode(e.m_iCause); } } } while (try_again); } catch (...) { fprintf(stderr, "(EE) VFSCopyFromLocal: Fatal error while copying in..., archive closed = %d.\n", globs->zip->IsClosed()); return cVFS_WriteErr; } return cVFS_OK; } /////////////////////////////// // end of extern "C" } /*** * Todo: * * - UTF-8, FName/FDisplayName and absolute/relative paths revision needed! * (check http://www.artpol-software.com/ZipArchive/KB/0610051525.aspx ) * - 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 * */