Created
April 24, 2023 12:24
-
-
Save ImSingee/165ae13e56ef15fdc0c40b7ef927a33c to your computer and use it in GitHub Desktop.
Embed data in a Go program and generate new executable (just a demo, not optimized for production)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io" | |
"os" | |
) | |
const flagStart = `-----{% start %}-----` | |
const flagEnd = `-----{% end %}-----` | |
func Self() string { | |
exe, err := os.Executable() | |
if err != nil { | |
panic(err) | |
} | |
return exe | |
} | |
func main() { | |
self := Self() | |
selfFile, err := os.Open(self) | |
if err != nil { | |
panic("open self failed " + err.Error()) | |
} | |
defer selfFile.Close() | |
newOffset, err := selfFile.Seek(-int64(len(flagEnd)), 2) | |
if err != nil { | |
panic("seek self failed " + err.Error()) | |
} | |
buf, err := io.ReadAll(selfFile) | |
if err != nil { | |
panic("read self end failed " + err.Error()) | |
} | |
alreadyAppendData := string(buf) == flagEnd | |
endAt := newOffset + int64(len(flagEnd)) | |
var embedData []byte | |
if alreadyAppendData { | |
// search start flag | |
_, err = selfFile.Seek(0, 0) | |
if err != nil { | |
panic("seek self to start failed " + err.Error()) | |
} | |
readStartAt, err := searchInReader(selfFile, []byte(flagStart)) | |
if err != nil { | |
panic("search start flag failed " + err.Error()) | |
} | |
_, err = selfFile.Seek(int64(readStartAt), 0) | |
if err != nil { | |
panic("seek self to start flag failed " + err.Error()) | |
} | |
allData, err := io.ReadAll(selfFile) | |
if err != nil { | |
panic("read from start flag to end failed " + err.Error()) | |
} | |
embedData = allData[:len(allData)-len(flagEnd)] | |
endAt = int64(readStartAt - len(flagStart)) | |
} | |
if len(embedData) != 0 { | |
fmt.Println("Embed Data Found:") | |
fmt.Println("=============") | |
fmt.Println(string(embedData)) | |
fmt.Println("=============") | |
} | |
var newEmbedData []byte | |
if len(os.Args) > 1 { | |
newEmbedData = []byte(os.Args[1]) | |
} else { | |
fmt.Println("Exit") | |
return | |
} | |
newFile, err := os.CreateTemp(".", "new-*") | |
if err != nil { | |
panic("create temp file failed " + err.Error()) | |
} | |
//defer newFile.Close() | |
_, err = selfFile.Seek(0, 0) | |
if err != nil { | |
panic("seek self to start failed " + err.Error()) | |
} | |
_, err = io.CopyN(newFile, selfFile, endAt) | |
if err != nil && err != io.EOF { | |
panic("copy self to new file failed " + err.Error()) | |
} | |
_, err = newFile.Write([]byte(flagStart)) | |
if err != nil { | |
panic("write new start flag failed " + err.Error()) | |
} | |
_, err = newFile.Write(newEmbedData) | |
if err != nil { | |
panic("write new embed data failed " + err.Error()) | |
} | |
_, err = newFile.Write([]byte(flagEnd)) | |
if err != nil { | |
panic("write new end flag failed " + err.Error()) | |
} | |
err = newFile.Close() | |
if err != nil { | |
panic("save new file failed " + err.Error()) | |
} | |
fmt.Println("new file saved to " + newFile.Name()) | |
_ = os.Chmod(newFile.Name(), 0755) | |
} | |
func searchInReader(r io.Reader, data []byte) (int, error) { | |
// production note: we cannot read whole file since it may be too large | |
all, err := io.ReadAll(r) | |
if err != nil { | |
return -1, err | |
} | |
found := bytes.LastIndex(all, data) | |
if found == -1 { | |
return -1, fmt.Errorf("not found") | |
} | |
return found + len(data), nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment