Home > OS >  How to write the output of an executable binary into memory rather than disk
How to write the output of an executable binary into memory rather than disk

Time:08-31

I got a binary that works like the below:

> ./my_bin raw.avi output_file.avi

output_file.avi is what I want, some verbose information will print in the terminal when the job is succeeded, like:

Copyright 2022 Company Inc... Success.

I want to run this command inside my code and redirect the output_file.avi into some byte array so that I don't have to read it from disk and delete it. My approach looks like the below Golang snippet:

func wrongOne(stdin []byte) ([]byte, error) {
    inBuf := bytes.NewBuffer(stdin)
    outBuf := bytes.NewBuffer(nil)
    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")
    cmd.Stdin = inBuf
    cmd.Stdout = outBuf
    err := cmd.Run()
    if err != nil {
        return nil, err
    }
    return outBuf.Bytes(), nil // wrong
}

However, the return byte array is longer than the below approach, which leads to failure on the MD5 check.

func correctOne(stdin []byte) ([]byte, error) {
    inBuf := bytes.NewBuffer(stdin)
    cmd := exec.Command("./my_bin", "/dev/stdin", "output_file")
    cmd.Stdin = inBuf
    err := cmd.Run()
    if err != nil {
        return nil, err
    }
    return os.ReadFile("output_file")
}

the wrongOne function can be modified to following code to be correct:

func modifiedWrongOne(stdin []byte) ([]byte, error) {
    inBuf := bytes.NewBuffer(stdin)
    outBuf := bytes.NewBuffer(nil)
    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/stdout")
    cmd.Stdin = inBuf
    cmd.Stdout = outBuf
    err := cmd.Run()
    if err != nil {
        return nil, err
    }
    correct, _ := correctOne(stdin)
    return outBuf.Bytes()[:len(correct)], nil // diff
}

I presume that the output verbose information is included in the /dev/stdout so that the wrongOne function doesn't works. i.e.,

the output of wrongOne = the output of correctOne []byte{"Copyright 2022 Company Inc... Success."}

Is there any solution that I can get the output_file.avi in the pipe without save it as file and read it from disk? Thanks!

CodePudding user response:

The command writes the copyright notice to stdout. To avoid commingling the copyright notice with the output file, use a file other than /dev/stdout as the output file.

The function below uses Cmd.ExtraFiles to connect a pipe to fd 3 in the child process. The function copies data from the pipe to a byte buffer and returns those bytes to the caller.

func otherOne(stdin []byte) ([]byte, error) {
    r, w, err := os.Pipe()
    if err != nil {
        return nil, err
    }
    defer r.Close()
    defer w.Close()

    cmd := exec.Command("./my_bin", "/dev/stdin", "/dev/fd/3")
    cmd.Stdin = bytes.NewReader(stdin)
    cmd.ExtraFiles = []*os.File{w} // The first file is fd 3.
    if err := cmd.Start(); err != nil {
        return nil, err
    }
    w.Close()
    var outbuf bytes.Buffer
    if _, err := io.Copy(&outbuf, r); err != nil {
        return nil, err
    }
    if err := cmd.Wait(); err != nil {
        return nil, err
    }
    return outbuf.Bytes(), nil
}

CodePudding user response:

maybe you can try to create ram disk.

  • Related