Gottox / sqsh-tools

🗜️ fast r/o squashfs implementation written in C.
https://gottox.de/sqsh-tools/
BSD 2-Clause "Simplified" License
37 stars 4 forks source link

Examples #33

Closed probonopd closed 1 year ago

probonopd commented 1 year ago

Is your feature request related to a problem? Please describe.

I'd like to consume libsqsh in a Qt based application to extract files from squashfs to files and/or memory. For this reason, I'd like to have it wrapped in a C++ class.

Describe the solution you'd like

Something along those lines with a working .cpp implementation

#ifndef SQSH_FSEXTRACTOR_H
#define SQSH_FSEXTRACTOR_H

#include <QString>
#include <QByteArray>
#include <QList>
#include <QDir>

#include "SqshFSInfo.h" // Include the previously defined SqshFSInfo class

class SqshFSExtractor
{
public:
    SqshFSExtractor(const QString &imagePath);
    ~SqshFSExtractor();

    SqshFSInfo getFileInfo(const QString &filePath) const;
    QList<SqshFSInfo> listFilesRecursively() const; // Recursive listing; like find /
    QList<SqshFSInfo> listFiles() const; // Directory listing, like ls /

    bool extractToFile(const QString &filePath, const QString &outputFilePath);
    bool extractRecursively(const QString &sourceDir, const QString &targetDir);
    QByteArray extractToMemory(const QString &filePath);

private:
    // Add any private members or helper functions here as needed
};

#endif // SQSH_FSEXTRACTOR_H
#ifndef SQSH_FSINFO_H
#define SQSH_FSINFO_H

#include <QString>
#include <QVector>

enum class FileType {
    File,
    Directory,
    Symlink,
    Device,
    Other
};

class SqshFSInfo
{
public:
    SqshFSInfo(const QString &name, FileType type, qint64 size = 0);
    ~SqshFSInfo();

    QVector<SqshFSInfo> getChildren() const;
    QString getName() const;
    FileType getType() const;
    qint64 getSize() const;

private:
    QString name;
    FileType type;
    qint64 size;
    QVector<SqshFSInfo> children;
};

#endif // SQSH_FSINFO_H

Additional context

Unfortunately, I am not able to do this with the current documentation. Do you think it can be done? Would you be able to present a sample implementation?

Gottox commented 1 year ago

I pretty much think, that a C++ wrapper should be achievable. While libsqsh is written in C, the headers are C++ compatible (otherwise consider this a bug and worth reporting).

The implementation stub you provided is a bit naive, as it expects the whole file tree to be loaded into memory, which will not scale with larger archives.

Unfortunately writing a wrapper is out of scope for this project and while I can give you hints, I can't provide you with any good examples, as I'm not experienced with C++.

probonopd commented 1 year ago

Thanks for your quick response. You are right about extractRecursively, it should be done differently.

To get things started, could you point me at working C examples for how to:

That would be a tremendous help to get me started. Thank you!

Gottox commented 1 year ago

Thanks for the input. That's a great way to improve the documentation!

  • Extract one (small-ish, think icon) known file to memory (following symlinks if needed)

sqsh_file_content(archive, path) will do exactly that. It is one of the lesser tested areas in libsqsh, so if you find issues, I'm eager to fix them!

  • List all files in one defined directory (e.g., the root directory)

I just wrote an example for this use case. Have a look in examples in the main branch.

probonopd commented 1 year ago

Thanks @Gottox. Very useful indeed!

I am having issues building it. I could not figure out a way to compile just the example using the given meson.build (but I will need to use CMake anyway). Using this

cmake_minimum_required(VERSION 3.0)
project(libsqsh-examples)

# Set the C++ standard to C++11 or higher
set(CMAKE_CXX_STANDARD 11)

# Find libsqsh using pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBSQSH REQUIRED libsqsh)

# Add the include directories for libsqsh
include_directories(${LIBSQSH_INCLUDE_DIRS})

# Build the 'list_files' executable
add_executable(list_files list_files.c)
target_link_libraries(list_files ${LIBSQSH_LIBRARIES})

# Build the 'list_files_ll' executable
add_executable(list_files_ll list_files_ll.c)
target_link_libraries(list_files_ll ${LIBSQSH_LIBRARIES})

it builds :+1: Maybe others will find this information useful, too.

Gottox commented 1 year ago

A few bits and pieces of the API are unstable till v1.0, so if you run into problems, either wait for the 0.6.0 release or use the main branch for now.

probonopd commented 1 year ago

I can confirm that the example works for me using the main branch.

% mksquashfs squashfs-root test.sfs -comp zstd

% /tmp/libsqsh/examples/build/list_files test.sfs 
.DirIcon
AppRun
appimagetool.desktop
appimagetool.png
usr

% /tmp/libsqsh/examples/build/list_files_ll test.sfs 
.DirIcon
AppRun
appimagetool.desktop
appimagetool.png
usr
probonopd commented 1 year ago

The only thing that does not work yet is extracting the data if the file is actually a symlink. Can you point me to a solution for this? E.g., how to (recursively) resolve symlinks. Thanks again for your help, which is tremendous.

Gottox commented 1 year ago

I think that's an actual bug. At least that's a blind spot in the unit tests.

probonopd commented 1 year ago

Should I open a new issue for it?

Gottox commented 1 year ago

Yes please! - I created a unit test for following symlinks, but I cannot reproduce the issue at the moment.

Gottox commented 1 year ago

At least the high level API (sqsh_file_contents, sqsh_directory_list) should work transparently on symlinks.