summaryrefslogtreecommitdiff
path: root/zip/zip.cpp
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2024-10-25 19:45:56 +0200
committerTomas Bzatek <tbzatek@redhat.com>2024-10-25 20:06:37 +0200
commitd1b057c4e3b865dc511cd2b5b591371303323272 (patch)
tree40b2a89044a11c6daeec88e66dcc13579bc7594a /zip/zip.cpp
parent5060e318edf3bec2bdb1b353b911203db923ff5f (diff)
downloadtuxcmd-modules-d1b057c4e3b865dc511cd2b5b591371303323272.tar.xz
zip: Implement manual file open-read-close
No write support at the moment.
Diffstat (limited to 'zip/zip.cpp')
-rw-r--r--zip/zip.cpp329
1 files changed, 255 insertions, 74 deletions
diff --git a/zip/zip.cpp b/zip/zip.cpp
index b33cf2d..c6db221 100644
--- a/zip/zip.cpp
+++ b/zip/zip.cpp
@@ -1,5 +1,5 @@
/* ZIP plugin for Tux Commander
- * version 0.7.1, designed for ZipArchive v4.6.9
+ * version 0.8, designed for ZipArchive v4.6.9
* Copyright (C) 2004-2024 Tomas Bzatek <tbzatek@users.sourceforge.net>
* Check for updates on tuxcmd.sourceforge.net
*
@@ -42,6 +42,7 @@
#include "logutils.h"
#include "filelist.h"
#include "filelist-vfs-intf.h"
+#include "tuxcmd-error.h"
#include "ZipArchive.h"
#include "ZipPlatform.h"
@@ -49,8 +50,8 @@
-#define VERSION "0.7.1"
-#define BUILD_DATE "2024-01-19"
+#define VERSION "0.8"
+#define BUILD_DATE "2024-10-25"
#define DEFAULT_BLOCK_SIZE 65536
@@ -929,38 +930,7 @@ VFSChangeTimes (struct TVFSGlobs *globs, const char *APath, guint32 mtime, guint
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////
-#if 0
-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;
-}
-#endif
-
-void
+void
VFSSetBlockSize (struct TVFSGlobs *globs, guint32 Value)
{
if (globs)
@@ -1013,6 +983,33 @@ VFSStopCopyOperation (struct TVFSGlobs *globs, GError **error)
return TRUE;
}
+/* returns TRUE if password has been set and to try again */
+static gboolean
+handle_password_prompt (struct TVFSGlobs *globs, const gchar *log_prefix, GError **error)
+{
+ gchar *passwd = NULL;
+ gboolean res;
+
+ if (globs->callback_ask_password) {
+ res = globs->callback_ask_password ("The archive is encrypted and requires a 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) {
+ log_debug ("%s: setting password to '%s'", log_prefix, passwd);
+ globs->zip->SetPassword (passwd);
+ g_free (passwd);
+ return TRUE;
+ } else {
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CANCELLED, "Operation has been cancelled.");
+ return FALSE;
+ }
+ }
+
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_SOURCE_READ, "An incorrect password set for the file being decrypted.");
+ return FALSE;
+}
+
/* Known issues:
* - crashes when no space left on NFS mounts, probably unhandled exception in further ZipArchive code (repro: Gentoo, Ubuntu)
@@ -1026,8 +1023,6 @@ VFSCopyToLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstN
char *s;
char *dest_path;
char *dest_filename;
- char *passwd;
- gboolean res;
if (sSrcName == NULL || sDstName == NULL || strlen (sSrcName) < 1 || strlen (sDstName) < 1) {
log_error ("VFSCopyToLocal: The value of 'sSrcName' or 'sDstName' is NULL or empty");
@@ -1063,27 +1058,15 @@ VFSCopyToLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstN
log_debug ("VFSCopyToLocal: copy OK, archive closed = %d.", globs->zip->IsClosed ());
}
catch (CZipException& e) {
- globs->zip->CloseFile (NULL, true);
log_error ("VFSCopyToLocal: Error while copying out: [%d] %s, archive closed = %d.",
e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ globs->zip->CloseFile (NULL, true);
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 a 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) {
- log_debug ("VFSCopyToLocal: setting password to '%s'", passwd);
- globs->zip->SetPassword (passwd);
- try_again = TRUE;
- break;
- } else {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Operation has been cancelled.");
- return FALSE;
- }
- }
+ if (! handle_password_prompt (globs, "VFSCopyToLocal", error))
+ return FALSE;
+ try_again = TRUE;
+ break;
default:
zip_error_to_gerror (e, error);
return FALSE;
@@ -1095,6 +1078,7 @@ VFSCopyToLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDstN
{
log_error ("VFSCopyToLocal: Fatal error while copying out..., archive closed = %d.", globs->zip->IsClosed());
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Fatal error while copying out.");
+ globs->zip->CloseFile (NULL, true);
return FALSE;
}
g_free (dest_path);
@@ -1113,8 +1097,6 @@ VFSCopyFromLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDs
{
gboolean try_again;
char *s;
- char *passwd;
- gboolean res;
if (sSrcName == NULL || sDstName == NULL || strlen (sSrcName) < 1 || strlen (sDstName) < 1) {
log_error ("VFSCopyFromLocal: The value of 'sSrcName' or 'sDstName' is NULL or empty");
@@ -1137,6 +1119,7 @@ VFSCopyFromLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDs
return FALSE;
}
+ globs->zip->CloseNewFile ();
log_debug ("VFSCopyFromLocal: copy OK, archive closed = %d.", globs->zip->IsClosed ());
globs->archive_modified = TRUE;
@@ -1157,28 +1140,16 @@ VFSCopyFromLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDs
g_free (s);
}
catch (CZipException& e) {
- globs->zip->CloseNewFile (true);
- globs->zip->CloseFile (NULL, true);
log_error ("VFSCopyFromLocal: Error while copying in: [%d] %s, archive closed = %d.",
e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ globs->zip->CloseNewFile (true);
+ globs->zip->CloseFile (NULL, true);
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 a 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) {
- log_debug ("VFSCopyFromLocal: setting password to '%s'", passwd);
- globs->zip->SetPassword (passwd);
- try_again = TRUE;
- break;
- } else {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Operation has been cancelled.");
- return FALSE;
- }
- }
+ if (! handle_password_prompt (globs, "VFSCopyFromLocal", error))
+ return FALSE;
+ try_again = TRUE;
+ break;
default:
zip_error_to_gerror (e, error);
return FALSE;
@@ -1189,12 +1160,222 @@ VFSCopyFromLocal (struct TVFSGlobs *globs, const char *sSrcName, const char *sDs
catch (...) {
log_error ("VFSCopyFromLocal: Fatal error while copying in..., archive closed = %d.", globs->zip->IsClosed());
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Fatal error while copying in.");
+ globs->zip->CloseNewFile (true);
+ globs->zip->CloseFile (NULL, true);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+TVFSFileDes
+VFSOpenFile (struct TVFSGlobs *globs, const char *APath, int Mode, GError **error)
+{
+ gboolean try_again;
+ long int file_no;
+ GError *local_error = NULL;
+
+ switch (Mode) {
+ case cVFS_OpenRead:
+ /* OK, break */
+ break;
+ case cVFS_OpenWrite:
+ case cVFS_OpenAppend:
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Writing files in the archive is not supported");
+ return NULL;
+ default:
+ g_set_error (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Invalid file open mode %d", Mode);
+ return NULL;
+ }
+
+ log_notice ("VFSOpenFile: Opening file '%s'", APath);
+
+ file_no = filelist_find_original_index_by_path (globs->files, APath) - 1;
+ if (file_no < 0) {
+ log_error ("VFSOpenFile: can't find file '%s'", APath);
+ g_set_error (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Cannot find file '%s'", APath);
+ return NULL;
+ }
+
+ try {
+ do {
+ try {
+ try_again = FALSE;
+ if (! globs->zip->OpenFile (file_no)) {
+ log_error ("VFSOpenFile: Error opening file, archive closed = %d.", globs->zip->IsClosed ());
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Error opening file.");
+ return NULL;
+ }
+ }
+ catch (CZipException& e) {
+ log_error ("VFSOpenFile: Error opening file: [%d] %s, archive closed = %d.",
+ e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ globs->zip->CloseFile (NULL, true);
+ switch (e.m_iCause) {
+ case CZipException::badPassword:
+ if (! handle_password_prompt (globs, "VFSOpenFile", &local_error)) {
+ if (g_error_matches (local_error, TUXCMD_ERROR, TUXCMD_ERROR_CANCELLED))
+ g_propagate_error (error, local_error);
+ else {
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, local_error->message);
+ g_error_free (local_error);
+ }
+ return NULL;
+ }
+ try_again = TRUE;
+ break;
+ default:
+ zip_error_to_gerror (e, &local_error);
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, local_error->message);
+ g_error_free (local_error);
+ return NULL;
+ }
+ }
+ } while (try_again);
+ }
+ catch (...)
+ {
+ log_error ("VFSCopyToLocal: Fatal error while opening file..., archive closed = %d.", globs->zip->IsClosed());
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Fatal error while opening file.");
+ globs->zip->CloseFile (NULL, true);
+ return NULL;
+ }
+
+ return (TVFSFileDes)(file_no + 1); /* FIXME: what to use as a filedescriptor? */
+}
+
+gboolean
+VFSCloseFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, GError **error)
+{
+ GError *local_error = NULL;
+ int r;
+
+ try {
+ try {
+ /* FIXME: cannot distinguish between clean close and close after exception */
+ r = globs->zip->CloseFile ();
+ if (r != 1) {
+ /* Returns one of the following values:
+ * 1 : The operation was successful.
+ * 0 : There is no file opened.
+ * -1 : Some bytes were left to uncompress - probably due to a bad password or a corrupted archive.
+ * -2 : Setting extracted file date and attributes was not successful.
+ */
+ log_error ("VFSCloseFile: Error closing file, archive closed = %d.", globs->zip->IsClosed ());
+ switch (r) {
+ case 0: g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE,
+ "There is no file opened.");
+ break;
+ case -1: g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE,
+ "Some bytes were left to uncompress - probably due to a bad password or a corrupted archive.");
+ break;
+ case -2: g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE,
+ "Setting extracted file date and attributes was not successful.");
+ break;
+ default:
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE, "Error closing file.");
+ }
+ globs->zip->CloseFile (NULL, true);
+ return FALSE;
+ }
+ }
+ catch (CZipException& e) {
+ log_error ("VFSCloseFile: Error closing file: [%d] %s, archive closed = %d.",
+ e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ zip_error_to_gerror (e, &local_error);
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE, local_error->message);
+ g_error_free (local_error);
+ globs->zip->CloseFile (NULL, true);
+ return FALSE;
+ }
+ }
+ catch (...)
+ {
+ log_error ("VFSCloseFile: Fatal error while closing file..., archive closed = %d.", globs->zip->IsClosed());
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_CLOSE_FILE, "Fatal error while closing file.");
+ globs->zip->CloseFile (NULL, true);
return FALSE;
}
return TRUE;
}
+gint64
+VFSReadFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, gpointer Buffer, guint64 ABlockSize, GError **error)
+{
+ gboolean try_again;
+ GError *local_error = NULL;
+
+ try {
+ do {
+ try {
+ DWORD r;
+
+ try_again = FALSE;
+
+ /* no file handle, only a global archive state (no multithreading) */
+ r = globs->zip->ReadFile (Buffer, ABlockSize);
+ /* returns 0 on EOF */
+ /* no error state available */
+ return r;
+ }
+ catch (CZipException& e) {
+ log_error ("VFSReadFile: Error reading file: [%d] %s, archive closed = %d.",
+ e.m_iCause, (LPCTSTR)e.GetErrorDescription(), globs->zip->IsClosed());
+ globs->zip->CloseFile (NULL, true);
+ switch (e.m_iCause) {
+ case CZipException::badPassword:
+ if (! handle_password_prompt (globs, "VFSReadFile", &local_error)) {
+ if (g_error_matches (local_error, TUXCMD_ERROR, TUXCMD_ERROR_CANCELLED))
+ g_propagate_error (error, local_error);
+ else {
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, local_error->message);
+ g_error_free (local_error);
+ }
+ globs->zip->CloseFile (NULL, true);
+ return -1;
+ }
+ try_again = TRUE;
+ break;
+ default:
+ zip_error_to_gerror (e, &local_error);
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, local_error->message);
+ g_error_free (local_error);
+ globs->zip->CloseFile (NULL, true);
+ return -1;
+ }
+ }
+ } while (try_again);
+ }
+ catch (...)
+ {
+ log_error ("VFSCopyToLocal: Fatal error while opening file..., archive closed = %d.", globs->zip->IsClosed());
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_OPEN_FILE, "Fatal error while opening file.");
+ globs->zip->CloseFile (NULL, true);
+ return -1;
+ }
+
+ g_warn_if_reached ();
+ return -1;
+}
+
+gint64
+VFSWriteFile (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, gpointer Buffer, guint64 BytesCount, GError **error)
+{
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_WRITE_FILE, "Writing files in the archive is not supported");
+ return -1;
+}
+
+guint64
+VFSFileSeek (struct TVFSGlobs *globs, TVFSFileDes FileDescriptor, guint64 AbsoluteOffset, GError **error)
+{
+ g_set_error_literal (error, TUXCMD_ERROR, TUXCMD_ERROR_SEEK, "Seeking in compressed data is not supported");
+ return 0;
+}
+
///////////////////////////////
// end of extern "C"