1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 "applypatch/store.h"
16 #include <algorithm>
17 #include <cstdio>
18 #include <fcntl.h>
19 #include <limits>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/vfs.h>
23 #include <unistd.h>
24 #include "applypatch/transfer_manager.h"
25 #include "log/log.h"
26 #include "utils.h"
27 
28 using namespace Updater::Utils;
29 
30 namespace Updater {
DoFreeSpace(const std::string & directoryPath)31 void Store::DoFreeSpace(const std::string &directoryPath)
32 {
33     std::vector<std::string> files;
34     if (GetFilesFromDirectory(directoryPath, files, true) <= 0) {
35         LOG(WARNING) << "Failed to get files for free space";
36         return;
37     }
38     for (const auto &file : files) {
39         if (DeleteFile(file.c_str()) == -1) {
40             LOG(ERROR) << "Failed to delete in do free space";
41             continue;
42         }
43     }
44 }
45 
FreeStore(const std::string & dirPath,const std::string & fileName)46 int32_t Store::FreeStore(const std::string &dirPath, const std::string &fileName)
47 {
48     if (dirPath.empty() || fileName.empty()) {
49         return -1;
50     }
51     std::string path = dirPath + "/" + fileName;
52     if (DeleteFile(path.c_str()) != -1) {
53         return 0;
54     }
55     LOG(ERROR) << "Failed to delete " << path;
56     return -1;
57 }
58 
CreateNewSpace(const std::string & path,bool needClear)59 int32_t Store::CreateNewSpace(const std::string &path, bool needClear)
60 {
61     if (path.empty()) {
62         LOG(ERROR) << "path is empty.";
63     }
64     std::string dirPath = path + '/';
65     struct stat fileStat {};
66     LOG(INFO) << "Create dir " << dirPath;
67     if (stat(dirPath.c_str(), &fileStat) == -1) {
68         if (errno != ENOENT) {
69             LOG(ERROR) << "Create new space, failed to stat";
70             return -1;
71         }
72         if (MkdirRecursive(dirPath, S_IRWXU) != 0) {
73             LOG(ERROR) << "Failed to make store";
74             return -1;
75         }
76     } else {
77         if (!needClear) {
78             return 0;
79         }
80         std::vector<std::string> files {};
81         if (GetFilesFromDirectory(dirPath, files) < 0) {
82             return -1;
83         }
84         if (files.empty()) {
85             return 0;
86         }
87         std::vector<std::string>::iterator iter = files.begin();
88         while (iter != files.end()) {
89             if (DeleteFile(*iter) == 0) {
90                 LOG(INFO) << "Delete " << *iter;
91             }
92             iter++;
93         }
94         files.clear();
95     }
96     return 0;
97 }
98 
WriteDataToStore(const std::string & dirPath,const std::string & fileName,const std::vector<uint8_t> & buffer,int size)99 int32_t Store::WriteDataToStore(const std::string &dirPath, const std::string &fileName,
100     const std::vector<uint8_t> &buffer, int size)
101 {
102     if (dirPath.empty()) {
103         return -1;
104     }
105     std::string pathTmp;
106     if (!fileName.empty()) {
107         pathTmp = dirPath + "/";
108     }
109     std::string path = pathTmp + fileName;
110     pathTmp = pathTmp + fileName;
111 
112     int fd = open(pathTmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
113     if (fd == -1) {
114         LOG(ERROR) << "Failed to create store, " << strerror(errno);
115         return -1;
116     }
117     if (size < 0 || !WriteFully(fd, buffer.data(), static_cast<size_t>(size))) {
118         if (errno == EIO) {
119             close(fd);
120             return 1;
121         }
122         LOG(ERROR) << "Write to stash failed, " << size << " blocks to " << path;
123         close(fd);
124         return -1;
125     }
126     if (fsync(fd) == -1) {
127         LOG(WARNING) << "Failed to fsync :" << strerror(errno);
128     }
129     close(fd);
130 
131     int fdd = open(dirPath.c_str(), O_RDONLY | O_DIRECTORY);
132     if (fdd == -1) {
133         LOG(ERROR) << "Failed to open";
134         return -1;
135     }
136     close(fdd);
137     return 0;
138 }
139 
LoadDataFromStore(const std::string & dirPath,const std::string & fileName,std::vector<uint8_t> & buffer)140 int32_t Store::LoadDataFromStore(const std::string &dirPath, const std::string &fileName,
141     std::vector<uint8_t> &buffer)
142 {
143     LOG(INFO) << "Store base is " << dirPath << "/" << fileName;
144     std::string path = dirPath;
145     if (!fileName.empty()) {
146         path = path + "/" + fileName;
147     }
148     struct stat fileStat {};
149     if (stat(path.c_str(), &fileStat) == -1) {
150         LOG(DEBUG) << "Failed to stat";
151         return -1;
152     }
153     if (fileStat.st_size % H_BLOCK_SIZE != 0) {
154         LOG(ERROR) << "Not multiple of block size 4096";
155         return -1;
156     }
157 
158     int fd = open(path.c_str(), O_RDONLY);
159     if (fd == -1) {
160         LOG(ERROR) << "Failed to create";
161         return -1;
162     }
163     buffer.resize(fileStat.st_size);
164     if (!ReadFully(fd, buffer.data(), fileStat.st_size)) {
165         LOG(ERROR) << "Failed to read store data";
166         close(fd);
167         fd = -1;
168         return -1;
169     }
170     close(fd);
171     fd = -1;
172     return 0;
173 }
174 } // namespace Updater
175