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