summaryrefslogtreecommitdiff
path: root/libarchive/libarchive.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 /libarchive/libarchive.c
downloadtuxcmd-modules-release-0.6.36-dev.tar.xz
Diffstat (limited to 'libarchive/libarchive.c')
-rw-r--r--libarchive/libarchive.c623
1 files changed, 623 insertions, 0 deletions
diff --git a/libarchive/libarchive.c b/libarchive/libarchive.c
new file mode 100644
index 0000000..5554cab
--- /dev/null
+++ b/libarchive/libarchive.c
@@ -0,0 +1,623 @@
+/* libarchive plugin for Tux Commander
+ * version 0.0.4, designed for libarchive 2.4.17
+ * Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ * Check for updates on tuxcmd.sourceforge.net
+ *
+ * Uses libarchive library
+ * Copyright (c) 2003-2007 Tim Kientzle
+ *
+ *
+
+
+ * 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 <fcntl.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"
+
+#include <archive.h>
+#include <archive_entry.h>
+
+
+
+#define VERSION "0.0.4"
+#define BUILD_DATE "2008-05-18"
+#define DEFAULT_BLOCK_SIZE 65536
+
+
+
+
+
+/******************************************************************************************************/
+/** Auxiliary classes */
+/************** ****************/
+
+
+
+// Declaration of the global plugin object
+struct TVFSGlobs {
+ TVFSLogFunc log_func;
+ char *curr_dir;
+ char *archive_path;
+
+ unsigned long block_size;
+
+ struct PathTree *files;
+ struct VfsFilelistData *vfs_filelist;
+
+ u_int64_t total_size;
+};
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+// Basic initialization functions
+int VFSAllocNeeded()
+{
+ return sizeof(struct TVFSGlobs);
+}
+
+void VFSInit(struct TVFSGlobs *globs, TVFSLogFunc log_func)
+{
+ globs->block_size = DEFAULT_BLOCK_SIZE;
+ globs->log_func = log_func;
+ if (globs->log_func != NULL) globs->log_func((char*)"libarchive plugin: VFSInit");
+}
+
+void VFSDestroy(struct TVFSGlobs *globs)
+{
+ if (globs->log_func != NULL) globs->log_func((char*)"libarchive plugin: VFSDestroy");
+}
+
+int VFSVersion()
+{
+ return 3;
+}
+
+struct TVFSInfo VFSGetInfo()
+{
+ struct TVFSInfo module_info;
+ module_info.Name = "libarchive plugin";
+ module_info.Description = "libarchive archiving plugin";
+ char *s = (char*)malloc(255);
+ snprintf(s, 255, "version %s, build date: %s\nusing %s\n",
+ VERSION, BUILD_DATE, ARCHIVE_LIBRARY_VERSION);
+ module_info.About = strdup(s);
+ free(s);
+ s = (char*)malloc(255);
+ snprintf(s, 255, "Plugin Copyright (C) 2008 Tomáš Bžatek\nlibarchive sources Copyright (c) 2003-2007 Tim Kientzle");
+ module_info.Copyright = strdup(s);
+ return module_info;
+}
+
+char *VFSGetPrefix(struct TVFSGlobs *globs)
+{
+ return globs->archive_path;
+}
+
+char *VFSGetExts()
+{
+ return (char*)"tar;gz;bz2;tgz;cpio;iso;a;deb";
+}
+
+
+/**************************************************************************************************************************************/
+/**************************************************************************************************************************************/
+
+static TVFSResult libarchive_open(struct archive **a, const char *filename, size_t block_size)
+{
+ int r;
+
+ *a = archive_read_new();
+
+ // Register supported formats
+
+ archive_read_support_compression_all(*a);
+ archive_read_support_format_all(*a);
+
+/*
+ archive_read_support_compression_bzip2(*a);
+ archive_read_support_compression_gzip(*a);
+ archive_read_support_compression_compress(*a);
+ archive_read_support_compression_none(*a);
+ archive_read_support_format_tar(*a);
+ archive_read_support_format_cpio(*a);
+ archive_read_support_format_ar(*a);
+ archive_read_support_format_empty(*a);
+ archive_read_support_format_gnutar(*a);
+ archive_read_support_format_iso9660(*a);
+ archive_read_support_format_cpio(*a);
+*/
+
+ r = archive_read_open_file(*a, filename, block_size);
+ if (r) {
+ fprintf(stderr, "(EE) libarchive_open: error occured when opening archive: %s\n", archive_error_string(*a));
+ return cVFS_Failed;
+ }
+ return cVFS_OK;
+}
+
+
+
+TVFSResult VFSOpen(struct TVFSGlobs *globs, char *sName)
+{
+ 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;
+ fprintf(stderr, "(--) VFSOpen: trying to open archive '%s'...\n", globs->archive_path);
+
+ TVFSResult Result;
+ struct archive *a;
+ struct archive_entry *entry;
+ int r;
+
+ Result = libarchive_open(&a, globs->archive_path, globs->block_size);
+ if (Result == cVFS_OK)
+ {
+ for (;;) {
+ entry = NULL;
+ r = archive_read_next_header(a, &entry);
+ if (r == ARCHIVE_EOF) {
+ break;
+ } else
+ if (r == ARCHIVE_WARN) {
+ log("(WW) VFSOpen: file '%s' - libarchive warning: '%s'\n", archive_entry_pathname(entry), archive_error_string(a));
+ } else
+ if (r != ARCHIVE_OK) {
+ fprintf(stderr, "(EE) VFSOpen: error occured while reading archive: '%s'\n", archive_error_string(a));
+ Result = cVFS_Failed;
+ break;
+ }
+
+ log("found file: %s, mode = %x\n", archive_entry_pathname(entry), archive_entry_mode(entry));
+
+ // 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)archive_entry_size(entry);
+ globs->total_size += item->iSize;
+
+ mode_t mode = archive_entry_mode(entry);
+ item->iMode = archive_entry_mode(entry);
+ if (S_ISREG(mode)) item->ItemType = vRegular;
+ else if (S_ISDIR(mode)) item->ItemType = vDirectory;
+ else if (S_ISCHR(mode)) item->ItemType = vChardev;
+ else if (S_ISBLK(mode)) item->ItemType = vBlockdev;
+ else if (S_ISFIFO(mode)) item->ItemType = vFifo;
+ else if (S_ISLNK(mode)) item->ItemType = vSymlink;
+ else if (S_ISSOCK(mode)) item->ItemType = vSock;
+
+ if (item->ItemType == vSymlink)
+ item->sLinkTo = strdup(archive_entry_symlink(entry));
+
+ item->iUID = geteuid();
+ item->iGID = getegid();
+ item->m_time = archive_entry_mtime(entry);
+ item->c_time = archive_entry_ctime(entry);
+ item->a_time = archive_entry_atime(entry);
+
+ // Add item to the global list and continue with next file
+ filelist_tree_add_item(globs->files, archive_entry_pathname(entry), item, 0);
+ }
+ archive_read_close(a);
+ }
+ archive_read_finish(a);
+ fprintf(stderr, "(II) VFSOpen: done. \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);
+ }
+ 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("(WW) VFSSetPassword: Not supported in libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+int VFSGetPasswordRequired(struct TVFSGlobs *globs)
+{
+ 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 libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSRemove(struct TVFSGlobs *globs, const char *APath)
+{
+ printf("(WW) VFSRemove: Not supported in libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSRename(struct TVFSGlobs *globs, const char *sSrcName, const char *sDstName)
+{
+ printf("(WW) VFSRename: Not supported in libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSMakeSymLink(struct TVFSGlobs *globs, const char *NewFileName, const char *PointTo)
+{
+ printf("(WW) VFSMakeSymLink: Not supported in libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChmod(struct TVFSGlobs *globs, const char *FileName, const uint Mode)
+{
+ printf("(WW) VFSChmod: Not supported in libarchive 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 libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+TVFSResult VFSChangeTimes(struct TVFSGlobs *globs, char *APath, long mtime, long atime)
+{
+ printf("(WW) VFSChangeTimes: Not supported in libarchive 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 libarchive plugin.\n");
+ return TRUE;
+}
+
+int VFSTwoSameFiles(struct TVFSGlobs *globs, const char *Path1, const char *Path2)
+{
+ printf("(WW) VFSTwoSameFiles: Not supported in libarchive, comparing by paths.\n");
+ return compare_two_same_files(Path1, Path2);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////
+
+
+
+
+/**
+ * The following code has been stolen from archive_read_data_into_fd.c (libarchive sources) and modified to allow progress callbacks
+ * Quote: "This implementation minimizes copying of data and is sparse-file aware."
+ **/
+static TVFSResult
+my_archive_read_data_into_fd(struct archive *a, struct archive_entry *entry, const char *sDstName, size_t max_block, TVFSCopyCallBackFunc pCallBackProgress, void *data, int Append)
+{
+ int r;
+ int fd;
+ const void *buff;
+ size_t size, bytes_to_write;
+ ssize_t bytes_written, total_written;
+ off_t offset;
+ off_t output_offset;
+ u_int64_t file_size;
+ gboolean cancel = FALSE;
+
+
+ printf("(II) my_archive_read_data_into_fd: extracting to '%s', Append = %d\n", sDstName, Append);
+
+ if (Append) fd = open(sDstName, O_APPEND | O_WRONLY);
+ else fd = open(sDstName, O_CREAT | O_WRONLY);
+ if (fd < 0) {
+ fprintf(stderr, "(EE) my_archive_read_data_into_fd: error occured while extracting data: %s\n", strerror(errno));
+ return cVFS_Failed;
+ }
+
+ total_written = 0;
+ output_offset = 0;
+ file_size = (u_int64_t)archive_entry_size(entry);
+
+ while ((r = archive_read_data_block(a, &buff, &size, &offset)) == ARCHIVE_OK) {
+ const char *p = buff;
+ if (offset > output_offset) {
+ lseek(fd, offset - output_offset, SEEK_CUR);
+ output_offset = offset;
+ }
+ while (size > 0) {
+ if (cancel) break;
+ bytes_to_write = size;
+ if (bytes_to_write > max_block)
+ bytes_to_write = max_block;
+ bytes_written = write(fd, p, bytes_to_write);
+ if (bytes_written < 0) {
+ fprintf(stderr, "(EE) my_archive_read_data_into_fd: error occured while extracting data: %s\n", strerror(errno));
+ return cVFS_Failed;
+ }
+ output_offset += bytes_written;
+ total_written += bytes_written;
+ p += bytes_written;
+ size -= bytes_written;
+
+ log(" (II) my_archive_read_data_into_fd: bytes_written = %u, total_written = %u\n", bytes_written, total_written);
+ if (pCallBackProgress) {
+ if (! pCallBackProgress(total_written, file_size, data)) {
+ cancel = TRUE;
+ break;
+ }
+// usleep(100000);
+ }
+ }
+ }
+
+ if ((close(fd)) || ((r != ARCHIVE_OK) && (r != ARCHIVE_EOF))) {
+ fprintf(stderr, "(EE) my_archive_read_data_into_fd: error closing extracted file: %s\n", strerror(errno));
+ return cVFS_WriteErr;
+ }
+ if (cancel) {
+ if (unlink(sDstName))
+ fprintf(stderr, "(EE) my_archive_read_data_into_fd: error unlinking cancelled extraction: %s\n", strerror(errno));
+ return cVFS_Cancelled;
+ }
+ printf("(II) my_archive_read_data_into_fd: done.\n");
+ return cVFS_OK;
+}
+
+
+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);
+
+ 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);
+
+
+ TVFSResult Result;
+ struct archive *a;
+ struct archive_entry *entry;
+ int r;
+
+ Result = libarchive_open(&a, globs->archive_path, globs->block_size);
+ if (Result == cVFS_OK)
+ {
+ for (;;) {
+ entry = NULL;
+ r = archive_read_next_header(a, &entry);
+ if (r == ARCHIVE_EOF) {
+ break;
+ } else
+ if (r == ARCHIVE_WARN) {
+ log("(WW) VFSOpen: file '%s' - libarchive warning: '%s'\n", archive_entry_pathname(entry), archive_error_string(a));
+ } else
+ if (r != ARCHIVE_OK) {
+ fprintf(stderr, "(EE) VFSCopyOut: error occured while reading archive: '%s'\n", archive_error_string(a));
+ Result = cVFS_Failed;
+ break;
+ }
+
+// printf ("found file: %s, mode = %x\n", archive_entry_pathname(entry), archive_entry_mode(entry));
+ char *ssrc = src;
+ const char *asrc = archive_entry_pathname(entry);
+ if (IS_DIR_SEP(*ssrc)) ssrc++;
+ if (IS_DIR_SEP(*asrc)) asrc++;
+
+// printf ("strcmp: '%s' vs. '%s'\n", ssrc, asrc);
+ if (strcmp(ssrc, asrc) == 0) {
+// printf("--> found file, extracting\n");
+ fprintf(stderr, "(II) VFSCopyOut: extract_file_path(sDstName) = '%s', extract_file_name(sDstName) = '%s' \n", extract_file_path(sDstName), extract_file_name(sDstName));
+
+ Result = my_archive_read_data_into_fd(a, entry, sDstName, globs->block_size, pCallBackProgress, data, Append);
+ break;
+ }
+ }
+ archive_read_close(a);
+ }
+ archive_read_finish(a);
+ 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 libarchive plugin.\n");
+ return cVFS_Not_Supported;
+}
+
+
+
+
+/**********
+ * TODO:
+ * - archive testing (needs new VFS API)
+ * - write support
+ * - support creating new archives (needs new VFS API)
+ *
+ ***/