/* UNRAR plugin for Tux Commander * version 0.3.7, designed for unrar v3.8.2 * Copyright (C) 2008 Tomas Bzatek * 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 #include #include #include #include #include #include #include #include #include #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.3.7" #define BUILD_DATE "2009-10-25" #define DEFAULT_BLOCK_SIZE 65536 // Declaration of the global plugin object struct TVFSGlobs { TVFSLogFunc log_func; char *curr_dir; char *archive_path; gboolean need_password; gboolean failed_passwd_callback; gboolean volume_missing_abort; char *password; unsigned long block_size; struct PathTree *files; struct VfsFilelistData *vfs_filelist; int64_t total_size; int64_t extract_file_size; int64_t extract_done; gboolean extract_cancelled; TVFSAskQuestionCallback callback_ask_question; TVFSAskPasswordCallback callback_ask_password; TVFSProgressCallback callback_progress; void *callback_data; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////// // 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->block_size = DEFAULT_BLOCK_SIZE; globs->need_password = FALSE; globs->failed_passwd_callback = FALSE; globs->volume_missing_abort = FALSE; globs->password = NULL; 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("unrar 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("unrar plugin: VFSDestroy"); free (globs); } int VFSVersion() { return cVFSVersion; } struct TVFSInfo * VFSGetInfo() { struct TVFSInfo *module_info = g_malloc0 (sizeof (struct TVFSInfo)); module_info->ID = g_strdup ("unrar_plugin"); module_info->Name = g_strdup ("UNRAR plugin"); module_info->About = g_strdup_printf ("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->Copyright = g_strdup ("Plugin Copyright (C) 2007-2009 Tomáš Bžatek\nUNRAR sources Copyright (C) 2002-2008 Alexander Roshal"); return module_info; } char * VFSGetArchiveExts () { return g_strdup ("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); if (! UserData) { fprintf(stderr, "(WW) unrar_callback: UserData == NULL, exiting!\n"); return 0; } struct TVFSGlobs *globs = (struct TVFSGlobs *)UserData; // >= 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 (globs->callback_ask_question) { static const char *choices[] = { "Abort", /* response = 0 */ "Ignore", /* response = 1 */ NULL }; char *message, *s; int choice = -1; s = g_filename_to_utf8 ((char *)P1, -1, NULL, NULL, NULL); message = g_strdup_printf ("Archive is incomplete, volume missing: \n\n%s", s ? s : (char *)P1); globs->callback_ask_question (message, &choices[0], &choice, 0, globs->callback_data); g_free (message); if (s) g_free (s); if (choice != 1) globs->volume_missing_abort = TRUE; return -1; } else { 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); // printf(" (II) unrar_callback: globs = 0x%lX, UserData = 0x%lX \n", (unsigned long int)globs, UserData); if ((globs) && (globs->callback_progress)) { // 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->callback_progress(globs->extract_done, globs->extract_file_size, globs->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); char *passwd = NULL; int res = FALSE; globs->failed_passwd_callback = TRUE; if (globs->callback_ask_password) { res = globs->callback_ask_password ("The archive is encrypted and requires password", NULL, NULL, NULL, VFS_ASK_PASSWORD_NEED_PASSWORD | VFS_ASK_PASSWORD_ARCHIVE_MODE, NULL, &passwd, NULL, NULL, NULL, globs->callback_data); if (res && passwd) { fprintf(stderr, " (II) unrar_callback: setting password to '%s'\n", passwd); if (strlen (passwd) > 0) { strncpy((char *)P1, passwd, P2); if (globs->password) g_free (globs->password); globs->password = g_strdup (passwd); } g_free (passwd); } } if (res) return 0; else { globs->extract_cancelled = TRUE; return -1; } } } 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 VFSOpenArchive(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->failed_passwd_callback = FALSE; globs->volume_missing_abort = FALSE; fprintf(stderr, "(--) VFSOpenArchive: 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) VFSOpenArchive: 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 = (int64_t)((int64_t)(header->UnpSizeHigh * 0x100000000) + (int64_t)header->UnpSize); item->iPackedSize = (int64_t)((int64_t)(header->PackSizeHigh * 0x100000000) + (int64_t)header->PackSize); 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; // g_print (" valid = %d\n", g_utf8_validate (header->FileName, -1, NULL)); char *s; if (g_utf8_validate (header->FileName, -1, NULL)) s = g_strdup (header->FileName); else s = wide_to_utf8 (header->FileNameW); // g_print (" ansi = '%s'\n wide = '%ls'\n utf8 = '%s'\n", header->FileName, header->FileNameW, s); // Add item to the global list and continue with next file filelist_tree_add_item(globs->files, s, header->FileName, item, 0); g_free (s); 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 || globs->volume_missing_abort) { fprintf(stderr, "(EE) VFSOpenArchive: RARReadHeader result = %d\n", res); Result = cVFS_Failed; if ((res == ERAR_MISSING_PASSWORD) || ((res == ERAR_BAD_DATA) && (globs->failed_passwd_callback))) Result = cVFS_BadPassword; } free(header); res = RARCloseArchive(handle); if (res) { fprintf(stderr, "(EE) VFSOpenArchive: RARCloseArchive result = %d\n", res); } } else { fprintf(stderr, "(EE) VFSOpenArchive: error occured when opening archive: OpenResult = %d\n", archive_data->OpenResult); Result = cVFS_Failed; } free(archive_data); fprintf(stderr, "(II) VFSOpenArchive: 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 VFSGetPasswordRequired(struct TVFSGlobs *globs) { if (globs) return globs->need_password; return FALSE; } void VFSResetPassword(struct TVFSGlobs *globs) { if (globs && globs->password) { g_free (globs->password); globs->password = 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) { 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 RAR archives, comparing by paths.\n"); return compare_two_same_files(Path1, Path2); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////// TVFSResult VFSCopyToLocal(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, int Append) { 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); struct PathTree *node = filelist_tree_find_node_by_path(globs->files, sSrcName); if (! node) { fprintf(stderr, "(EE) VFSCopyToLocal: cannot find file '%s'\n", sSrcName); return cVFS_ReadErr; } TVFSResult Result = cVFS_OK; gboolean found = FALSE; char *src = node->original_pathstr; if (! src) { fprintf(stderr, "(WW) VFSCopyToLocal: cannot determine original filename\n"); src = (char *)sSrcName; } printf("(II) VFSCopyToLocal: new src path: '%s'\n", src); 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) VFSCopyToLocal: 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) VFSCopyToLocal: 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 = (int64_t)((int64_t)(header->UnpSizeHigh * 0x100000000) + (int64_t)header->UnpSize); globs->extract_cancelled = FALSE; found = TRUE; int res2 = RARProcessFile(handle, RAR_EXTRACT, NULL, (char *)sDstName); if (globs->extract_cancelled) { fprintf(stderr, "(WW) VFSCopyToLocal: cancelled !\n"); Result = cVFS_Cancelled; } else if (res2) { fprintf(stderr, "(EE) VFSCopyToLocal: RARProcessFile result = %d\n", res2); Result = cVFS_ReadErr; } break; } else { int res2 = RARProcessFile(handle, RAR_SKIP, NULL, NULL); if (res2) { fprintf(stderr, "(EE) VFSCopyToLocal: RARProcessFile result = %d\n", res2); Result = cVFS_ReadErr; } } } if ((res != ERAR_END_ARCHIVE) && (res)) { if (globs->extract_cancelled) { fprintf(stderr, "(WW) VFSCopyToLocal: cancelled !\n"); Result = cVFS_Cancelled; } else { fprintf(stderr, "(EE) VFSCopyToLocal: 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; if (globs->password) { g_free (globs->password); globs->password = NULL; } break; case ERAR_UNKNOWN: default: Result = cVFS_WriteErr; break; } } } free(header); res = RARCloseArchive(handle); if (res) { fprintf(stderr, "(EE) VFSCopyToLocal: RARCloseArchive result = %d\n", res); Result = cVFS_ReadErr; } } else { fprintf(stderr, "(EE) VFSCopyToLocal: error occured when opening archive: OpenResult = %d\n", archive_data->OpenResult); Result = cVFS_ReadErr; } free(archive_data); if ((! found) && Result == cVFS_OK) { fprintf(stderr, "(EE) VFSCopyToLocal: file not found in archive.\n"); Result = cVFS_ReadErr; } fprintf(stderr, "(II) VFSCopyToLocal: finished. \n"); return Result; } TVFSResult VFSCopyFromLocal(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName, int Append) { printf("(WW) VFSCopyFromLocal: Not supported in UNRAR plugin.\n"); return cVFS_Not_Supported; } /********** * TODO: * * - UTF-8, FName/FDisplayName and absolute/relative paths revision needed! * - find a reliable way to catch bad password errors and free the cached invalid password * - no error reporting when archive is corrupted -- hopefully fixed by ask_question callback * - archive testing (needs new VFS API) * ***/