Skip to content
Snippets Groups Projects
Commit f1ff4c3e authored by Mohamed Amine Younes Bouacida's avatar Mohamed Amine Younes Bouacida Committed by Adrien Béraud
Browse files

archiver: add libarchive

Change-Id: I2ff7d879de55e18bedcbddce74f743ffe8755ca6
parent acf910d4
No related branches found
No related tags found
No related merge requests found
......@@ -144,6 +144,7 @@ if(MSVC)
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/include;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/msgpack-c/include;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/libarchive/libarchive;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/jsoncpp/include;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/yaml-cpp/include;"
"${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib/include;"
......@@ -165,6 +166,7 @@ if(MSVC)
"_WIN32_WINNT=0x0A00;"
"ASIO_STANDALONE;"
"STATIC_GETOPT;"
"LIBARCHIVE_STATIC;"
"OPENDHT_PROXY_CLIENT;"
"OPENDHT_PROXY_SERVER;"
"OPENDHT_PUSH_NOTIFICATIONS;"
......@@ -226,40 +228,41 @@ if(MSVC)
# Dependencies
################################################################################
set(libAdditionalDependencies "${CMAKE_STATIC_LINKER_FLAGS} /LTCG ws2_32.lib
advapi32.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avcodec.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avdevice.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avfilter.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avformat.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avutil.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swresample.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swscale.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libgnutls.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/lib_json.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libopendht.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/argon2/vs2015/Argon2Ref/vs2015/build/Argon2Ref.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/secp256k1.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/yaml-cpp/msvc/Release/libyaml-cppmd.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/portaudio.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libupnp.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/natpmp/msvc/Release/natpmp.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-core-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-simple-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua2-lib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua-lib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-ua-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjmedia/lib/pjmedia-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib-util/lib/pjlib-util-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib/lib/pjlib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjnath/lib/pjnath-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/fmt/msvc/Release/fmt.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/http_parser/x64/Release/http-parser.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/asio/asio/msvc/x64/Release/asio.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/libeay32.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/ssleay32.lib
set(libAdditionalDependencies "${CMAKE_STATIC_LINKER_FLAGS} /LTCG ws2_32.lib
advapi32.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avcodec.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avdevice.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avfilter.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avformat.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avutil.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swresample.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swscale.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libgnutls.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/lib_json.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libopendht.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/argon2/vs2015/Argon2Ref/vs2015/build/Argon2Ref.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/secp256k1.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/yaml-cpp/msvc/Release/libyaml-cppmd.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/portaudio.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libupnp.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/natpmp/msvc/Release/natpmp.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/libarchive/msvc/libarchive/Release/archive_static.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-core-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-simple-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua2-lib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua-lib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-ua-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjmedia/lib/pjmedia-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib-util/lib/pjlib-util-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib/lib/pjlib-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjnath/lib/pjnath-x86_64-x64-vc15-Release.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/fmt/msvc/Release/fmt.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/http_parser/x64/Release/http-parser.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/asio/asio/msvc/x64/Release/asio.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/libeay32.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/ssleay32.lib
${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/speexdsp/lib/libspeexdsp.lib
/ignore:4006
/ignore:4006
"
)
......
......@@ -10,7 +10,8 @@
"secp256k1",
"speexdsp",
"upnp",
"yaml-cpp"
"yaml-cpp",
"libarchive"
],
"configuration": "ReleaseLib_win32",
"project_paths": ["ring-daemon.vcxproj"]
......
......@@ -302,6 +302,7 @@ PKG_CHECK_MODULES(PJPROJECT, libpjproject,, AC_MSG_ERROR([Missing pjproject file
PKG_CHECK_MODULES([YAMLCPP], [yaml-cpp >= 0.5.1],, AC_MSG_ERROR([yaml-cpp not found]))
PKG_CHECK_MODULES([JSONCPP], [jsoncpp >= 1.6.5],, AC_MSG_ERROR([jsoncpp not found]))
PKG_CHECK_MODULES([ARCHIVE], [libarchive >= 3.0],, AC_MSG_ERROR([libarchive not found]))
if test "${HAVE_ANDROID}" = "1"; then
dnl Check for OpenSL
......
2f9e2a551a6bcab56fb1a030b5d656df7299a3d151465aa02f0420d344d2fada49dee4755b3abff9095f62519e14dc9af8afa1695ecc6d5fdb4f0b28e6ede852 libarchive-3.4.0.tar.gz
{
"name": "libarchive",
"version": "a53d711261f4d5bf2104d9c3616a8602a45ba196",
"url": "https://github.com/libarchive/libarchive/archive/__VERSION__.tar.gz",
"deps": [],
"patches": [],
"win_patches": [],
"project_paths": ["msvc/libarchive/archive_static.vcxproj"],
"with_env" : "",
"custom_scripts": {
"pre_build": [
"mkdir msvc & cd msvc & cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib -DENABLE_TEST=OFF -DENABLE_TAR=OFF -DENABLE_CPIO=OFF -DENABLE_CAT=OFF -DENABLE_LIBXML2=OFF -G %CMAKE_GENERATOR%"
],
"build": [],
"post_build": []
}
}
\ No newline at end of file
# LIBARCHIVE
LIBARCHIVE_VERSION := 3.4.0
LIBARCHIVE_URL := https://github.com/libarchive/libarchive/releases/download/v$(LIBARCHIVE_VERSION)/libarchive-$(LIBARCHIVE_VERSION).tar.gz
PKGS += libarchive
ifeq ($(call need_pkg,"libarchive >= 3.4.0"),)
PKGS_FOUND += libarchive
endif
LIBARCHIVE_CMAKECONF := \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_LIBDIR=lib \
-DENABLE_TEST=OFF \
-DENABLE_TAR=OFF \
-DENABLE_CPIO=OFF \
-DENABLE_CAT=OFF \
-DENABLE_LIBXML2=OFF
$(TARBALLS)/libarchive-$(LIBARCHIVE_VERSION).tar.gz:
$(call download,$(LIBARCHIVE_URL))
.sum-libarchive: libarchive-$(LIBARCHIVE_VERSION).tar.gz
libarchive: libarchive-$(LIBARCHIVE_VERSION).tar.gz
$(UNPACK)
$(MOVE)
.libarchive: libarchive toolchain.cmake .sum-libarchive
cd $< && mkdir -p buildlib
ifdef HAVE_ANDROID
cd $< && cp -R contrib/android/include/* $(PREFIX)/include
endif
cd $< && cd buildlib && $(HOSTVARS) $(CMAKE) .. $(LIBARCHIVE_CMAKECONF)
cd $< && cd buildlib && $(MAKE) install
ifdef HAVE_LINUX
cd $< && cd $(PREFIX)/lib && rm libarchive.so*
endif
touch $@
......@@ -503,8 +503,8 @@ endif
echo "set(CMAKE_CXX_COMPILER $(CXX))" >> $@
echo "set(CMAKE_FIND_ROOT_PATH $(PREFIX))" >> $@
echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> $@
echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)" >> $@
echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> $@
echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)" >> $@
echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)" >> $@
echo "set(CMAKE_BUILD_TYPE Release)" >> $@
# Default pattern rules
......
......@@ -57,6 +57,7 @@ libring_la_LDFLAGS = \
@GNUTLS_LIBS@ \
@OPENDHT_LIBS@ \
@SECP256K1_LIBS@ \
@ARCHIVE_LIBS@ \
@ZLIB_LIBS@ \
@LIBSSL_LIBS@ \
@LIBCRYPTO_LIBS@ \
......
......@@ -32,6 +32,11 @@
#include <json/json.h>
#include <zlib.h>
extern "C" {
#include <archive.h>
#include <archive_entry.h>
}
#include <sys/stat.h>
#include <fstream>
......@@ -87,8 +92,8 @@ accountToJsonValue(const std::map<std::string, std::string>& details) {
int
exportAccounts(const std::vector<std::string>& accountIDs,
const std::string& filepath,
const std::string& password)
const std::string& filepath,
const std::string& password)
{
if (filepath.empty() || !accountIDs.size()) {
JAMI_ERR("Missing arguments");
......@@ -304,4 +309,207 @@ openGzip(const std::string& path, const char *mode)
#endif
}
// LIBARCHIVE DEFINITIONS
//==========================
using ArchivePtr = std::unique_ptr<archive, void(*)(archive*)>;
using ArchiveEntryPtr = std::unique_ptr<archive_entry, void(*)(archive_entry*)>;
struct DataBlock {
const void *buff;
size_t size;
int64_t offset;
};
long readDataBlock(const ArchivePtr &a, DataBlock &b)
{
return archive_read_data_block(a.get(), &b.buff, &b.size, &b.offset);
}
long writeDataBlock(const ArchivePtr &a, DataBlock &b)
{
return archive_write_data_block(a.get(), b.buff, b.size, b.offset);
}
ArchivePtr createArchiveReader() {
ArchivePtr archivePtr{archive_read_new(), [](archive * a) {
archive_read_close(a);
archive_read_free(a);
}};
return archivePtr;
}
static ArchivePtr createArchiveDiskWriter() {
return {archive_write_disk_new(), [](archive * a) {
archive_write_close(a);
archive_write_free(a);
}};
}
//==========================
std::vector<std::string> listArchiveContent(const std::string &archivePath)
{
std::vector<std::string> fileNames;
ArchivePtr archiveReader = createArchiveReader();
struct archive_entry* entry;
int r;
// Set reader formats(archive) and filters(compression)
archive_read_support_filter_all(archiveReader.get());
archive_read_support_format_all(archiveReader.get());
// Try to read the archive
if ((r = archive_read_open_filename(archiveReader.get(), archivePath.c_str(), 10240))) {
throw std::runtime_error(archive_error_string(archiveReader.get()));
}
while (archive_read_next_header(archiveReader.get(), &entry) == ARCHIVE_OK) {
std::string fileEntry = archive_entry_pathname(entry) ? archive_entry_pathname(entry) : "Undefined";
fileNames.push_back(fileEntry);
}
return fileNames;
}
void uncompressArchive(const std::string &archivePath, const std::string &dir, const FileMatchPair& f)
{
int r;
ArchivePtr archiveReader = createArchiveReader();
ArchivePtr archiveDiskWriter = createArchiveDiskWriter();
struct archive_entry* entry;
int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_NO_HFS_COMPRESSION;
// Set reader formats(archive) and filters(compression)
archive_read_support_filter_all(archiveReader.get());
archive_read_support_format_all(archiveReader.get());
// Set written files flags and standard lookup(uid/gid)
archive_write_disk_set_options(archiveDiskWriter.get(), flags);
archive_write_disk_set_standard_lookup(archiveDiskWriter.get());
// Try to read the archive
if ((r = archive_read_open_filename(archiveReader.get(), archivePath.c_str(), 10240))) {
throw std::runtime_error("Open Archive: " + archivePath + "\t" +
archive_error_string(archiveReader.get()));
}
while(true) {
// Read headers until End of File
r = archive_read_next_header(archiveReader.get(), &entry);
if( r == ARCHIVE_EOF) {
break;
}
std::string fileEntry = archive_entry_pathname(entry) ? archive_entry_pathname(entry) : "Undefined";
if (r != ARCHIVE_OK) {
throw std::runtime_error("Read file pathname: " + fileEntry + "\t" +
archive_error_string(archiveReader.get()));
}
// File is ok, copy its header to the ext writer
const auto& fileMatchPair = f(fileEntry);
if(fileMatchPair.first) {
std::string entryDestinationPath = dir + DIR_SEPARATOR_CH + fileMatchPair.second;
archive_entry_set_pathname(entry, entryDestinationPath.c_str());
r = archive_write_header(archiveDiskWriter.get(), entry);
if (r != ARCHIVE_OK) {
// Rollback if failed at a write operation
fileutils::removeAll(dir);
throw std::runtime_error("Write file header: " + fileEntry + "\t" +
archive_error_string(archiveDiskWriter.get()));
} else {
// Here both the reader and the writer have moved past the headers
// Copying the data content
DataBlock db;
while(true) {
r = readDataBlock(archiveReader,db);
if (r == ARCHIVE_EOF) {
break;
}
if (r != ARCHIVE_OK) {
throw std::runtime_error("Read file data: " + fileEntry + "\t" +
archive_error_string(archiveReader.get()));
}
r = writeDataBlock(archiveDiskWriter, db);
if (r != ARCHIVE_OK) {
// Rollback if failed at a write operation
fileutils::removeAll(dir);
throw std::runtime_error("Write file data: " + fileEntry + "\t" +
archive_error_string(archiveDiskWriter.get()));
}
}
}
}
}
}
std::vector<uint8_t> readFileFromArchive(const std::string &archivePath,
const std::string &fileRelativePathName)
{
long r;
ArchivePtr archiveReader = createArchiveReader();
struct archive_entry* entry;
// Set reader formats(archive) and filters(compression)
archive_read_support_filter_all(archiveReader.get());
archive_read_support_format_all(archiveReader.get());
// Try to read the archive
if ((r = archive_read_open_filename(archiveReader.get(), archivePath.c_str(), 10240))) {
throw std::runtime_error("Open Archive: " + archivePath + "\t" +
archive_error_string(archiveReader.get()));
}
while(true) {
// Read headers until End of File
r = archive_read_next_header(archiveReader.get(), &entry);
if( r == ARCHIVE_EOF) {
break;
}
std::string fileEntry = archive_entry_pathname(entry) ? archive_entry_pathname(entry) : "";
if (r != ARCHIVE_OK) {
throw std::runtime_error("Read file pathname: " + fileEntry + "\t" +
archive_error_string(archiveReader.get()));
}
// File is ok and the reader has moved past the header
if(fileEntry == fileRelativePathName){
// Copying the data content
DataBlock db;
std::vector<uint8_t> fileContent;
while(true) {
r = readDataBlock(archiveReader,db);
if (r == ARCHIVE_EOF) {
return fileContent;
}
if (r != ARCHIVE_OK) {
throw std::runtime_error("Read file data: " + fileEntry + "\t" +
archive_error_string(archiveReader.get()));
}
if (fileContent.size() < static_cast<size_t>(db.offset)) {
fileContent.resize(db.offset);
}
auto dat = static_cast<const uint8_t*>(db.buff);
// push the buffer data in the string stream
fileContent.insert(fileContent.end(), dat, dat+db.size);
}
}
}
throw std::runtime_error("File " + fileRelativePathName + " not found in the archive");
}
}} // namespace jami::archiver
......@@ -25,6 +25,7 @@
#include <string>
#include <vector>
#include <map>
#include <functional>
typedef struct gzFile_s *gzFile;
......@@ -35,6 +36,8 @@ namespace jami {
*/
namespace archiver {
using FileMatchPair = std::function<std::pair<bool,const std::string>(const std::string&)>;
/**
* Create a protected archive containing a list of accounts
* @param accountIDs The accounts to exports
......@@ -43,8 +46,8 @@ namespace archiver {
* @returns 0 for OK, error code otherwise
*/
int exportAccounts(const std::vector<std::string>& accountIDs,
const std::string& filepath,
const std::string& password);
const std::string& filepath,
const std::string& password);
/**
* Read a protected archive and add accounts found in it
......@@ -81,6 +84,37 @@ std::vector<uint8_t> decompressGzip(const std::string& path);
*/
gzFile openGzip(const std::string& path, const char *mode);
/**
* @brief listArchiveContent
* @param archivePath
* @return list of relative file path names
*/
std::vector<std::string> listArchiveContent(const std::string& archivePath);
/**
* @brief uncompressArchive Uncompresses an archive and puts the different files
* in dir folder according to a FileMatchPair f
* @param path
* @param dir
* @param f takes a file name relative path inside the archive like mysubfolder/myfile
* and returns a pair (bool, new file name relative path)
* Where the bool indicates if we should uncompress this file
* and the new file name relative path puts the file in the directory dir under a different
* relative path name like mynewsubfolder/myfile
* @return void
*/
void uncompressArchive(const std::string& path, const std::string &dir, const FileMatchPair& f);
/**
* @brief readFileFromArchive read a file from an archive without uncompressing
* the whole archive
* @param path archive path
* @param fileRelativePathName file path relative path name in the archive
* E.g: data/myfile.txt inside the archive
* @return fileContent std::vector<uint8_t> that contains the file content
*/
std::vector<uint8_t> readFileFromArchive(const std::string &path,
const std::string &fileRelativePathName);
}
} // namespace jami
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment