| 86 | } |
| 87 | |
| 88 | func (a *atomicFile) Close() (err error) { |
| 89 | a.closedMu.Lock() |
| 90 | defer a.closedMu.Unlock() |
| 91 | |
| 92 | if a.closed { |
| 93 | return nil |
| 94 | } |
| 95 | a.closed = true |
| 96 | |
| 97 | defer func() { |
| 98 | if err != nil { |
| 99 | _ = os.Remove(a.f.Name()) // ignore errors |
| 100 | } |
| 101 | }() |
| 102 | // The order of operations here is: |
| 103 | // 1. sync |
| 104 | // 2. close |
| 105 | // 3. rename |
| 106 | // While the ordering of 2 and 3 is not important on Unix-like operating systems, Windows cannot rename an open |
| 107 | // file. By closing first, we allow the rename operation to succeed. |
| 108 | if err = a.f.Sync(); err != nil { |
| 109 | return fmt.Errorf("failed to sync temp file %q: %w", a.f.Name(), err) |
| 110 | } |
| 111 | if err = a.f.Close(); err != nil { |
| 112 | return fmt.Errorf("failed to close temp file %q: %w", a.f.Name(), err) |
| 113 | } |
| 114 | if err = os.Rename(a.f.Name(), a.name); err != nil { |
| 115 | return fmt.Errorf("failed to rename %q to %q: %w", a.f.Name(), a.name, err) |
| 116 | } |
| 117 | return nil |
| 118 | } |
| 119 | |
| 120 | func (a *atomicFile) Cancel() error { |
| 121 | a.closedMu.Lock() |