1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <nvram/core/storage.h>
18 
19 namespace nvram {
20 namespace storage {
21 namespace {
22 
23 // Maximum number of space blobs supported.
24 const int kMaxSpaces = 32;
25 
26 class StorageSlot {
27  public:
28   bool present() const { return blob_.size() != 0; }
29 
30   Status Load(Blob* blob) const {
31     if (blob_.size() == 0) {
32       return Status::kNotFound;
33     }
34 
35     if (!blob->Assign(blob_.data(), blob_.size())) {
36       return Status::kStorageError;
37     }
38 
39     return Status::kSuccess;
40   }
41 
42   Status Store(const Blob& blob) {
43     if (!blob_.Assign(blob.data(), blob.size())) {
44       return Status::kStorageError;
45     }
46 
47     return Status::kSuccess;
48   }
49 
50   Status Delete() {
51     return blob_.Resize(0) ? Status::kSuccess : Status::kStorageError;
52   }
53 
54  private:
55   Blob blob_;
56 };
57 
58 // Stores the header blob.
59 StorageSlot g_header;
60 
61 // Stores the space blobs.
62 struct {
63   uint32_t index;
64   StorageSlot slot;
65 } g_spaces[kMaxSpaces];
66 
67 // Find the storage slot in |g_spaces| that corresponds to |index|. Returns
68 // |nullptr| if no matching slot exists.
69 StorageSlot* FindSpaceSlot(uint32_t index) {
70   for (size_t i = 0; i < kMaxSpaces; ++i) {
71     if (g_spaces[i].slot.present() && g_spaces[i].index == index) {
72       return &g_spaces[i].slot;
73     }
74   }
75 
76   return nullptr;
77 }
78 
79 }  // namespace
80 
81 Status LoadHeader(Blob* blob) {
82   return g_header.Load(blob);
83 }
84 
85 Status StoreHeader(const Blob& blob) {
86   return g_header.Store(blob);
87 }
88 
89 Status LoadSpace(uint32_t index, Blob* blob) {
90   StorageSlot* slot = FindSpaceSlot(index);
91   return slot ? slot->Load(blob) : Status::kNotFound;
92 }
93 
94 Status StoreSpace(uint32_t index, const Blob& blob) {
95   StorageSlot* slot = FindSpaceSlot(index);
96   if (slot) {
97     return slot->Store(blob);
98   }
99 
100   // Allocate a new slot.
101   for (size_t i = 0; i < kMaxSpaces; ++i) {
102     if (!g_spaces[i].slot.present()) {
103       g_spaces[i].index = index;
104       return g_spaces[i].slot.Store(blob);
105     }
106   }
107 
108   return Status::kStorageError;
109 }
110 
111 Status DeleteSpace(uint32_t index) {
112   StorageSlot* slot = FindSpaceSlot(index);
113   if (slot) {
114     slot->Delete();
115   }
116 
117   return Status::kSuccess;
118 }
119 
120 }  // namespace storage
121 }  // namespace nvram
122