github.com/LanceLRQ/deer-common@v0.0.9-0.20210319081233-e8222ac018a8/utils/binary.go (about) 1 package utils 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/binary" 7 "github.com/LanceLRQ/deer-common/constants" 8 "github.com/LanceLRQ/deer-common/structs" 9 "github.com/pkg/errors" 10 "os" 11 "os/exec" 12 "path" 13 "path/filepath" 14 "runtime" 15 "strings" 16 "syscall" 17 ) 18 19 func IsExecutableFile(filePath string) (bool, error) { 20 fp, err := os.OpenFile(filePath, os.O_RDONLY|syscall.O_NONBLOCK, 0) 21 if err != nil { 22 return false, errors.Errorf("open file error") 23 } 24 defer fp.Close() 25 26 var magic uint32 = 0 27 err = binary.Read(fp, binary.BigEndian, &magic) 28 if err != nil { 29 return false, err 30 } 31 32 isExec := false 33 if runtime.GOOS == "darwin" { 34 isExec = magic == 0xCFFAEDFE || magic == 0xCEFAEDFE || magic == 0xFEEDFACF || magic == 0xFEEDFACE 35 } else if runtime.GOOS == "linux" { 36 isExec = magic == 0x7F454C46 37 } 38 return isExec, nil 39 } 40 41 func GetCompiledBinaryFileName(typeName, moduleName string) string { 42 prefix, ok := constants.TestlibBinaryPrefixs[typeName] 43 if !ok { 44 prefix = "" 45 } 46 return prefix + moduleName 47 } 48 49 // 根据配置文件将对应预编译文件转换成绝对路径 50 func GetCompiledBinaryFileAbsPath(typeName, moduleName, configDir string) (string, error) { 51 targetName := GetCompiledBinaryFileName(typeName, moduleName) 52 return filepath.Abs(path.Join(path.Join(configDir, "bin"), targetName)) 53 } 54 55 // 解析generator脚本 56 func ParseGeneratorScript(script string) (string, []string, error) { 57 vals := strings.Split(script, " ") 58 if len(vals) <= 1 { 59 return "", nil, errors.Errorf("generator calling script error") 60 } 61 return vals[0], vals[1:], nil 62 } 63 64 // 运行UnixShell,支持context 65 func RunUnixShell(options *structs.ShellOptions) (*structs.ShellResult, error) { 66 fpath, err := exec.LookPath(options.Name) 67 if err != nil { 68 return nil, err 69 } 70 result := structs.ShellResult{} 71 proc := exec.CommandContext(options.Context, fpath, options.Args...) 72 var stderr, stdout bytes.Buffer 73 74 if options.StdWriter != nil && options.StdWriter.Output != nil { 75 proc.Stdout = options.StdWriter.Output 76 } else { 77 proc.Stdout = &stdout 78 } 79 if options.StdWriter != nil && options.StdWriter.Error != nil { 80 proc.Stderr = options.StdWriter.Error 81 } else { 82 proc.Stderr = &stderr 83 } 84 85 if options.StdWriter != nil && options.StdWriter.Input != nil { 86 proc.Stdin = options.StdWriter.Input 87 } else { 88 stdin, err := proc.StdinPipe() 89 if err != nil { 90 return nil, err 91 } 92 if options.OnStart != nil { 93 err = options.OnStart(stdin) 94 if err != nil { 95 return nil, err 96 } 97 } 98 _ = stdin.Close() 99 } 100 101 //err = proc.Run() 102 if err := proc.Start(); err != nil { 103 return nil, err 104 } 105 106 err = proc.Wait() 107 108 if options.StdWriter == nil || options.StdWriter.Output == nil { 109 result.Stdout = stdout.String() 110 } 111 if options.StdWriter == nil || options.StdWriter.Error == nil { 112 result.Stderr = stderr.String() 113 } 114 result.ExitCode = proc.ProcessState.ExitCode() 115 result.Signal = int(proc.ProcessState.Sys().(syscall.WaitStatus).Signal()) 116 if err != nil { 117 result.Success = false 118 result.ErrorMessage = err.Error() 119 if serr := result.Stderr; serr == "" { 120 result.Stderr += err.Error() 121 } 122 return &result, nil 123 } 124 result.Success = true 125 return &result, nil 126 } 127 128 func CallGenerator(ctx context.Context, tc *structs.TestCase, configDir string) ([]byte, error) { 129 name, args, err := ParseGeneratorScript(tc.Generator) 130 if err != nil { 131 return nil, err 132 } 133 gBin, err := GetCompiledBinaryFileAbsPath("generator", name, configDir) 134 if err != nil { 135 return nil, err 136 } 137 rel, err := RunUnixShell(&structs.ShellOptions{ 138 Context: ctx, 139 Name: gBin, 140 Args: args, 141 StdWriter: nil, 142 OnStart: nil, 143 }) 144 if err != nil { 145 return nil, err 146 } 147 if rel.Success { 148 return []byte(rel.Stdout), nil 149 } else { 150 return nil, errors.Errorf("generator error") 151 } 152 } 153 154 // 判断是否是题目包 155 func IsZipFile(filePath string) (bool, error) { 156 fp, err := os.OpenFile(filePath, os.O_RDONLY|syscall.O_NONBLOCK, 0) 157 if err != nil { 158 return false, errors.Errorf("open file error") 159 } 160 defer fp.Close() 161 162 var magic uint32 = 0 163 err = binary.Read(fp, binary.BigEndian, &magic) 164 if err != nil { 165 return false, err 166 } 167 return magic == constants.ZipArchiveMagicCode, nil 168 } 169 170 // 判断是否是题目包 171 func IsProblemPackage(filePath string) (bool, error) { 172 fp, err := os.OpenFile(filePath, os.O_RDONLY|syscall.O_NONBLOCK, 0) 173 if err != nil { 174 return false, errors.Errorf("open file error") 175 } 176 defer fp.Close() 177 178 var magic uint16 = 0 179 err = binary.Read(fp, binary.BigEndian, &magic) 180 if err != nil { 181 return false, err 182 } 183 184 return magic == constants.ProblemPackageMagicCode, nil 185 }