* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applypatch/store.h"
#include <algorithm>
#include <cstdio>
#include <fcntl.h>
#include <limits>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include "applypatch/transfer_manager.h"
#include "log/log.h"
#include "utils.h"
using namespace Updater::Utils;
namespace Updater {
void Store::DoFreeSpace(const std::string &directoryPath)
{
std::vector<std::string> files;
if (GetFilesFromDirectory(directoryPath, files, true) <= 0) {
LOG(WARNING) << "Failed to get files for free space";
return;
}
for (const auto &file : files) {
if (DeleteFile(file.c_str()) == -1) {
LOG(ERROR) << "Failed to delete in do free space";
continue;
}
}
}
int32_t Store::FreeStore(const std::string &dirPath, const std::string &fileName)
{
if (dirPath.empty() || fileName.empty()) {
return -1;
}
std::string path = dirPath + "/" + fileName;
if (DeleteFile(path.c_str()) != -1) {
return 0;
}
LOG(ERROR) << "Failed to delete " << path;
return -1;
}
int32_t Store::CreateNewSpace(const std::string &path, bool needClear)
{
if (path.empty()) {
LOG(ERROR) << "path is empty.";
}
std::string dirPath = path + '/';
struct stat fileStat {};
LOG(INFO) << "Create dir " << dirPath;
if (stat(dirPath.c_str(), &fileStat) == -1) {
if (errno != ENOENT) {
LOG(ERROR) << "Create new space, failed to stat";
return -1;
}
if (MkdirRecursive(dirPath, S_IRWXU) != 0) {
LOG(ERROR) << "Failed to make store";
return -1;
}
} else {
if (!needClear) {
return 0;
}
std::vector<std::string> files {};
if (GetFilesFromDirectory(dirPath, files) < 0) {
return -1;
}
if (files.empty()) {
return 0;
}
std::vector<std::string>::iterator iter = files.begin();
while (iter != files.end()) {
if (DeleteFile(*iter) == 0) {
LOG(INFO) << "Delete " << *iter;
}
iter++;
}
files.clear();
}
return 0;
}
int32_t Store::WriteDataToStore(const std::string &dirPath, const std::string &fileName,
const std::vector<uint8_t> &buffer, int size)
{
if (dirPath.empty()) {
return -1;
}
std::string pathTmp;
if (!fileName.empty()) {
pathTmp = dirPath + "/";
}
std::string path = pathTmp + fileName;
pathTmp = pathTmp + fileName;
int fd = open(pathTmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
LOG(ERROR) << "Failed to create store, " << strerror(errno);
return -1;
}
fdsan_exchange_owner_tag(fd, 0, FDSAN_UPDATER_TAG);
if (size < 0 || !WriteFully(fd, buffer.data(), static_cast<size_t>(size))) {
if (errno == EIO) {
fdsan_close_with_tag(fd, FDSAN_UPDATER_TAG);
return 1;
}
LOG(ERROR) << "Write to stash failed, " << size << " blocks to " << path;
fdsan_close_with_tag(fd, FDSAN_UPDATER_TAG);
return -1;
}
if (fsync(fd) == -1) {
LOG(WARNING) << "Failed to fsync :" << strerror(errno);
}
fdsan_close_with_tag(fd, FDSAN_UPDATER_TAG);
int fdd = open(dirPath.c_str(), O_RDONLY | O_DIRECTORY);
if (fdd == -1) {
LOG(ERROR) << "Failed to open";
return -1;
}
fdsan_exchange_owner_tag(fdd, 0, FDSAN_UPDATER_TAG);
fdsan_close_with_tag(fdd, FDSAN_UPDATER_TAG);
return 0;
}
int32_t Store::LoadDataFromStore(const std::string &dirPath, const std::string &fileName,
std::vector<uint8_t> &buffer)
{
std::string path = dirPath;
if (!fileName.empty()) {
path = path + "/" + fileName;
}
struct stat fileStat {};
if (stat(path.c_str(), &fileStat) == -1) {
LOG(DEBUG) << "Failed to stat";
return -2;
}
if (fileStat.st_size % H_BLOCK_SIZE != 0) {
LOG(ERROR) << "Not multiple of block size 4096";
return -1;
}
int fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
LOG(ERROR) << "Failed to create";
return -1;
}
fdsan_exchange_owner_tag(fd, 0, FDSAN_UPDATER_TAG);
buffer.resize(fileStat.st_size);
if (!ReadFully(fd, buffer.data(), fileStat.st_size)) {
LOG(ERROR) << "Failed to read store data";
fdsan_close_with_tag(fd, FDSAN_UPDATER_TAG);
fd = -1;
return -1;
}
fdsan_close_with_tag(fd, FDSAN_UPDATER_TAG);
fd = -1;
return 0;
}
}