| 568 | } |
| 569 | |
| 570 | func (m *directManager) atomicWriteFile(fs wholeFileFS, filename string, data []byte, perm os.FileMode) error { |
| 571 | var randBytes [12]byte |
| 572 | if _, err := rand.Read(randBytes[:]); err != nil { |
| 573 | return fmt.Errorf("atomicWriteFile: %w", err) |
| 574 | } |
| 575 | |
| 576 | tmpName := fmt.Sprintf("%s.%x.tmp", filename, randBytes[:]) |
| 577 | defer fs.Remove(tmpName) |
| 578 | |
| 579 | if err := fs.WriteFile(tmpName, data, perm); err != nil { |
| 580 | return fmt.Errorf("atomicWriteFile: %w", err) |
| 581 | } |
| 582 | // Explicitly set the permissions on the temporary file before renaming |
| 583 | // it. This ensures that if we have a umask set which prevents creating |
| 584 | // world-readable files, the file will still have the correct |
| 585 | // permissions once it's renamed into place. See #12609. |
| 586 | if err := fs.Chmod(tmpName, perm); err != nil { |
| 587 | return fmt.Errorf("atomicWriteFile: Chmod: %w", err) |
| 588 | } |
| 589 | |
| 590 | return m.rename(tmpName, filename) |
| 591 | } |
| 592 | |
| 593 | // wholeFileFS is a high-level file system abstraction designed just for use |
| 594 | // by directManager, with the goal that it is easy to implement over wsl.exe. |