| 127 | } |
| 128 | |
| 129 | func shadowCopyPluginToDir(file pluginFile, dir string) (string, error) { |
| 130 | source := filepath.Clean(file.Path) |
| 131 | tmp, errTemp := os.CreateTemp(dir, shadowPluginTempPrefix+file.ID+"-*"+filepath.Ext(source)) |
| 132 | if errTemp != nil { |
| 133 | return "", errTemp |
| 134 | } |
| 135 | tmpName := tmp.Name() |
| 136 | removeTemp := true |
| 137 | defer func() { |
| 138 | if removeTemp { |
| 139 | removeShadowPlugin(tmpName) |
| 140 | } |
| 141 | }() |
| 142 | |
| 143 | in, errOpen := os.Open(source) |
| 144 | if errOpen != nil { |
| 145 | _ = tmp.Close() |
| 146 | return "", errOpen |
| 147 | } |
| 148 | defer func() { |
| 149 | _ = in.Close() |
| 150 | }() |
| 151 | hasher := sha256.New() |
| 152 | size, errCopy := io.Copy(io.MultiWriter(tmp, hasher), in) |
| 153 | if errCopy != nil { |
| 154 | _ = tmp.Close() |
| 155 | return "", errCopy |
| 156 | } |
| 157 | if errClose := tmp.Close(); errClose != nil { |
| 158 | return "", errClose |
| 159 | } |
| 160 | digest := hex.EncodeToString(hasher.Sum(nil)) |
| 161 | target := shadowPluginPath(dir, file.ID, digest, filepath.Ext(source)) |
| 162 | if shadowPluginMatches(target, size, digest) { |
| 163 | return target, nil |
| 164 | } |
| 165 | if errRemove := os.Remove(target); errRemove != nil && !errors.Is(errRemove, os.ErrNotExist) { |
| 166 | if shadowPluginMatches(target, size, digest) { |
| 167 | return target, nil |
| 168 | } |
| 169 | removeShadowPlugin(target) |
| 170 | return "", fmt.Errorf("remove stale shadow plugin: %w", errRemove) |
| 171 | } |
| 172 | if errRename := os.Rename(tmpName, target); errRename != nil { |
| 173 | if shadowPluginMatches(target, size, digest) { |
| 174 | return target, nil |
| 175 | } |
| 176 | return "", fmt.Errorf("move shadow plugin: %w", errRename) |
| 177 | } |
| 178 | removeTemp = false |
| 179 | return target, nil |
| 180 | } |
| 181 | |
| 182 | func shadowPluginDir() (string, error) { |
| 183 | dir := filepath.Join(os.TempDir(), "cliproxy-pluginhost", shadowPluginProcessDirName(os.Getpid())) |