1 /*
2  * Copyright (C) 2024 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 
16 #define MLOG_TAG "RingtoneRestore"
17 
18 #include "ringtone_restore.h"
19 
20 #include <sys/stat.h>
21 
22 #include "datashare_ext_ability.h"
23 #include "datashare_ext_ability_context.h"
24 #include "result_set_utils.h"
25 #include "ringtone_restore_type.h"
26 #include "ringtone_restore_db_utils.h"
27 #include "ringtone_errno.h"
28 #include "ringtone_file_utils.h"
29 #include "ringtone_log.h"
30 #include "ringtone_type.h"
31 
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35 static const int32_t QUERY_COUNT = 500;
36 static const int32_t INVALID_QUERY_OFFSET = -1;
Init(const std::string &backupPath)37 int32_t RingtoneRestore::Init(const std::string &backupPath)
38 {
39     RINGTONE_INFO_LOG("Init db start");
40     if (backupPath.empty()) {
41         RINGTONE_ERR_LOG("error: backup path is null");
42         return E_INVALID_ARGUMENTS;
43     }
44     dbPath_ = backupPath + RINGTONE_LIBRARY_DB_PATH_EL1 + "/rdb" + "/" + RINGTONE_LIBRARY_DB_NAME;
45     if (!RingtoneFileUtils::IsFileExists(dbPath_)) {
46         RINGTONE_ERR_LOG("ringtone db is not exist, path=%{public}s", dbPath_.c_str());
47         dbPath_ = backupPath + RINGTONE_LIBRARY_DB_PATH + "/rdb" + "/" + RINGTONE_LIBRARY_DB_NAME;
48         if (!RingtoneFileUtils::IsFileExists(dbPath_)) {
49             RINGTONE_ERR_LOG("ringtone db is not exist, path=%{public}s", dbPath_.c_str());
50             return E_FAIL;
51         }
52     }
53     backupPath_ = backupPath;
54     if (RingtoneRestoreBase::Init(backupPath) != E_OK) {
55         return E_FAIL;
56     }
57     int32_t err = RingtoneRestoreDbUtils::InitDb(restoreRdb_, RINGTONE_LIBRARY_DB_NAME, dbPath_,
58         RINGTONE_BUNDLE_NAME, true);
59     if (err != E_OK) {
60         RINGTONE_ERR_LOG("ringtone rdb fail, err = %{public}d", err);
61         return E_HAS_DB_ERROR;
62     }
63 
64     RINGTONE_INFO_LOG("Init db successfully");
65     return E_OK;
66 }
67 
QueryFileInfos(int32_t offset)68 vector<FileInfo> RingtoneRestore::QueryFileInfos(int32_t offset)
69 {
70     vector<FileInfo> result;
71     string querySql = "SELECT * FROM " + RINGTONE_TABLE;
72     if (offset != INVALID_QUERY_OFFSET) {
73         querySql += " LIMIT " + to_string(offset) + ", " + to_string(QUERY_COUNT);
74     }
75     auto resultSet = restoreRdb_->QuerySql(querySql);
76     if (resultSet == nullptr) {
77         return {};
78     }
79 
80     vector<shared_ptr<RingtoneMetadata>> metaDatas {};
81     auto ret = resultSet->GoToFirstRow();
82     while (ret == NativeRdb::E_OK) {
83         auto metaData = make_unique<RingtoneMetadata>();
84         if (PopulateMetadata(resultSet, metaData) != E_OK) {
85             RINGTONE_INFO_LOG("read resultset error");
86             continue;
87         }
88         metaDatas.push_back(std::move(metaData));
89         ret = resultSet->GoToNextRow();
90     };
91     resultSet->Close();
92 
93     return ConvertToFileInfos(metaDatas);
94 }
95 
ConvertToFileInfos(vector<shared_ptr<RingtoneMetadata>> &metaDatas)96 vector<FileInfo> RingtoneRestore::ConvertToFileInfos(vector<shared_ptr<RingtoneMetadata>> &metaDatas)
97 {
98     vector<FileInfo> infos = {};
99     for (auto meta : metaDatas) {
100         infos.emplace_back(*meta);
101     }
102     return infos;
103 }
104 
CheckRestoreFileInfos(vector<FileInfo> &infos)105 void RingtoneRestore::CheckRestoreFileInfos(vector<FileInfo> &infos)
106 {
107     for (auto it = infos.begin(); it != infos.end();) {
108         // at first, check backup file path
109         string srcPath = backupPath_ + it->data;
110         if (!RingtoneFileUtils::IsFileExists(srcPath)) {
111             // 系统铃音不克隆,需要进行设置铃音判断
112             if (it->sourceType == SOURCE_TYPE_PRESET) {
113                 it->restorePath = it->data;
114                 CheckSetting(*it);
115             }
116             RINGTONE_INFO_LOG("warnning:backup file is not exist, path=%{private}s", srcPath.c_str());
117             infos.erase(it);
118         } else {
119             it++;
120         }
121     }
122 }
123 
StartRestore()124 int32_t RingtoneRestore::StartRestore()
125 {
126     if (restoreRdb_ == nullptr || backupPath_.empty()) {
127         return E_FAIL;
128     }
129     auto ret = RingtoneRestoreBase::StartRestore();
130     if (ret != E_OK) {
131         return ret;
132     }
133     auto infos = QueryFileInfos(INVALID_QUERY_OFFSET);
134     if ((!infos.empty()) && (infos.size() != 0)) {
135         CheckRestoreFileInfos(infos);
136         ret = InsertTones(infos);
137     }
138     FlushSettings();
139     return ret;
140 }
141 
UpdateRestoreFileInfo(FileInfo &info)142 void RingtoneRestore::UpdateRestoreFileInfo(FileInfo &info)
143 {
144     info.displayName = RingtoneFileUtils::GetFileNameFromPath(info.restorePath);
145     if (info.title == TITLE_DEFAULT) {
146         info.title = RingtoneFileUtils::GetBaseNameFromPath(info.restorePath);
147     }
148 
149     struct stat statInfo;
150     if (stat(info.restorePath.c_str(), &statInfo) != 0) {
151         RINGTONE_ERR_LOG("stat syscall err %{public}d", errno);
152         return;
153     }
154     info.dateModified = static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim));
155 }
156 
OnPrepare(FileInfo &info, const std::string &destPath)157 bool RingtoneRestore::OnPrepare(FileInfo &info, const std::string &destPath)
158 {
159     if (!RingtoneFileUtils::IsFileExists(destPath)) {
160         return false;
161     }
162 
163     string fileName = RingtoneFileUtils::GetFileNameFromPath(info.data);
164     if (fileName.empty()) {
165         RINGTONE_ERR_LOG("src file name is null");
166         return false;
167     }
168     string baseName = RingtoneFileUtils::GetBaseNameFromPath(info.data);
169     if (baseName.empty()) {
170         RINGTONE_ERR_LOG("src file base name is null");
171         return false;
172     }
173     string extensionName = RingtoneFileUtils::GetExtensionFromPath(info.data);
174 
175     int32_t repeatCount = 1;
176     string srcPath = backupPath_ + info.data;
177     info.restorePath = destPath + "/" + fileName;
178     while (RingtoneFileUtils::IsFileExists(info.restorePath)) {
179         if (RingtoneFileUtils::IsSameFile(srcPath, info.restorePath)) {
180             CheckSetting(info);
181             RINGTONE_ERR_LOG("samefile: srcPath=%{private}s, dstPath=%{private}s", srcPath.c_str(),
182                 info.restorePath.c_str());
183             return false;
184         }
185         info.restorePath = destPath + "/" + baseName + "(" + to_string(repeatCount++) + ")" + "." + extensionName;
186     }
187 
188     if (!RingtoneRestoreBase::MoveFile(srcPath, info.restorePath)) {
189         return false;
190     }
191 
192     UpdateRestoreFileInfo(info);
193 
194     return true;
195 }
196 
OnFinished(vector<FileInfo> &infos)197 void RingtoneRestore::OnFinished(vector<FileInfo> &infos)
198 {
199     if (!RingtoneFileUtils::RemoveDirectory(backupPath_)) {
200         RINGTONE_ERR_LOG("cleanup backup dir failed, restorepath=%{public}s, err: %{public}s",
201             backupPath_.c_str(), strerror(errno));
202     }
203 }
204 } // namespace Media
205 } // namespace OHOS
206