(opts editOpts, tree *sops.Tree, dataKey []byte)
| 118 | } |
| 119 | |
| 120 | func editTree(opts editOpts, tree *sops.Tree, dataKey []byte) ([]byte, error) { |
| 121 | // Create temporary file for editing |
| 122 | tmpdir, err := os.MkdirTemp("", "") |
| 123 | if err != nil { |
| 124 | return nil, common.NewExitError(fmt.Sprintf("Could not create temporary directory: %s", err), codes.CouldNotWriteOutputFile) |
| 125 | } |
| 126 | defer os.RemoveAll(tmpdir) |
| 127 | |
| 128 | tmpfile, err := os.Create(filepath.Join(tmpdir, filepath.Base(opts.InputPath))) |
| 129 | if err != nil { |
| 130 | return nil, common.NewExitError(fmt.Sprintf("Could not create temporary file: %s", err), codes.CouldNotWriteOutputFile) |
| 131 | } |
| 132 | // Ensure that in any case, the temporary file is always closed. |
| 133 | defer tmpfile.Close() |
| 134 | // Ensure that the file is read+write for owner only. |
| 135 | if err = tmpfile.Chmod(0600); err != nil { |
| 136 | return nil, common.NewExitError(fmt.Sprintf("Could not change permissions of temporary file to read-write for owner only: %s", err), codes.CouldNotWriteOutputFile) |
| 137 | } |
| 138 | |
| 139 | tmpfileName := tmpfile.Name() |
| 140 | |
| 141 | // Catch when the user presses Ctrl+C, or kills SOPS. |
| 142 | ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) |
| 143 | defer stop() |
| 144 | |
| 145 | result := make(chan editTreeResult, 1) |
| 146 | |
| 147 | // This goroutine handles signals that exit SOPS, that usually lead to termination |
| 148 | // before editTree() can clean up the temporary directory and file. |
| 149 | go func() { |
| 150 | <-ctx.Done() |
| 151 | result <- createError(&cancelError{}) |
| 152 | }() |
| 153 | |
| 154 | // This goroutine handles regular execution of editing. |
| 155 | go func() { |
| 156 | result <- editTreeImpl(tmpfile, tmpfileName, opts, tree, dataKey) |
| 157 | }() |
| 158 | |
| 159 | // Wait until the first result shows up (either an exit is requested, or editTreeImpl returns). |
| 160 | res := <-result |
| 161 | return res.value, res.err |
| 162 | } |
| 163 | |
| 164 | func editTreeImpl(tmpfile *os.File, tmpfileName string, opts editOpts, tree *sops.Tree, dataKey []byte) editTreeResult { |
| 165 | // Write to temporary file |
no test coverage detected