summaryrefslogtreecommitdiff
path: root/unrar/unrar.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-08 11:04:43 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-08 11:04:43 +0200
commit16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d (patch)
tree3d22f54f7298f81b18ed66d05a62fa8bfab359ab /unrar/unrar.c
downloadtuxcmd-modules-16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d.tar.xz
Diffstat (limited to 'unrar/unrar.c')
-rw-r--r--unrar/unrar.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/unrar/unrar.c b/unrar/unrar.c
new file mode 100644
index 0000000..6435aeb
--- /dev/null
+++ b/unrar/unrar.c
@@ -0,0 +1,734 @@
+/* UNRAR plugin for Tux Commander
+ * version 0.2.2, designed for unrar v3.7.1 beta1
+ * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ * Check for updates on tuxcmd.sourceforge.net
+ *
+ * Uses UNRAR sources
+ * UnRAR - free utility for RAR archives
+ * Copyright (C) Alexander L. Roshal
+ * http://www.rarlab.com/
+ *
+
+
+ * 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 "vfsutils.h"
+#include "strutils.h"
+#include "treepathutils.h"
+#include "treepath_vfs.h"
+
+#define _UNIX
+
+#include "unrar/version.hpp"
+#include "unrar/dll.hpp"
+
+
+// Compatibility types from headers.hpp
+enum HOST_SYSTEM {
+ HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
+ HOST_BEOS=5,HOST_MAX
+};
+
+
+#define VERSION "0.2.2"
+#define BUILD_DATE "2008-05-11"
+#define DEFAULT_BLOCK_SIZE 65536
+
+
+
+
+
+/******************************************************************************************************/
+/** Auxiliary classes */
+/************** ****************/
+
+
+
+// Declaration of the global plugin object
+struct TVFSGlobs {
+ TVFSLogFunc log_func;
+ char *curr_dir;
+ char *archive_path;
+
+ gboolean need_password;
+ gboolean passwd_callback;
+ char *password;
+
+ unsigned long block_size;
+
+ struct PathTree *files;
+ struct VfsFilelistData *vfs_filelist;
+
+ u_int64_t total_size;
+
+ void *extract_callback_data;
+ TVFSCopyCallBackFunc extract_callback_func;
+ u_int64_t extract_file_size;
+ u_int64_t extract_done;
+ gboolean extract_cancelled;
+};
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+// Basic initialization functions
+int VFSAllocNeeded()
+{
+ return sizeof(struct TVFSGlobs);
+}
+
+void VFSInit(struct TVFSGlobs *globs, TVFSLogFunc log_func)
+{
+ globs->block_size = DEFAULT_BLOCK_SIZE;
+ globs->extract_callback_data = NULL;
+ globs->extract_callback_func = NULL;
+ globs->need_password = FALSE;
+ globs->passwd_callback = FALSE;
+
+ globs->log_func = log_func;
+ if (globs->log_func != NULL) globs->log_func((char*)"unrar plugin: VFSInit");
+}
+
+void VFSDestroy(struct TVFSGlobs *globs)
+{
+ if (globs->log_func != NULL) globs->log_func((char*)"unrar plugin: VFSDestroy");
+}
+
+int VFSVersion()
+{
+ return 3;
+}
+
+struct TVFSInfo VFSGetInfo()
+{
+ struct TVFSInfo module_info;
+ module_info.Name = "UNRAR plugin";
+ module_info.Description = "RAR archiving plugin";
+ char *s = (char*)malloc(255);
+ snprintf(s, 255, "version %s, build date: %s\nusing unrar sources v%d.%d [%d-%.2d-%.2d]\n",
+ VERSION, BUILD_DATE, RARVER_MAJOR, RARVER_MINOR, RARVER_YEAR, RARVER_MONTH, RARVER_DAY);
+ module_info.About = strdup(s);
+ free(s);
+ s = (char*)malloc(255);
+ snprintf(s, 255, "Plugin Copyright (C) 2008 Tomáš Bžatek\nUNRAR sources Copyright (C) 2002-2007 Alexander Roshal");
+ module_info.Copyright = strdup(s);
+ return module_info;
+}
+
+char *VFSGetPrefix(struct TVFSGlobs *globs)
+{
+ return globs->archive_path;
+// return (char*)"unrar";
+}
+
+char *VFSGetExts()
+{
+ return (char*)"rar;r00;r01;r02;r03;r04;r05;r06;r07;r08;r09;r10;r11;r12;r13;r14;r15;r16;r17;r18;r19;r20;r21;r22;r23;r24;r25;r26;r27;r28;r29;r30;r31;r32;r33;r34;r35;r36;r37;r38;r39;r40;r41;r42;r43;r44;r45;r46;r47;r48;r49;r50;r51;r52;r53;r54;r55;r56;r57;r58;r59;r60;r61;r62;r63;r64;r65;r66;r67;r68;r69;r70;r71;r72;r73;r74;r75;r76;r77;r78;r79;r80;r81;r82;r83;r84;r85;r86;r87;r88;r89;r90;r91;r92;r93;r94;r95;r96;r97;r98;r99";
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+int unrar_callback(UINT msg, LONG UserData, LONG P1, LONG P2)
+{
+// fprintf(stderr, "(II) unrar_callback called: msg = %d, UserData = %lx, sizeof(UserData) = %ld, P1 = %ld, P2 = %ld\n", msg, UserData, sizeof(UserData), P1, P2);
+
+ // >= 0 => Weiter, -1 => Stop
+ switch(msg)
+ {
+ case UCM_CHANGEVOLUME: {
+ if (P2 == RAR_VOL_ASK) {
+ fprintf(stderr, " (II) unrar_callback: UCM_CHANGEVOLUME message, RAR_VOL_ASK, P1 = %ld, (char*)P1 = '%s' \n", P1, (char*)P1);
+ if (P1)
+ if (access((char*)P1, R_OK) != 0) {
+ fprintf(stderr, "(EE) unrar_callback: UCM_CHANGEVOLUME message, RAR_VOL_ASK: access test failed - missing part? Error = %s \n", strerror(errno));
+ return -1;
+ }
+ } else
+ if (P2 == RAR_VOL_NOTIFY) {
+ fprintf(stderr, " (II) unrar_callback: UCM_CHANGEVOLUME message, RAR_VOL_NOTIFY, P1 = %ld, (char*)P1 = '%s' \n", P1, (char*)P1);
+ }
+ break;
+ }
+
+ case UCM_PROCESSDATA: {
+ fprintf(stderr, " (II) unrar_callback: UCM_PROCESSDATA message, P1 = %ld, P2 = %ld \n", P1, P2);
+ struct TVFSGlobs *globs = (struct TVFSGlobs *)UserData;
+// printf(" (II) unrar_callback: globs = 0x%lX, UserData = 0x%lX \n", (unsigned long int)globs, UserData);
+ if ((globs) && (globs->extract_callback_func != NULL)) {
+// printf(" (II) unrar_callback: globs->extract_callback_func = 0x%lX, globs->extract_callback_data = 0x%lX \n", (unsigned long int)globs->extract_callback_func, (unsigned long int)globs->extract_callback_data);
+// long int res = globs->extract_callback_func((u_int64_t)P1, (u_int64_t)((u_int64_t)P1 + (u_int64_t)P2), globs->extract_callback_data);
+
+ globs->extract_done += P2;
+ int res = globs->extract_callback_func(globs->extract_done, globs->extract_file_size, globs->extract_callback_data);
+
+// fprintf(stderr, " (II) unrar_callback: res = %d \n", res);
+ if (! res ) {
+ globs->extract_cancelled = TRUE;
+ fprintf(stderr, "(WW) unrar_callback: received cancellation result\n");
+ return -1; // Cancel operation
+ }
+ }
+ break;
+ }
+
+ case UCM_NEEDPASSWORD: {
+ fprintf(stderr, " (II) unrar_callback: UCM_NEEDPASSWORD message, P1 = %ld, P2 = %ld, (char*)P1 = '%s', maxlen = %ld \n", P1, P2, (char*)P1, P2);
+ struct TVFSGlobs *globs = (struct TVFSGlobs *)UserData;
+ if (globs) globs->passwd_callback = TRUE;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int PASCAL unrar_changevol_proc(char *ArcName, int Mode)
+{
+ fprintf(stderr, "(II) unrar_changevol_proc called: ArcName = '%s', Mode = %d\n", ArcName, Mode);
+
+ return 0;
+}
+
+int PASCAL unrar_process_data_proc(unsigned char *Addr, int Size)
+{
+ fprintf(stderr, "(II) unrar_process_data_proc called: Addr = '%s', Size = %d\n", Addr, Size);
+
+ return 0;
+}
+
+
+time_t rar_time_to_unix(unsigned int FileTime)
+{
+ struct tm t;
+ t.tm_sec = (FileTime & 0x1f) * 2;
+ t.tm_min = (FileTime >> 5) & 0x3f;
+ t.tm_hour = (FileTime >> 11) & 0x1f;
+ t.tm_mday = (FileTime >> 16) & 0x1f;
+ t.tm_mon = ((FileTime >> 21) & 0x0f)-1;
+ t.tm_year = (FileTime >> 25) + 80;
+ t.tm_isdst = -1;
+// printf("date: %d-%.2d-%.2d %d:%.2d:%.2d \n", t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+ return(mktime(&t));
+}
+
+
+TVFSResult VFSOpen(struct TVFSGlobs *globs, char *sName)
+{
+ TVFSResult Result = cVFS_OK;
+
+ globs->files = filelist_tree_new();
+ globs->vfs_filelist = vfs_filelist_new(globs->files);
+ globs->curr_dir = NULL;
+ globs->archive_path = strdup(sName);
+ globs->total_size = 0;
+ globs->passwd_callback = FALSE;
+ fprintf(stderr, "(--) VFSOpen: trying to open archive '%s'...\n", globs->archive_path);
+
+ HANDLE PASCAL handle;
+ struct RAROpenArchiveDataEx *archive_data;
+
+ archive_data = (struct RAROpenArchiveDataEx*) malloc(sizeof(struct RAROpenArchiveDataEx));
+ memset(archive_data, 0, sizeof(struct RAROpenArchiveDataEx));
+ archive_data->ArcName = globs->archive_path;
+ archive_data->CmtBuf = NULL;
+ archive_data->CmtBufSize = 0;
+ archive_data->OpenMode = RAR_OM_LIST;
+
+ handle = RAROpenArchiveEx(archive_data);
+// printf(" handle = %lu \n", (unsigned long int)handle);
+// printf(" archive_data->OpenResult = %d \n", archive_data->OpenResult);
+// printf(" archive_data->CmtState = %d \n", archive_data->CmtState);
+// printf(" archive_data->CmtSize = %d \n", archive_data->CmtSize);
+
+ if ((handle) && (! archive_data->OpenResult))
+ {
+ // Set callbacks
+ RARSetCallback(handle, unrar_callback, (LONG)globs);
+// RARSetChangeVolProc(handle, unrar_changevol_proc);
+// RARSetProcessDataProc(handle, unrar_process_data_proc);
+
+ if (globs->password) {
+ fprintf(stderr, "(II) VFSOpen: Setting password... \n");
+ RARSetPassword(handle, globs->password);
+ }
+
+ struct RARHeaderDataEx *header;
+ header = (struct RARHeaderDataEx*) malloc(sizeof(struct RARHeaderDataEx));
+ memset(header, 0, sizeof(struct RARHeaderDataEx));
+ header->CmtBuf = NULL;
+ header->CmtBufSize = 0;
+
+ int PASCAL res = 0;
+ while ((res = RARReadHeaderEx(handle, header)) == 0)
+ {
+ printf(" header->FileName = '%s', Flags = 0x%x\n", header->FileName, header->Flags);
+
+ // 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)((u_int64_t)(header->UnpSizeHigh * 0x100000000) + (u_int64_t)header->UnpSize);
+ globs->total_size += item->iSize;
+ if ((header->Flags & 0x00e0 /* LHD_WINDOWMASK */ ) == 0x00e0 /* LHD_DIRECTORY */)
+ item->ItemType = vDirectory;
+ else item->ItemType = vRegular;
+ if ((header->Flags & 0x0004) == 0x0004) globs->need_password = TRUE;
+
+ switch (header->HostOS)
+ {
+ case HOST_MSDOS:
+ case HOST_OS2:
+ case HOST_WIN32:
+ if (header->FileAttr & 0x10) header->FileAttr = 0x41ff | header->FileAttr;
+ else
+ if (header->FileAttr & 1) header->FileAttr = 0x8124 | header->FileAttr;
+ else header->FileAttr = 0x81b6 | header->FileAttr;
+ break;
+ }
+
+ item->iMode = header->FileAttr;
+ item->iUID = geteuid();
+ item->iGID = getegid();
+ item->m_time = rar_time_to_unix(header->FileTime);
+ item->c_time = item->m_time;
+ item->a_time = item->m_time;
+
+ // Add item to the global list and continue with next file
+ filelist_tree_add_item(globs->files, header->FileName, item, 0);
+ int PASCAL res2 = RARProcessFile(handle, RAR_SKIP, NULL, NULL);
+ if (res2) printf("RARProcessFile result = %d\n", res2);
+ }
+// printf("\nRARReadHeader result = %d\n", res);
+ if (res != ERAR_END_ARCHIVE) {
+ fprintf(stderr, "(EE) VFSOpen: RARReadHeader result = %d\n", res);
+ Result = cVFS_Failed;
+ if ((res == ERAR_MISSING_PASSWORD) || ((res == ERAR_BAD_DATA) && (globs->passwd_callback)))
+ Result = cVFS_BadPassword;
+ }
+ free(header);
+
+ res = RARCloseArchive(handle);
+ if (res) {
+ fprintf(stderr, "(EE) VFSOpen: RARCloseArchive result = %d\n", res);
+ }
+ } else {
+ fprintf(stderr, "(EE) VFSOpen: error occured when opening archive: OpenResult = %d\n", archive_data->OpenResult);
+ Result = cVFS_Failed;
+ }
+
+ free(archive_data);
+ fprintf(stderr, "(II) VFSOpen: done. \n");
+ if (globs->need_password) printf("Password present.\n");
+ printf("\n\nList of items:\n");
+ filelist_tree_print(globs->files);
+
+ return Result;
+}
+
+
+TVFSResult VFSClose(struct TVFSGlobs *globs)
+{
+ if (globs) {
+ fprintf(stderr, "(II) VFSClose: Freeing objects...\n");
+ if (globs->vfs_filelist) vfs_filelist_free(globs->vfs_filelist);
+ if (globs->files) filelist_tree_free(globs->files);
+ if (globs->archive_path) free(globs->archive_path);
+ if (globs->curr_dir) free(globs->curr_dir);
+ if (globs->password) free(globs->password);
+ }
+ return cVFS_OK;
+}
+
+char *VFSGetPath(struct TVFSGlobs *globs)
+{
+ return include_trailing_path_sep(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->total_size;
+}
+
+
+
+
+/******************************************************************************************************/
+
+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");
+ if (globs->password) free(globs->password);
+ globs->password = strdup(pass);
+ 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)
+{
+ printf("(WW) VFSMkDir: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSRemove(struct TVFSGlobs *globs, const char *APath)
+{
+ printf("(WW) VFSRemove: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSRename(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName)
+{
+ printf("(WW) VFSRename: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSMakeSymLink(struct TVFSGlobs *globs, const char *NewFileName, const char *PointTo)
+{
+ printf("(WW) VFSMakeSymLink: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChmod(struct TVFSGlobs *globs, const char *FileName, const uint Mode)
+{
+ printf("(WW) VFSChmod: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChown(struct TVFSGlobs *globs, const char *FileName, const uint UID, const uint GID)
+{
+ printf("(WW) VFSChown: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChangeTimes(struct TVFSGlobs *globs, char *APath, long mtime, long atime)
+{
+ printf("(WW) VFSChangeTimes: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+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("(WW) VFSIsOnSameFS: Not supported in UNRAR plugin.\n");
+ return TRUE;
+}
+
+int VFSTwoSameFiles(struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ printf("(WW) VFSTwoSameFiles: Not supported in ZIP archives, comparing by paths.\n");
+ return compare_two_same_files(Path1, Path2);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+
+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);
+
+ TVFSResult Result = cVFS_OK;
+
+ char *src;
+ if (! IS_DIR_SEP(*sSrcName)) src = g_build_path("/", globs->curr_dir, sSrcName, NULL);
+ else src = g_strdup(sSrcName);
+
+ printf("(II) VFSCopyOut: new src path: '%s'\n", src);
+
+// printf("(II) VFSCopyOut: pCallBackProgress = 0x%lX, data = 0x%lX\n", (unsigned long int)pCallBackProgress, (unsigned long int)data);
+ globs->extract_callback_data = data;
+ globs->extract_callback_func = pCallBackProgress;
+
+ HANDLE PASCAL handle;
+ struct RAROpenArchiveDataEx *archive_data;
+
+ archive_data = (struct RAROpenArchiveDataEx*) malloc(sizeof(struct RAROpenArchiveDataEx));
+ memset(archive_data, 0, sizeof(struct RAROpenArchiveDataEx));
+ archive_data->ArcName = globs->archive_path;
+ archive_data->CmtBuf = NULL;
+ archive_data->CmtBufSize = 0;
+ archive_data->OpenMode = RAR_OM_EXTRACT;
+
+ handle = RAROpenArchiveEx(archive_data);
+// printf(" handle = %lu \n", (unsigned long int)handle);
+// printf(" archive_data->OpenResult = %d \n", archive_data->OpenResult);
+// printf(" archive_data->CmtState = %d \n", archive_data->CmtState);
+// printf(" archive_data->CmtSize = %d \n", archive_data->CmtSize);
+// printf("sizeof(TVFSResult) = %ld \n", sizeof(TVFSResult));
+
+ if ((handle) && (! archive_data->OpenResult))
+ {
+ // Set callbacks
+// printf(" setting callback: globs = 0x%lX, (unsigned long int)globs = 0x%lX, (LONG)globs = 0x%lX\n", globs, (unsigned long int)globs, (LONG)globs);
+ RARSetCallback(handle, unrar_callback, (LONG)globs);
+// RARSetChangeVolProc(handle, unrar_changevol_proc);
+// RARSetProcessDataProc(handle, unrar_process_data_proc);
+
+ if (globs->password) {
+ printf("(II) VFSCopyOut: Setting password... \n");
+ RARSetPassword(handle, globs->password);
+ }
+
+ struct RARHeaderDataEx *header;
+ header = (struct RARHeaderDataEx*) malloc(sizeof(struct RARHeaderDataEx));
+ memset(header, 0, sizeof(struct RARHeaderDataEx));
+ header->CmtBuf = NULL;
+ header->CmtBufSize = 0;
+
+ int res = 0;
+ while ((res = RARReadHeaderEx(handle, header)) == 0)
+ {
+ char *ssrc = src;
+ char *asrc = header->FileName;
+ if (IS_DIR_SEP(*ssrc)) ssrc++;
+ if (IS_DIR_SEP(*asrc)) asrc++;
+ if (strcmp(ssrc, asrc) == 0) {
+// fprintf(stderr, "(II) VFSCopyOut: extract_file_path(sDstName) = '%s', extract_file_name(sDstName) = '%s' \n", extract_file_path(sDstName), extract_file_name(sDstName));
+ globs->extract_done = 0;
+ globs->extract_file_size = (u_int64_t)((u_int64_t)(header->UnpSizeHigh * 0x100000000) + (u_int64_t)header->UnpSize);
+ globs->extract_cancelled = FALSE;
+
+ int res2 = RARProcessFile(handle, RAR_EXTRACT, NULL, (char *)sDstName);
+
+ if (globs->extract_cancelled) Result = cVFS_Cancelled;
+ else
+ if (res2) {
+ fprintf(stderr, "(EE) VFSCopyOut: RARProcessFile result = %d\n", res2);
+ Result = cVFS_ReadErr;
+ }
+ break;
+ } else {
+ int res2 = RARProcessFile(handle, RAR_SKIP, NULL, NULL);
+ if (res2) {
+ fprintf(stderr, "(EE) VFSCopyOut: RARProcessFile result = %d\n", res2);
+ Result = cVFS_ReadErr;
+ }
+ }
+ }
+
+ if ((res != ERAR_END_ARCHIVE) && (res)) {
+ fprintf(stderr, "(EE) VFSCopyOut: RARReadHeader result = %d\n", res);
+ switch (res) {
+ case ERAR_NO_MEMORY:
+ case ERAR_SMALL_BUF:
+ Result = cVFS_mallocFailed;
+ break;
+ case ERAR_BAD_DATA:
+ case ERAR_BAD_ARCHIVE:
+ case ERAR_UNKNOWN_FORMAT:
+ case ERAR_EOPEN:
+ case ERAR_ECLOSE:
+ case ERAR_EREAD:
+ Result = cVFS_ReadErr;
+ break;
+ case ERAR_ECREATE:
+ case ERAR_EWRITE:
+ Result = cVFS_WriteErr;
+ break;
+ case ERAR_MISSING_PASSWORD:
+ Result = cVFS_BadPassword;
+ break;
+ case ERAR_UNKNOWN:
+ default:
+ Result = cVFS_WriteErr;
+ break;
+ }
+ }
+
+ free(header);
+
+ res = RARCloseArchive(handle);
+ if (res) {
+ fprintf(stderr, "(EE) VFSCopyOut: RARCloseArchive result = %d\n", res);
+ Result = cVFS_ReadErr;
+ }
+ } else {
+ fprintf(stderr, "(EE) VFSCopyOut: error occured when opening archive: OpenResult = %d\n", archive_data->OpenResult);
+ Result = cVFS_ReadErr;
+ }
+
+ free(archive_data);
+ g_free(src);
+
+ fprintf(stderr, "(II) VFSCopyOut: finished. \n");
+ return Result;
+}
+
+TVFSResult VFSCopyIn(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, TVFSCopyCallBackFunc pCallBackProgress, void *data, int Append)
+{
+ printf("(WW) VFSCopyIn: Not supported in UNRAR plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+
+
+
+/**********
+ * TODO:
+ * - no error reporting when archive is corrupted
+ * - archive testing (needs new VFS API)
+ *
+ ***/