Skip to content
File

Blob: cmd/server/storage_identity_unix.go

go84 lines
1//go:build !windows
2 
3package server
4 
5import (
6 "fmt"
7 "os"
8 "path/filepath"
9)
10 
11func prepareKVProviderDirectory(dir string) error {
12 dir = filepath.Clean(dir)
13 info, err := os.Stat(dir)
14 if err == nil {
15 if !info.IsDir() {
16 return fmt.Errorf("data path %q is not a directory", dir)
17 }
18 return nil
19 }
20 if !os.IsNotExist(err) {
21 return err
22 }
23 parent := filepath.Dir(dir)
24 if parent == dir {
25 return err
26 }
27 if err := prepareKVProviderDirectory(parent); err != nil {
28 return err
29 }
30 err = os.Mkdir(dir, 0750)
31 created := err == nil
32 if err != nil && !os.IsExist(err) {
33 return err
34 }
35 if !created {
36 info, err := os.Stat(dir)
37 if err != nil {
38 return err
39 }
40 if !info.IsDir() {
41 return fmt.Errorf("data path %q is not a directory", dir)
42 }
43 }
44 // Persist each new directory's name before creating a child or marker.
45 // Existing ancestors need only traversal permission and are left alone.
46 if err := syncKVProviderIdentity(parent); err != nil {
47 if created {
48 // Only remove this initialization's empty directory. A retry must
49 // not mistake a failed creation flush for an established directory.
50 _ = os.Remove(dir)
51 }
52 return err
53 }
54 return nil
55}
56 
57func publishKVProviderMarker(tempPath, dir string) error {
58 // A hard link publishes the complete, synced marker atomically and never
59 // overwrites an identity established by a concurrent startup.
60 if err := os.Link(tempPath, filepath.Join(dir, kvProviderMarker)); err != nil {
61 return err
62 }
63 if err := os.Remove(tempPath); err != nil {
64 return fmt.Errorf("removing temporary marker: %w", err)
65 }
66 return syncKVProviderIdentity(dir)
67}
68 
69func syncKVProviderIdentity(dir string) error {
70 d, err := os.Open(dir)
71 if err != nil {
72 return fmt.Errorf("opening directory to sync storage identity: %w", err)
73 }
74 syncErr := d.Sync()
75 closeErr := d.Close()
76 if syncErr != nil {
77 return fmt.Errorf("syncing directory for storage identity: %w", syncErr)
78 }
79 if closeErr != nil {
80 return fmt.Errorf("closing directory after syncing storage identity: %w", closeErr)
81 }
82 return nil
83}