diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-06-08 11:04:43 +0200 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2008-06-08 11:04:43 +0200 |
| commit | 16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d (patch) | |
| tree | 3d22f54f7298f81b18ed66d05a62fa8bfab359ab /libarchive/libarchive.c | |
| download | tuxcmd-modules-16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d.tar.xz | |
Initial commitv0.6.36release-0.6.36-dev
Diffstat (limited to 'libarchive/libarchive.c')
| -rw-r--r-- | libarchive/libarchive.c | 623 |
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) + * + ***/ |
