Commit c6c00a1e authored by jan.koester's avatar jan.koester
Browse files

zstd support modprobe depmod

parent 835c4e11
Loading
Loading
Loading
Loading
+25 −18
Changes for commands/modutils/depmod.cpp: 25 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -41,16 +41,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "shell.h"
#include "xz/xz.h"
#include "zstd/zstd.h"

namespace fresh { namespace cmd {

    namespace {
        const char kXzSuffix[]=".xz";
        const size_t kXzSuffixLen=sizeof(kXzSuffix)-1;
        // The compressed-module suffixes: CONFIG_MODULE_COMPRESS_XZ's
        // ".ko.xz" and CONFIG_MODULE_COMPRESS_ZSTD's ".ko.zst" (0: neither).
        size_t compressedSuffixLen(const std::string &s){
            for(const char *suf: {".xz",".zst"}){
                size_t n=std::strlen(suf);
                if(s.size()>n && s.compare(s.size()-n,n,suf)==0) return n;
            }
            return 0;
        }

        bool hasXzSuffix(const std::string &s){
            return s.size()>kXzSuffixLen &&
                   s.compare(s.size()-kXzSuffixLen,kXzSuffixLen,kXzSuffix)==0;
        // Reads and decompresses a ".ko.xz" or ".ko.zst" file into IMAGE.
        bool readCompressed(const std::string &path,std::vector<unsigned char> &image){
            std::ifstream in(path,std::ios::binary);
            if(!in.is_open()) return false;
            std::vector<unsigned char> compressed(
                (std::istreambuf_iterator<char>(in)),std::istreambuf_iterator<char>());
            return compressedSuffixLen(path)==4 ? fresh::zstd::decompress(compressed,image)
                                                : fresh::xz::decompress(compressed,image);
        }
    }

@@ -105,17 +118,13 @@ namespace fresh { namespace cmd {
        }

        // Opens PATH and reads its ".modinfo" section, transparently
        // decompressing first if PATH ends in ".xz" -- a ".ko.xz" file's
        // decompressing first if PATH ends in ".xz" or ".zst" -- a compressed module's
        // raw bytes are LZMA2-compressed data, not a valid ELF file, so
        // readModinfoSection() above can't be pointed at it directly.
        static bool readModinfoSectionFromFile(const std::string &path,std::vector<char> &out){
            if(hasXzSuffix(path)){
                std::ifstream in(path,std::ios::binary);
                if(!in.is_open()) return false;
                std::vector<unsigned char> compressed(
                    (std::istreambuf_iterator<char>(in)),std::istreambuf_iterator<char>());
            if(compressedSuffixLen(path)){
                std::vector<unsigned char> image;
                if(!fresh::xz::decompress(compressed,image)) return false;
                if(!readCompressed(path,image)) return false;
                std::string blob(reinterpret_cast<char *>(image.data()),image.size());
                std::istringstream mem(blob,std::ios::binary);
                return readModinfoSection(mem,out);
@@ -189,18 +198,17 @@ namespace fresh { namespace cmd {
                }
                // Strip a compressed-module suffix before the ".ko" check
                // below, matching CONFIG_MODULE_COMPRESS_XZ -- this only
                // recognizes ".ko.xz" specifically, not every ".xz" file
                // recognizes ".ko.xz"/".ko.zst" specifically, not every ".xz" file
                // that might otherwise be sitting under /lib/modules.
                std::string base=name;
                if(hasXzSuffix(base))
                    base.resize(base.size()-kXzSuffixLen);
                base.resize(base.size()-compressedSuffixLen(base));
                if(base.size()>3 && base.substr(base.size()-3)==".ko")
                    out.push_back(full);
            }
            closedir(d);
        }

        // Strips a compressed-module suffix (".ko.xz") before the ".ko"
        // Strips a compressed-module suffix (".ko.xz", ".ko.zst") before the ".ko"
        // check, matching the real kernel's own CONFIG_MODULE_COMPRESS_XZ
        // naming -- same fix as modprobe's own moduleName(), which this
        // must stay consistent with: modprobe looks up modules.dep entries
@@ -208,8 +216,7 @@ namespace fresh { namespace cmd {
        static std::string moduleName(const std::string &koPath){
            size_t slash=koPath.find_last_of('/');
            std::string base=(slash==std::string::npos) ? koPath : koPath.substr(slash+1);
            if(hasXzSuffix(base))
                base.resize(base.size()-kXzSuffixLen);
            base.resize(base.size()-compressedSuffixLen(base));
            if(base.size()>3 && base.substr(base.size()-3)==".ko")
                base=base.substr(0,base.size()-3);
            for(auto &c: base) if(c=='-') c='_'; // matches kernel's own name normalization
+23 −15
Changes for commands/modutils/modprobe.cpp: 23 added lines, 15 removed lines.
Original line number Diff line number Diff line
@@ -46,16 +46,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "shell.h"
#include "xz/xz.h"
#include "zstd/zstd.h"

namespace fresh { namespace cmd {

    namespace {
        const char kXzSuffix[]=".xz";
        const size_t kXzSuffixLen=sizeof(kXzSuffix)-1;
        // The compressed-module suffixes: CONFIG_MODULE_COMPRESS_XZ's
        // ".ko.xz" and CONFIG_MODULE_COMPRESS_ZSTD's ".ko.zst" (0: neither).
        size_t compressedSuffixLen(const std::string &s){
            for(const char *suf: {".xz",".zst"}){
                size_t n=std::strlen(suf);
                if(s.size()>n && s.compare(s.size()-n,n,suf)==0) return n;
            }
            return 0;
        }

        bool hasXzSuffix(const std::string &s){
            return s.size()>kXzSuffixLen &&
                   s.compare(s.size()-kXzSuffixLen,kXzSuffixLen,kXzSuffix)==0;
        // Reads and decompresses a ".ko.xz" or ".ko.zst" file into IMAGE.
        bool readCompressed(const std::string &path,std::vector<unsigned char> &image){
            std::ifstream in(path,std::ios::binary);
            if(!in.is_open()) return false;
            std::vector<unsigned char> compressed(
                (std::istreambuf_iterator<char>(in)),std::istreambuf_iterator<char>());
            return compressedSuffixLen(path)==4 ? fresh::zstd::decompress(compressed,image)
                                                : fresh::xz::decompress(compressed,image);
        }

        // kmod's alias_normalize(): '-' and '_' are the same in module names
@@ -94,7 +107,7 @@ namespace fresh { namespace cmd {
    public:
        ModprobeCommand():ShellCommand("modprobe"){}

        // Strips a compressed-module suffix (".ko.xz") before the ".ko"
        // Strips a compressed-module suffix (".ko.xz", ".ko.zst") before the ".ko"
        // check below, matching the real Linux kernel's own
        // CONFIG_MODULE_COMPRESS_XZ naming -- without this, a compressed
        // module's canonical name would keep the whole ".ko.xz" tail
@@ -103,15 +116,14 @@ namespace fresh { namespace cmd {
        static std::string moduleName(const std::string &koPath){
            size_t slash=koPath.find_last_of('/');
            std::string base=(slash==std::string::npos) ? koPath : koPath.substr(slash+1);
            if(hasXzSuffix(base))
                base.resize(base.size()-kXzSuffixLen);
            base.resize(base.size()-compressedSuffixLen(base));
            if(base.size()>3 && base.substr(base.size()-3)==".ko")
                base=base.substr(0,base.size()-3);
            for(auto &c: base) if(c=='-') c='_';
            return base;
        }

        // A ".ko.xz" path is decompressed into memory first and loaded via
        // A ".ko.xz"/".ko.zst" path is decompressed into memory first and loaded via
        // init_module() (the buffer-based syscall); finit_module() (the fd-
        // based one, used for an ordinary uncompressed ".ko") can't be
        // handed a compressed file directly -- the kernel's own module
@@ -119,13 +131,9 @@ namespace fresh { namespace cmd {
        // job (real kmod does exactly this same in-memory decompress before
        // init_module()).
        static bool loadOne(const std::string &koPath,const std::string &params){
            if(hasXzSuffix(koPath)){
                std::ifstream in(koPath,std::ios::binary);
                if(!in.is_open()) return false;
                std::vector<unsigned char> compressed(
                    (std::istreambuf_iterator<char>(in)),std::istreambuf_iterator<char>());
            if(compressedSuffixLen(koPath)){
                std::vector<unsigned char> image;
                if(!fresh::xz::decompress(compressed,image)){
                if(!readCompressed(koPath,image)){
                    errno=EINVAL;
                    return false;
                }
+1 −0
Changes for lib/CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -2,3 +2,4 @@ add_subdirectory(awk)
add_subdirectory(bison)
add_subdirectory(flex)
add_subdirectory(xz)
add_subdirectory(zstd)
+3 −0
Changes for lib/zstd/CMakeLists.txt: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
# Like lib/xz: only modprobe/depmod use the decoder, they link into fresh
# via target_sources() already, so this does the same.
target_sources(fresh PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/zstd.cpp)

lib/zstd/zstd.cpp

0 → 100644
+531 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading