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
28using namespace Updater::Utils;
29
30namespace Updater {
31void 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
46int32_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
59int32_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
99int32_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
140int32_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