diff --git a/changelog/25395.txt b/changelog/25395.txt new file mode 100644 index 000000000000..cd2ca5137e0f --- /dev/null +++ b/changelog/25395.txt @@ -0,0 +1,3 @@ +```release-note:bug +storage/file: Fixing spuriously deleting storage keys ending with .temp +``` diff --git a/sdk/physical/file/file.go b/sdk/physical/file/file.go index d7ad9de3a2b0..95f420c69c3f 100644 --- a/sdk/physical/file/file.go +++ b/sdk/physical/file/file.go @@ -245,17 +245,21 @@ func (b *FileBackend) PutInternal(ctx context.Context, entry *physical.Entry) er // JSON encode the entry and write it fullPath := filepath.Join(path, key) - tempPath := fullPath + ".temp" - f, err := os.OpenFile( - tempPath, - os.O_CREATE|os.O_TRUNC|os.O_WRONLY, - 0o600) + f, err := os.CreateTemp(path, key) if err != nil { if f != nil { f.Close() } return err } + + if err = os.Chmod(f.Name(), 0o600); err != nil { + if f != nil { + f.Close() + } + return err + } + if f == nil { return errors.New("could not successfully get a file handle") } @@ -266,7 +270,7 @@ func (b *FileBackend) PutInternal(ctx context.Context, entry *physical.Entry) er }) f.Close() if encErr == nil { - err = os.Rename(tempPath, fullPath) + err = os.Rename(f.Name(), fullPath) if err != nil { return err } @@ -278,7 +282,7 @@ func (b *FileBackend) PutInternal(ctx context.Context, entry *physical.Entry) er // See if we ended up with a zero-byte file and if so delete it, might be a // case of disk being full but the file info is in metadata that is // reserved. - fi, err := os.Stat(tempPath) + fi, err := os.Stat(f.Name()) if err != nil { return encErr } @@ -286,7 +290,7 @@ func (b *FileBackend) PutInternal(ctx context.Context, entry *physical.Entry) er return encErr } if fi.Size() == 0 { - os.Remove(tempPath) + os.Remove(f.Name()) } return encErr } diff --git a/sdk/physical/file/file_test.go b/sdk/physical/file/file_test.go index 14c33094dec4..7fc6398c8dff 100644 --- a/sdk/physical/file/file_test.go +++ b/sdk/physical/file/file_test.go @@ -240,3 +240,54 @@ func TestFileBackend(t *testing.T) { physical.ExerciseBackend_ListPrefix(t, b) } + +func TestFileBackendCreateTempKey(t *testing.T) { + dir := t.TempDir() + + logger := logging.NewVaultLogger(log.Debug) + + b, err := NewFileBackend(map[string]string{ + "path": dir, + }, logger) + if err != nil { + t.Fatalf("err: %s", err) + } + temp := &physical.Entry{Key: "example.temp", Value: []byte("tempfoo")} + err = b.Put(context.Background(), temp) + if err != nil { + t.Fatalf("err: %v", err) + } + + nonTemp := &physical.Entry{Key: "example", Value: []byte("foobar")} + err = b.Put(context.Background(), nonTemp) + if err != nil { + t.Fatalf("err: %v", err) + } + + vals, err := b.List(context.Background(), "") + if err != nil { + t.Fatal(err) + } + if len(vals) != 2 || vals[0] == vals[1] { + t.Fatalf("bad: %v", vals) + } + for _, val := range vals { + if val != "example.temp" && val != "example" { + t.Fatalf("bad val: %v", val) + } + } + out, err := b.Get(context.Background(), "example") + if err != nil { + t.Fatalf("err: %v", err) + } + if !reflect.DeepEqual(out, nonTemp) { + t.Fatalf("bad: %v expected: %v", out, nonTemp) + } + out, err = b.Get(context.Background(), "example.temp") + if err != nil { + t.Fatalf("err: %v", err) + } + if !reflect.DeepEqual(out, temp) { + t.Fatalf("bad: %v expected: %v", out, temp) + } +}