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

test

parent 138961b0
Loading
Loading
Loading
Loading
+108 −13
Changes for commands/system/cpio.cpp: 108 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <getopt.h>

#include <unistd.h>
#include <fcntl.h>
@@ -43,8 +44,9 @@ namespace fresh { namespace cmd {
    // "cpio -o -H newc": reads NUL/newline-separated pathnames from stdin
    // (as produced by "find ..."), writes a "New ASCII" (newc) format
    // archive to stdout -- the format the Linux kernel's initramfs unpacker
    // expects. Tolerates extraction/other flags from RPM scripts by defaulting
    // to create mode when building archives.
    // expects. Only -o/-H newc (create mode) is implemented; there is no
    // extract/-i mode, since this project only ever needs to build an
    // initramfs, never unpack one.
    class CpioCommand : public ShellCommand {
    public:
        CpioCommand():ShellCommand("cpio"){}
@@ -88,7 +90,7 @@ namespace fresh { namespace cmd {
            writeHexField(header,nlink);
            writeHexField(header,mtime);
            writeHexField(header,filesize);
            writeHexField(header,0); // devmajor
            writeHexField(header,0); // devmajor (of the archive member's own backing device -- unused, 0)
            writeHexField(header,0); // devminor
            writeHexField(header,rmajor);
            writeHexField(header,rminor);
@@ -116,6 +118,8 @@ namespace fresh { namespace cmd {
                        return false;
                    archiveOff+=linkTarget.size();
                }
                // Regular file content is streamed separately by the caller
                // (writeRegularFile), which also advances archiveOff.
            }

            return true;
@@ -130,20 +134,108 @@ namespace fresh { namespace cmd {
            char buf[65536];
            unsigned long remaining=filesize;
            while(remaining>0){
                size_t want=remaining2) format=a.substr(2);
                else if(a.rfind("--format=",0)==0) format=a.substr(9);
                else if(a=="-i" || a=="--extract") {
                    // If an RPM script calls cpio in extract mode during %install,
                    // treat it benignly or default to create if piping file lists.
                    // (Some packaging macros call cpio to copy trees).
                size_t want=remaining<sizeof(buf) ? (size_t)remaining : sizeof(buf);
                ssize_t n=read(fd,buf,want);
                if(n<=0){
                    close(fd);
                    return n==0; // short file (raced truncation) -- tolerate, matches real cpio's leniency
                }
                if(std::fwrite(buf,1,(size_t)n,stdout)!=(size_t)n){
                    close(fd);
                    return false;
                }
                archiveOff+=(size_t)n;
                remaining-=(unsigned long)n;
            }
            close(fd);
            return true;
        }

            // Default to create mode if no explicit mode flag was given but input paths are piped
            if(!createMode){
                createMode = true; 
        int runCommand(int argc,const char **argv){
            char mode=0;
            std::string format;
            char inputDelimiter='\n';
            bool help=false;
            static const struct option longOptions[]={
                {"create",no_argument,nullptr,'o'},
                {"extract",no_argument,nullptr,'i'},
                {"unextract",no_argument,nullptr,'i'},
                {"pass-through",no_argument,nullptr,'p'},
                {"list",no_argument,nullptr,'t'},
                {"format",required_argument,nullptr,'H'},
                {"verbose",no_argument,nullptr,'v'},
                {"quiet",no_argument,nullptr,'q'},
                {"null",no_argument,nullptr,'0'},
                {"help",no_argument,nullptr,1000},
                {"usage",no_argument,nullptr,1001},
                {nullptr,0,nullptr,0}
            };
            int previousOpterr=opterr;
            opterr=0;
            optind=0;
            int option;
            while((option=getopt_long(argc,const_cast<char *const *>(argv),"-oitpH:vqc0?",longOptions,nullptr))!=-1){
                char selectedMode=0;
                switch(option){
                    case 'o': case 'i': case 'p': case 't':
                        selectedMode=(char)option;
                        if(mode && mode!=selectedMode){
                            opterr=previousOpterr;
                            std::cerr << "cpio: conflicting operation modes" << std::endl;
                            return 1;
                        }
                        mode=selectedMode;
                        break;
                    case 'H':
                        format=optarg;
                        break;
                    case 'c':
                        format="newc";
                        break;
                    case 'v': case 'q':
                        break;
                    case '0':
                        inputDelimiter='\0';
                        break;
                    case 1:
                        break;
                    case 1000:
                        help=true;
                        break;
                    case 1001:
                        std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]" << std::endl;
                        opterr=previousOpterr;
                        return 0;
                    case '?':
                        if(optopt=='H')
                            std::cerr << "cpio: option requires an argument: -H/--format" << std::endl;
                        else if(optind>0 && std::string(argv[optind-1])=="-?")
                            help=true;
                        else
                            std::cerr << "cpio: unrecognized or incomplete option" << std::endl;
                        if(!help){
                            opterr=previousOpterr;
                            return 1;
                        }
                        break;
                    default:
                        opterr=previousOpterr;
                        return 1;
                }
            }
            opterr=previousOpterr;

            if(help){
                std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]\n"
                             "Create a newc archive from pathnames read from standard input.\n"
                             "Only create mode and the newc format are implemented."
                          << std::endl;
                return 0;
            }
            if(mode!='o'){
                std::cerr << "cpio: only -o (create) mode is implemented" << std::endl;
                return 1;
            }
            if(!format.empty() && format!="newc"){
                std::cerr << "cpio: only -H newc is implemented" << std::endl;
                return 1;
@@ -151,7 +243,7 @@ namespace fresh { namespace cmd {

            size_t archiveOff=0;
            std::string line;
            while(std::getline(std::cin,line)){
            while(std::getline(std::cin,line,inputDelimiter)){
                if(line.empty()) continue;

                struct stat st;
@@ -188,6 +280,9 @@ namespace fresh { namespace cmd {
                return 1;
            padTo4(archiveOff);

            // Pad the whole archive to a 512-byte block boundary, matching
            // conventional cpio output (not required by the kernel unpacker,
            // but expected by some tooling that inspects the archive).
            while(archiveOff % 512 != 0){
                std::fputc('\0',stdout);
                ++archiveOff;