/* ZIP plugin for Tux Commander * version 0.6.0, designed for ZipArchive v3.2.0 * Copyright (C) 2004-2009 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 "tuxcmd-vfs.h" #include "strutils.h" #include "vfsutils.h" #include "filelist.h" #include "filelist-vfs-intf.h" #include "ZipArchive.h" #include "ZipPlatform.h" #include "ZipCallback.h" #define VERSION "0.6.0" #define BUILD_DATE "2009-11-28" #define DEFAULT_BLOCK_SIZE 65536 using namespace std; extern "C" { /******************************************************************************************************/ /** Utilities */ /************** ****************/ static 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; gboolean archive_opened; guint32 block_size; gboolean 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 ********/ static void build_global_filelist (struct TVFSGlobs *globs) { int iCount; int i; CZipFileHeader *fh; struct TVFSItem *item; char *s; /* Ensure the filelist is freed */ if (globs->vfs_filelist) vfs_filelist_free (globs->vfs_filelist); if (globs->files) filelist_tree_free (globs->files); globs->files = filelist_tree_new(); globs->vfs_filelist = vfs_filelist_new (globs->files); iCount = globs->zip->GetCount(); /* list files in the archive */ for (i = 0; i < iCount; i++) { 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 (i = 0; i < iCount; i++) { fh = globs->zip->GetFileInfo (i); if (fh != NULL) { /* Create a TVFSItem entry and fill all info */ item = (struct TVFSItem *) g_malloc0 (sizeof (struct TVFSItem)); item->iSize = (guint64) fh->m_uUncomprSize; item->iPackedSize = (guint64) 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; /* Add item to the global list and continue with next file */ s = g_filename_display_name ((LPCTSTR) fh->GetFileName ()); filelist_tree_add_item (globs->files, s, item, (LPCTSTR) fh->GetFileName (), 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 *) g_malloc0 (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: VFSFree"); g_free (globs); } int VFSVersion () { return cVFSVersion; } struct TVFSInfo * VFSGetInfo () { struct TVFSInfo *module_info; 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, const char *sName) { int iCount; globs->files = NULL; globs->vfs_filelist = 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; } } 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 global file list */ build_global_filelist (globs); /* set 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 = g_strdup (sName); globs->archive_modified = FALSE; return cVFS_OK; } TVFSResult VFSClose (struct TVFSGlobs *globs) { if (globs) { /* close the archive... */ fprintf (stderr, "(II) VFSClose: Closing the archive...\n"); try { if (globs->archive_modified) globs->zip->Flush (); /* In case of inconsistency, try using afWriteDir value. * (use when an exception was thrown, yhe Close method writes the * central directory structure to the archive, so that the archive should be usable.) */ globs->zip->Close (CZipArchive::afNoException, false); } catch (CZipException e) { fprintf (stderr, "(EE) VFSClose: Error while closing archive: %s\n", (LPCTSTR)e.GetErrorDescription()); return cVFS_Failed; } /* free 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; } /* free 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... */ g_free (globs->archive_path); } return cVFS_OK; } char * VFSGetPath (struct TVFSGlobs *globs) { return g_strdup (globs->curr_dir); } TVFSResult VFSGetFileSystemInfo (struct TVFSGlobs *globs, const char *APath, gint64 *FSSize, gint64 *FSFree, char **FSLabel) { if (FSSize) *FSSize = globs->zip->GetOccupiedSpace (); if (FSFree) *FSFree = 0; if (FSLabel) *FSLabel = NULL; return cVFS_OK; } /******************************************************************************************************/ TVFSResult VFSChangeDir (struct TVFSGlobs *globs, const 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; } gboolean 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, const char *sDir, struct TVFSItem *Item, gboolean FollowSymlinks, gboolean AddFullPath) { 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, FollowSymlinks, AddFullPath); } TVFSResult VFSListNext (struct TVFSGlobs *globs, struct TVFSItem *Item) { return vfs_filelist_list_next (globs->vfs_filelist, Item); } TVFSResult VFSListClose (struct TVFSGlobs *globs) { return vfs_filelist_list_close (globs->vfs_filelist); } /******************************************************************************************************/ TVFSResult VFSFileInfo (struct TVFSGlobs *globs, const char *AFileName, struct TVFSItem *Item, gboolean FollowSymlinks, gboolean AddFullPath) { printf ("(--) VFSFileInfo: requested info for object '%s'\n", AFileName); if (! globs) return cVFS_Failed; return vfs_filelist_file_info (globs->vfs_filelist, AFileName, Item, FollowSymlinks, AddFullPath); } /******************************************************************************************************/ /** Recursive tree size counting */ /************** ****************/ guint64 VFSGetDirSize (struct TVFSGlobs *globs, const 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) { CZipFileHeader header; char *s; bool bRet; if (sDirName == NULL || strlen (sDirName) < 1) { printf ("(EE) VFSMkDir: The value of 'sDirName' is NULL or empty\n"); return cVFS_Failed; } if (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 { // globs->zip->SetFileHeaderAttr (header, 0x41ED0010); globs->zip->SetFileHeaderAttr (header, 0x41ED); /* alternatively use ZipPlatform::GetDefaultAttributes(); */ s = exclude_leading_path_sep (sDirName); header.SetFileName(s); g_free (s); header.SetTime (time (NULL)); 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) { char *AFile, *AFile1, *AFile2, *AFile3; unsigned long int file_no; printf ("(II) VFSRemove: Going to remove the file '%s'...\n", APath); AFile = exclude_trailing_path_sep (APath); file_no = filelist_find_original_index_by_path (globs->files, AFile) - 1; g_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"); /* If we delete last file from a directory, we should make an empty one. * Some archives store pathnames only with filenames, no separate records for directories. **/ AFile1 = exclude_trailing_path_sep (APath); AFile2 = g_path_get_dirname (AFile1); AFile3 = exclude_trailing_path_sep (AFile2); if (strlen (AFile3) > 0 && g_strcmp0 (AFile3, "/") != 0) { printf ("(II) VFSRemove: AFile1: '%s', AFile2: '%s', AFile3: '%s'\n", AFile1, AFile2, AFile3); file_no = filelist_find_original_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); } } g_free (AFile1); g_free (AFile2); g_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) { char *AFile; char *ADestFile; unsigned long int file_no; printf ("(II) VFSRename: Going to rename/move the file '%s' to '%s'...\n", sSrcName, sDstName); AFile = exclude_trailing_path_sep (sSrcName); ADestFile = exclude_trailing_path_sep (sDstName); file_no = filelist_find_original_index_by_path (globs->files, AFile) - 1; g_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; } g_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, guint32 Mode) { char *AFile; unsigned long int file_no; CZipFileHeader *header; printf ("(II) VFSChmod: Going to change permissions of the file '%s'...\n", FileName); AFile = exclude_trailing_path_sep (FileName); file_no = filelist_find_original_index_by_path (globs->files, AFile) - 1; g_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); 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 local header information */ globs->zip->OverwriteLocalHeader (file_no); #if 0 // 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"); } #endif 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, guint32 UID, guint32 GID) { fprintf (stderr, "(EE) VFSChown: Owner changing is not supported in ZIP archives.\n"); return cVFS_Not_Supported; } TVFSResult VFSChangeTimes (struct TVFSGlobs *globs, const char *APath, guint32 mtime, guint32 atime) { char *AFile; unsigned long int file_no; CZipFileHeader *header; printf ("(II) VFSChangeTimes: Going to change date/times of the file '%s'...\n", APath); AFile = exclude_trailing_path_sep (APath); file_no = filelist_find_original_index_by_path (globs->files, AFile) - 1; g_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); 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 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, guint32 Value) { if (globs) globs->block_size = Value; } gboolean VFSIsOnSameFS (struct TVFSGlobs *globs, const char *Path1, const char *Path2, gboolean FollowSymlinks) { printf ("(II) VFSIsOnSameFS: Not supported in ZIP archives.\n"); return TRUE; } gboolean VFSTwoSameFiles (struct TVFSGlobs *globs, const char *Path1, const char *Path2, gboolean FollowSymlinks) { 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, gboolean Append) { gboolean try_again; unsigned long int file_no; char *s; char *dest_path; char *dest_filename; char *passwd; gboolean res; 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); file_no = filelist_find_original_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; } s = exclude_trailing_path_sep (sDstName); dest_path = g_path_get_dirname (s); dest_filename = g_path_get_basename (s); g_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) { passwd = NULL; 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; } g_free (dest_path); g_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, gboolean Append) { gboolean try_again; char *s; char *passwd; gboolean res; 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; 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"); } */ g_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) { passwd = NULL; 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 * */