summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ipn/store.go5
-rw-r--r--ipn/store/stores.go14
2 files changed, 13 insertions, 6 deletions
diff --git a/ipn/store.go b/ipn/store.go
index 3bef012ba..a771784ad 100644
--- a/ipn/store.go
+++ b/ipn/store.go
@@ -68,8 +68,9 @@ func CurrentProfileKey(userID string) StateKey {
// StateStore persists state, and produces it back on request.
type StateStore interface {
- // ReadState returns the bytes associated with ID. Returns (nil,
- // ErrStateNotExist) if the ID doesn't have associated state.
+ // ReadState returns the bytes associated with ID.
+ // It returns (nil, ErrStateNotExist) if the ID doesn't have associated state.
+ // The returned value must not be mutated.
ReadState(id StateKey) ([]byte, error)
// WriteState saves bs as the state associated with ID.
//
diff --git a/ipn/store/stores.go b/ipn/store/stores.go
index 8bf3a24b0..9cef1eaf6 100644
--- a/ipn/store/stores.go
+++ b/ipn/store/stores.go
@@ -173,16 +173,22 @@ func (s *FileStore) ReadState(id ipn.StateKey) ([]byte, error) {
}
// WriteState implements the StateStore interface.
-func (s *FileStore) WriteState(id ipn.StateKey, bs []byte) error {
+func (s *FileStore) WriteState(id ipn.StateKey, bs []byte) (err error) {
s.mu.Lock()
defer s.mu.Unlock()
- if bytes.Equal(s.cache[id], bs) {
+ bs0 := s.cache[id]
+ if bytes.Equal(bs0, bs) {
return nil
}
+ defer func() {
+ if err != nil {
+ s.cache[id] = bs0
+ }
+ }()
s.cache[id] = bytes.Clone(bs)
- bs, err := json.MarshalIndent(s.cache, "", " ")
+ b, err := json.MarshalIndent(s.cache, "", " ")
if err != nil {
return err
}
- return atomicfile.WriteFile(s.path, bs, 0600)
+ return atomicfile.WriteFile(s.path, b, 0600)
}