-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add method AtomicWritePrivateFile in new diskutil package (#187)
Signed-off-by: Max Lambrecht <[email protected]>
- Loading branch information
Max Lambrecht
authored
Jun 1, 2023
1 parent
3ef177c
commit e957f82
Showing
4 changed files
with
129 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package diskutil | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
// Define the file mode for private files. | ||
const ( | ||
fileModePrivate = 0600 | ||
) | ||
|
||
// AtomicWritePrivateFile writes data to a file atomically. | ||
// The file is created with private permissions (0600). | ||
func AtomicWritePrivateFile(path string, data []byte) error { | ||
return atomicWrite(path, data, fileModePrivate) | ||
} | ||
|
||
func atomicWrite(path string, data []byte, mode os.FileMode) error { | ||
tmpPath := path + ".tmp" | ||
|
||
// Attempt to write to temporary file | ||
if err := write(tmpPath, data, mode); err != nil { | ||
return err | ||
} | ||
|
||
// If write is successful, rename temp file to actual path | ||
return rename(tmpPath, path) | ||
} | ||
|
||
func write(path string, data []byte, mode os.FileMode) error { | ||
// Attempt to open file, deferring close until function finishes | ||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
|
||
_, err = file.Write(data) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Sync file contents to disk | ||
return file.Sync() | ||
} | ||
|
||
func rename(oldPath, newPath string) error { | ||
// Attempt to rename file | ||
if err := os.Rename(oldPath, newPath); err != nil { | ||
return err | ||
} | ||
|
||
// Open containing directory and defer close until function finishes | ||
dir, err := os.Open(filepath.Dir(newPath)) | ||
if err != nil { | ||
return err | ||
} | ||
defer dir.Close() | ||
|
||
// Sync directory changes to disk | ||
return dir.Sync() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package diskutil | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestWriteFile(t *testing.T) { | ||
tempDir, err := os.MkdirTemp("", "galadriel-test") | ||
require.NoError(t, err) | ||
t.Cleanup(func() { | ||
require.NoError(t, os.RemoveAll(tempDir)) | ||
}) | ||
|
||
tests := []struct { | ||
name string | ||
data []byte | ||
atomicWriteFunc func(string, []byte) error | ||
expectMode os.FileMode | ||
}{ | ||
{ | ||
name: "basic - AtomicWritePrivateFile", | ||
data: []byte("Hello, World"), | ||
atomicWriteFunc: AtomicWritePrivateFile, | ||
expectMode: 0600, | ||
}, | ||
{ | ||
name: "empty - AtomicWritePrivateFile", | ||
data: []byte{}, | ||
atomicWriteFunc: AtomicWritePrivateFile, | ||
expectMode: 0600, | ||
}, | ||
{ | ||
name: "binary - AtomicWritePrivateFile", | ||
data: []byte{0xFF, 0, 0xFF, 0x3D, 0xD8, 0xA9, 0xDC, 0xF0, 0x9F, 0x92, 0xA9}, | ||
atomicWriteFunc: AtomicWritePrivateFile, | ||
expectMode: 0600, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt | ||
t.Run(tt.name, func(t *testing.T) { | ||
file := filepath.Join(tempDir, "file") | ||
err := tt.atomicWriteFunc(file, tt.data) | ||
require.NoError(t, err) | ||
|
||
info, err := os.Stat(file) | ||
require.NoError(t, err) | ||
require.EqualValues(t, tt.expectMode, info.Mode()) | ||
|
||
content, err := os.ReadFile(file) | ||
require.NoError(t, err) | ||
require.Equal(t, tt.data, content) | ||
|
||
require.NoError(t, os.Remove(file)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters