1 // Copyright (C) 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "icing/file/version-util.h"
16
17 #include <cstdint>
18 #include <string>
19 #include <utility>
20
21 #include "icing/text_classifier/lib3/utils/base/status.h"
22 #include "icing/text_classifier/lib3/utils/base/statusor.h"
23 #include "icing/absl_ports/canonical_errors.h"
24 #include "icing/file/filesystem.h"
25 #include "icing/index/index.h"
26
27 namespace icing {
28 namespace lib {
29
30 namespace version_util {
31
ReadVersion(const Filesystem & filesystem,const std::string & version_file_path,const std::string & index_base_dir)32 libtextclassifier3::StatusOr<VersionInfo> ReadVersion(
33 const Filesystem& filesystem, const std::string& version_file_path,
34 const std::string& index_base_dir) {
35 // 1. Read the version info.
36 VersionInfo existing_version_info(-1, -1);
37 if (filesystem.FileExists(version_file_path.c_str()) &&
38 !filesystem.PRead(version_file_path.c_str(), &existing_version_info,
39 sizeof(VersionInfo), /*offset=*/0)) {
40 return absl_ports::InternalError("Fail to read version");
41 }
42
43 // 2. Check the Index magic to see if we're actually on version 0.
44 libtextclassifier3::StatusOr<int> existing_flash_index_magic_or =
45 Index::ReadFlashIndexMagic(&filesystem, index_base_dir);
46 if (!existing_flash_index_magic_or.ok()) {
47 if (absl_ports::IsNotFound(existing_flash_index_magic_or.status())) {
48 // Flash index magic doesn't exist. In this case, we're unable to
49 // determine the version change state correctly (regardless of the
50 // existence of the version file), so invalidate VersionInfo by setting
51 // version to -1, but still keep the max_version value read in step 1.
52 existing_version_info.version = -1;
53 return existing_version_info;
54 }
55 // Real error.
56 return std::move(existing_flash_index_magic_or).status();
57 }
58 if (existing_flash_index_magic_or.ValueOrDie() ==
59 kVersionZeroFlashIndexMagic) {
60 existing_version_info.version = 0;
61 if (existing_version_info.max_version == -1) {
62 existing_version_info.max_version = 0;
63 }
64 }
65
66 return existing_version_info;
67 }
68
WriteVersion(const Filesystem & filesystem,const std::string & version_file_path,const VersionInfo & version_info)69 libtextclassifier3::Status WriteVersion(const Filesystem& filesystem,
70 const std::string& version_file_path,
71 const VersionInfo& version_info) {
72 ScopedFd scoped_fd(filesystem.OpenForWrite(version_file_path.c_str()));
73 if (!scoped_fd.is_valid() ||
74 !filesystem.PWrite(scoped_fd.get(), /*offset=*/0, &version_info,
75 sizeof(VersionInfo)) ||
76 !filesystem.DataSync(scoped_fd.get())) {
77 return absl_ports::InternalError("Fail to write version");
78 }
79 return libtextclassifier3::Status::OK;
80 }
81
GetVersionStateChange(const VersionInfo & existing_version_info,int32_t curr_version)82 StateChange GetVersionStateChange(const VersionInfo& existing_version_info,
83 int32_t curr_version) {
84 if (!existing_version_info.IsValid()) {
85 return StateChange::kUndetermined;
86 }
87
88 if (existing_version_info.version == 0) {
89 return (existing_version_info.max_version == existing_version_info.version)
90 ? StateChange::kVersionZeroUpgrade
91 : StateChange::kVersionZeroRollForward;
92 }
93
94 if (existing_version_info.version == curr_version) {
95 return StateChange::kCompatible;
96 } else if (existing_version_info.version > curr_version) {
97 return StateChange::kRollBack;
98 } else { // existing_version_info.version < curr_version
99 return (existing_version_info.max_version == existing_version_info.version)
100 ? StateChange::kUpgrade
101 : StateChange::kRollForward;
102 }
103 }
104
105 } // namespace version_util
106
107 } // namespace lib
108 } // namespace icing
109