1 /*
2  * Copyright (C) 2015 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 "persistent_integer.h"
18 
19 #include <fcntl.h>
20 
21 #include <base/logging.h>
22 #include <base/posix/eintr_wrapper.h>
23 
24 #include "constants.h"
25 
26 namespace chromeos_metrics {
27 
PersistentInteger(const std::string & name,const base::FilePath & directory)28 PersistentInteger::PersistentInteger(const std::string& name,
29                                      const base::FilePath& directory)
30     : value_(0),
31       version_(kVersion),
32       name_(name),
33       backing_file_path_(directory.Append(name_)),
34       synced_(false) {}
35 
~PersistentInteger()36 PersistentInteger::~PersistentInteger() {}
37 
Set(int64_t value)38 void PersistentInteger::Set(int64_t value) {
39   value_ = value;
40   Write();
41 }
42 
Get()43 int64_t PersistentInteger::Get() {
44   // If not synced, then read.  If the read fails, it's a good idea to write.
45   if (!synced_ && !Read())
46     Write();
47   return value_;
48 }
49 
GetAndClear()50 int64_t PersistentInteger::GetAndClear() {
51   int64_t v = Get();
52   Set(0);
53   return v;
54 }
55 
Add(int64_t x)56 void PersistentInteger::Add(int64_t x) {
57   Set(Get() + x);
58 }
59 
Write()60 void PersistentInteger::Write() {
61   int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(),
62                              O_WRONLY | O_CREAT | O_TRUNC,
63                              S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH));
64   PCHECK(fd >= 0) << "cannot open " << backing_file_path_.value()
65                   << " for writing";
66   PCHECK((HANDLE_EINTR(write(fd, &version_, sizeof(version_))) ==
67           sizeof(version_)) &&
68          (HANDLE_EINTR(write(fd, &value_, sizeof(value_))) ==
69           sizeof(value_)))
70       << "cannot write to " << backing_file_path_.value();
71   close(fd);
72   synced_ = true;
73 }
74 
Read()75 bool PersistentInteger::Read() {
76   int fd = HANDLE_EINTR(open(backing_file_path_.value().c_str(), O_RDONLY));
77   if (fd < 0) {
78     PLOG(WARNING) << "cannot open " << backing_file_path_.value()
79                   << " for reading";
80     return false;
81   }
82   int32_t version;
83   int64_t value;
84   bool read_succeeded = false;
85   if (HANDLE_EINTR(read(fd, &version, sizeof(version))) == sizeof(version) &&
86       version == version_ &&
87       HANDLE_EINTR(read(fd, &value, sizeof(value))) == sizeof(value)) {
88     value_ = value;
89     read_succeeded = true;
90     synced_ = true;
91   }
92   close(fd);
93   return read_succeeded;
94 }
95 
96 }  // namespace chromeos_metrics
97