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 "Scanner"
17 
18 #include "ringtone_scanner.h"
19 
20 #include "directory_ex.h"
21 #include "ringtone_default_setting.h"
22 #include "ringtone_file_utils.h"
23 #include "ringtone_log.h"
24 #include "ringtone_mimetype_utils.h"
25 #include "ringtone_rdbstore.h"
26 #include "ringtone_scanner_utils.h"
27 
28 namespace OHOS {
29 namespace Media {
30 using namespace std;
31 using namespace OHOS::AppExecFwk;
32 using namespace OHOS::DataShare;
33 static const int32_t SCANNER_WAIT_FOR_TIMEOUT = 10000; // ms
34 static const std::string PATH_PLAY_MODE_SYNC = "/synchronized";
35 static const std::string PATH_PLAY_MODE_CLASSIC = "/non-synchronized";
36 static const std::string PATH_VIBRATE_TYPE_STANDARD = "/standard";
37 static const std::string PATH_VIBRATE_TYPE_GENTLE = "/gentle";
38 static const std::string ALARMS_TYPE = "alarms";
39 static const std::string RINGTONES_TYPE = "ringtones";
40 static const std::string NOTIFICATIONS_TYPE = "notifications";
41 #ifndef OHOS_LOCAL_DEBUG_DISABLE
42 // liuxk just for debug
43 static const std::string LOCAL_DIR = "/data/storage/el2/base/preload_data";
44 #endif
45 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_typeMap = {
46 #ifndef OHOS_LOCAL_DEBUG_DISABLE
47     // liuxk just for debug
48     {LOCAL_DIR + "/alarms", {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_ALARM}},
49     {LOCAL_DIR + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
50     {LOCAL_DIR + "/notifications", {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_NOTIFICATION}},
51 #endif
52     // customized tones map
53     {RINGTONE_CUSTOMIZED_ALARM_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_ALARM}},
54     {RINGTONE_CUSTOMIZED_RINGTONE_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_RINGTONE}},
55     {RINGTONE_CUSTOMIZED_NOTIFICATIONS_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_NOTIFICATION}},
56     // customized tones map
57     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
58     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
59     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
60     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
61     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
62     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
63     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
64     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
65     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
66 };
67 // vibrate type map
68 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_vibrateTypeMap = {
69     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
70     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
71     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
72     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
73     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
74     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
75 };
76 
77 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_vibratePlayModeMap = {
78     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
79         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
80     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
81         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
82     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
83         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
84     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
85         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
86     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
87         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
88     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
89         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
90     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
91         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
92     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
93         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
94     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
95         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
96     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
97         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
98     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
99         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
100     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
101         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
102 };
103 
RingtoneScannerObj(const std::string & path,const std::shared_ptr<IRingtoneScannerCallback> & callback,RingtoneScannerObj::ScanType type)104 RingtoneScannerObj::RingtoneScannerObj(const std::string &path,
105     const std::shared_ptr<IRingtoneScannerCallback> &callback,
106     RingtoneScannerObj::ScanType type) : type_(type), callback_(callback)
107 {
108     if (type_ == DIRECTORY) {
109         dir_ = path;
110     } else if (type_ == FILE) {
111         path_ = path;
112     }
113     // when path is /Photo, it means update or clone scene
114     stopFlag_ = make_shared<bool>(false);
115 }
116 
RingtoneScannerObj(RingtoneScannerObj::ScanType type)117 RingtoneScannerObj::RingtoneScannerObj(RingtoneScannerObj::ScanType type) : type_(type)
118 {
119     stopFlag_ = make_shared<bool>(false);
120 }
121 
SetStopFlag(std::shared_ptr<bool> & flag)122 void RingtoneScannerObj::SetStopFlag(std::shared_ptr<bool> &flag)
123 {
124     stopFlag_ = flag;
125 }
126 
ScanFile()127 int32_t RingtoneScannerObj::ScanFile()
128 {
129     RINGTONE_DEBUG_LOG("scan file %{private}s", path_.c_str());
130 
131     int32_t ret = ScanFileInternal();
132     if (ret != E_OK) {
133         RINGTONE_ERR_LOG("ScanFileInternal err %{public}d", ret);
134     }
135 
136     (void)InvokeCallback(ret);
137 
138     return ret;
139 }
140 
InvokeCallback(int32_t err)141 int32_t RingtoneScannerObj::InvokeCallback(int32_t err)
142 {
143     if (callback_ == nullptr) {
144         return E_OK;
145     }
146 
147     return callback_->OnScanFinished(err, uri_, path_);
148 }
149 
Scan()150 void RingtoneScannerObj::Scan()
151 {
152     switch (type_) {
153         case FILE:
154             ScanFile();
155             break;
156         case DIRECTORY:
157             ScanDir();
158             break;
159         case START:
160             BootScan();
161             break;
162         default:
163             break;
164     }
165 }
166 
BootScan()167 int32_t RingtoneScannerObj::BootScan()
168 {
169     static const std::vector<std::string> preloadDirs = {
170         {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/alarms"},
171         {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/ringtones"},
172         {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/notifications"},
173         {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/alarms"},
174         {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/ringtones"},
175         {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/notifications"},
176         {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/alarms"},
177         {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/ringtones"},
178         {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/notifications"},
179         {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + "/standard"},
180         {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + "/gentle"},
181         {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + "/standard"},
182         {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + "/gentle"},
183         {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + "/standard"},
184         {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + "/gentle"},
185     };
186 
187     int64_t scanStart = RingtoneFileUtils::UTCTimeMilliSeconds();
188     for (auto &dir : preloadDirs) {
189         RINGTONE_INFO_LOG("start to scan realpath %{private}s", dir.c_str());
190         string realPath;
191         if (!PathToRealPath(dir, realPath)) {
192             RINGTONE_ERR_LOG("failed to get realpath %{private}s, errno %{public}d", dir.c_str(), errno);
193             continue;
194         }
195 
196         RINGTONE_INFO_LOG("start to scan realpath %{private}s", dir.c_str());
197         callback_ = make_shared<ScanErrCallback>(dir);
198 
199         if (RingtoneScannerUtils::IsDirectory(realPath)) {
200             dir_ = move(realPath);
201             (void)ScanDir();
202         } else if (RingtoneScannerUtils::IsRegularFile(realPath)) {
203             path_ = move(realPath);
204             (void)ScanFile();
205         }
206     }
207 
208     // reset ringtone default settings
209     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
210     RingtoneDefaultSetting::GetObj(rawRdb)->Update();
211 
212     int64_t scanEnd = RingtoneFileUtils::UTCTimeMilliSeconds();
213     RINGTONE_INFO_LOG("total preload tone files count:%{public}d, scanned: %{public}d, costed-time:%{public}"
214         PRId64 " ms", tonesScannedCount_, tonesScannedCount_, scanEnd - scanStart);
215     unique_lock<mutex> lock(scannerLock_);
216     scannerCv_.notify_one();
217     return E_OK;
218 }
219 
WaitFor()220 void RingtoneScannerObj::WaitFor()
221 {
222     unique_lock<mutex> lock(scannerLock_);
223     scannerCv_.wait_for(lock, chrono::milliseconds(SCANNER_WAIT_FOR_TIMEOUT));
224 }
225 
ScanDir()226 int32_t RingtoneScannerObj::ScanDir()
227 {
228     RINGTONE_INFO_LOG("scan dir %{private}s", dir_.c_str());
229 
230     int32_t ret = ScanDirInternal();
231     if (ret != E_OK) {
232         RINGTONE_ERR_LOG("ScanDirInternal err %{public}d", ret);
233     }
234 
235     (void)InvokeCallback(ret);
236 
237     return ret;
238 }
239 
ScanDirInternal()240 int32_t RingtoneScannerObj::ScanDirInternal()
241 {
242     if (RingtoneScannerUtils::IsDirHiddenRecursive(dir_)) {
243         RINGTONE_ERR_LOG("the dir %{private}s is hidden", dir_.c_str());
244         return E_DIR_HIDDEN;
245     }
246 
247     /* no further operation when stopped */
248     auto err = WalkFileTree(dir_);
249     if (err != E_OK) {
250         RINGTONE_ERR_LOG("walk file tree err %{public}d", err);
251         return err;
252     }
253     err = CommitTransaction();
254     if (err != E_OK) {
255         RINGTONE_ERR_LOG("commit transaction err %{public}d", err);
256         return err;
257     }
258 
259     err = CommitVibrateTransaction();
260     if (err != E_OK) {
261         RINGTONE_ERR_LOG("commit vibrate transaction err %{public}d", err);
262         return err;
263     }
264     err = CleanupDirectory();
265     if (err != E_OK) {
266         RINGTONE_ERR_LOG("clean up dir err %{public}d", err);
267         return err;
268     }
269 
270     return E_OK;
271 }
272 
CleanupDirectory()273 int32_t RingtoneScannerObj::CleanupDirectory()
274 {
275     return E_OK;
276 }
277 
CommitTransaction()278 int32_t RingtoneScannerObj::CommitTransaction()
279 {
280     unique_ptr<RingtoneMetadata> data;
281     string tableName = RINGTONE_TABLE;
282 
283     // will begin a transaction in later pr
284     for (uint32_t i = 0; i < dataBuffer_.size(); i++) {
285         data = move(dataBuffer_[i]);
286         if (data->GetToneId() != FILE_ID_DEFAULT) {
287             RingtoneScannerDb::UpdateMetadata(*data, tableName);
288         } else {
289             RingtoneScannerDb::InsertMetadata(*data, tableName);
290         }
291     }
292 
293     if (dataBuffer_.size() > 0) {
294         tonesScannedCount_ += dataBuffer_.size();
295     }
296     dataBuffer_.clear();
297 
298     return E_OK;
299 }
300 
CommitVibrateTransaction()301 int32_t RingtoneScannerObj::CommitVibrateTransaction()
302 {
303     unique_ptr<VibrateMetadata> vibrateData;
304     string vibrateTableName = VIBRATE_TABLE;
305 
306     for (uint32_t i = 0; i < vibrateDataBuffer_.size(); i++) {
307         vibrateData = move(vibrateDataBuffer_[i]);
308         if (vibrateData->GetVibrateId() != FILE_ID_DEFAULT) {
309             RingtoneScannerDb::UpdateVibrateMetadata(*vibrateData, vibrateTableName);
310         } else {
311             RingtoneScannerDb::InsertVibrateMetadata(*vibrateData, vibrateTableName);
312         }
313     }
314 
315     if (vibrateDataBuffer_.size() > 0) {
316         tonesScannedCount_ += vibrateDataBuffer_.size();
317     }
318     vibrateDataBuffer_.clear();
319 
320     return E_OK;
321 }
322 
WalkFileTree(const string & path)323 int32_t RingtoneScannerObj::WalkFileTree(const string &path)
324 {
325     int err = E_OK;
326     DIR *dirPath = nullptr;
327     struct dirent *ent = nullptr;
328     size_t len = path.length();
329     struct stat statInfo;
330     if (len >= FILENAME_MAX - 1) {
331         return ERR_INCORRECT_PATH;
332     }
333     auto fName = (char *)calloc(FILENAME_MAX, sizeof(char));
334     if (fName == nullptr) {
335         return E_NO_MEMORY;
336     }
337     if (strcpy_s(fName, FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
338         free(fName);
339         return E_ERR;
340     }
341     fName[len++] = '/';
342     if ((dirPath = opendir(path.c_str())) == nullptr) {
343         free(fName);
344         return E_PERMISSION_DENIED;
345     }
346     while ((ent = readdir(dirPath)) != nullptr) {
347         if (*stopFlag_) {
348             err = E_STOP;
349             break;
350         }
351         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
352             continue;
353         }
354         if (strncpy_s(fName + len, FILENAME_MAX - len, ent->d_name, FILENAME_MAX - len)) {
355             continue;
356         }
357         if (lstat(fName, &statInfo) == -1) {
358             continue;
359         }
360         string currentPath = fName;
361         if (S_ISDIR(statInfo.st_mode)) {
362             if (RingtoneScannerUtils::IsDirHidden(currentPath)) {
363                 continue;
364             }
365             (void)WalkFileTree(currentPath);
366         } else {
367             (void)ScanFileInTraversal(currentPath);
368         }
369     }
370     closedir(dirPath);
371     free(fName);
372     return err;
373 }
374 
ScanFileInTraversal(const string & path)375 int32_t RingtoneScannerObj::ScanFileInTraversal(const string &path)
376 {
377     path_ = path;
378     if (RingtoneScannerUtils::IsFileHidden(path_)) {
379         RINGTONE_ERR_LOG("the file is hidden");
380         return E_FILE_HIDDEN;
381     }
382 
383     bool flag = (path_.find(ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH) != std::string::npos) ? true : false;
384     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH) != std::string::npos);
385     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH) != std::string::npos);
386     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
387 
388     if (flag) {
389         if (extension.compare("json") == 0) {
390             isVibrateFile_ = true;
391             return ScanVibrateFile();
392         }
393         return E_OK;
394     }
395 
396     int32_t err = GetFileMetadata();
397     if (err != E_OK) {
398         if (err != E_SCANNED) {
399             RINGTONE_ERR_LOG("failed to get file metadata");
400         }
401         return err;
402     }
403 
404     err = BuildFileInfo();
405     if (err != E_OK) {
406         RINGTONE_ERR_LOG("failed to get other file metadata");
407         return err;
408     }
409 
410     return E_OK;
411 }
412 
GetFileMetadata()413 int32_t RingtoneScannerObj::GetFileMetadata()
414 {
415     if (path_.empty()) {
416         return E_INVALID_ARGUMENTS;
417     }
418     struct stat statInfo = { 0 };
419     if (stat(path_.c_str(), &statInfo) != 0) {
420         RINGTONE_ERR_LOG("stat syscall err %{public}d", errno);
421         return E_SYSCALL;
422     }
423 
424     int errCode = 0;
425     if (isVibrateFile_) {
426         errCode = BuildVibrateData(statInfo);
427         if (errCode != E_OK) {
428             return errCode;
429         }
430     } else {
431         errCode = BuildData(statInfo);
432         if (errCode != E_OK) {
433             return errCode;
434         }
435     }
436 
437     return E_OK;
438 }
439 
BuildFileInfo()440 int32_t RingtoneScannerObj::BuildFileInfo()
441 {
442     auto err = GetMediaInfo();
443     if (err != E_OK) {
444         RINGTONE_ERR_LOG("failed to get media info");
445     }
446 
447     err = AddToTransaction();
448     if (err != E_OK) {
449         RINGTONE_ERR_LOG("failed to add to transaction err %{public}d", err);
450         return err;
451     }
452 
453     return E_OK;
454 }
455 
AddToTransaction()456 int32_t RingtoneScannerObj::AddToTransaction()
457 {
458     if (isVibrateFile_) {
459         vibrateDataBuffer_.emplace_back(move(vibrateData_));
460         if (vibrateDataBuffer_.size() >= MAX_BATCH_SIZE) {
461             return CommitVibrateTransaction();
462         }
463     } else {
464         dataBuffer_.emplace_back(move(data_));
465         if (dataBuffer_.size() >= MAX_BATCH_SIZE) {
466             return CommitTransaction();
467         }
468     }
469 
470     return E_OK;
471 }
472 
GetMediaInfo()473 int32_t RingtoneScannerObj::GetMediaInfo()
474 {
475 #ifdef ENABLE_METADATA_EXTRACTOR
476     auto pos = data_->GetMimeType().find_first_of("/");
477     std::string mimePrefix = data_->GetMimeType().substr(0, pos) + "/*";
478     if (find(EXTRACTOR_SUPPORTED_MIME.begin(), EXTRACTOR_SUPPORTED_MIME.end(), mimePrefix) !=
479         EXTRACTOR_SUPPORTED_MIME.end()) {
480         return RingtoneMetadataExtractor::Extract(data_);
481     }
482 #endif // ENABLE_METADATA_EXTRACTOR
483     return E_OK;
484 }
485 
BuildData(const struct stat & statInfo)486 int32_t RingtoneScannerObj::BuildData(const struct stat &statInfo)
487 {
488     data_ = make_unique<RingtoneMetadata>();
489     if (data_ == nullptr) {
490         RINGTONE_ERR_LOG("failed to make unique ptr for metadata");
491         return E_DATA;
492     }
493 
494     if (S_ISDIR(statInfo.st_mode)) {
495         return E_INVALID_ARGUMENTS;
496     }
497 
498     int32_t err = RingtoneScannerDb::GetFileBasicInfo(path_, data_);
499     if (err != E_OK) {
500         RINGTONE_ERR_LOG("failed to get file basic info");
501         return err;
502     }
503 
504     for (const auto& pair : g_typeMap) {
505         if (path_.find(pair.first) == 0) {
506             data_->SetSourceType(pair.second.first);
507             data_->SetToneType(pair.second.second);
508         }
509     }
510 
511     // file path
512     data_->SetData(path_);
513     auto dispName = RingtoneScannerUtils::GetFileNameFromUri(path_);
514     data_->SetDisplayName(dispName);
515     if (data_->GetTitle() == TITLE_DEFAULT) {
516         data_->SetTitle(RingtoneScannerUtils::GetFileTitle(data_->GetDisplayName()));
517     }
518 
519     // statinfo
520     data_->SetSize(statInfo.st_size);
521     data_->SetDateModified(static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim)));
522 
523     // extension and type
524     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
525     std::string mimeType = RingtoneMimeTypeUtils::GetMimeTypeFromExtension(extension);
526     data_->SetMimeType(mimeType);
527     int32_t mime = RingtoneMimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
528     data_->SetMediaType(mime);
529 
530     return E_OK;
531 }
532 
BuildVibrateData(const struct stat & statInfo)533 int32_t RingtoneScannerObj::BuildVibrateData(const struct stat &statInfo)
534 {
535     vibrateData_ = make_unique<VibrateMetadata>();
536     if (vibrateData_ == nullptr) {
537         RINGTONE_ERR_LOG("failed to make unique ptr for metadata");
538         return E_DATA;
539     }
540 
541     if (S_ISDIR(statInfo.st_mode)) {
542         return E_INVALID_ARGUMENTS;
543     }
544 
545     int32_t err = RingtoneScannerDb::GetVibrateFileBasicInfo(path_, vibrateData_);
546     if (err != E_OK) {
547         RINGTONE_ERR_LOG("failed to get file basic info");
548         return err;
549     }
550 
551     for (const auto &pair : g_vibrateTypeMap) {
552         if (path_.find(pair.first) == 0) {
553             vibrateData_->SetSourceType(pair.second.first);
554             vibrateData_->SetVibrateType(pair.second.second);
555             int32_t ntype = 0;
556             if (pair.second.second == VIBRATE_TYPE_STANDARD) {
557                 ntype = (path_.find(ALARMS_TYPE) != string::npos) ? VIBRATE_TYPE_SALARM : VIBRATE_TYPE_STANDARD;
558                 ntype = (path_.find(RINGTONES_TYPE) != string::npos) ? VIBRATE_TYPE_SRINGTONE : ntype;
559                 ntype = (path_.find(NOTIFICATIONS_TYPE) != string::npos) ? \
560                     VIBRATE_TYPE_SNOTIFICATION : ntype;
561                 vibrateData_->SetVibrateType(ntype);
562             } else {
563                 ntype = (path_.find(ALARMS_TYPE) != string::npos) ? VIBRATE_TYPE_GALARM : VIBRATE_TYPE_GENTLE;
564                 ntype = (path_.find(RINGTONES_TYPE) != string::npos) ? VIBRATE_TYPE_GRINGTONE : ntype;
565                 ntype = (path_.find(NOTIFICATIONS_TYPE) != string::npos) ? \
566                     VIBRATE_TYPE_GNOTIFICATION : ntype;
567                 vibrateData_->SetVibrateType(ntype);
568             }
569         }
570     }
571 
572     for (const auto &pair : g_vibratePlayModeMap) {
573         if (path_.find(pair.first) == 0) {
574             vibrateData_->SetPlayMode(pair.second.second);
575         }
576     }
577 
578     // file path
579     vibrateData_->SetData(path_);
580     auto dispName = RingtoneScannerUtils::GetFileNameFromUri(path_);
581     vibrateData_->SetDisplayName(dispName);
582     if (vibrateData_->GetTitle() == TITLE_DEFAULT) {
583         vibrateData_->SetTitle(RingtoneScannerUtils::GetFileTitle(vibrateData_->GetDisplayName()));
584     }
585 
586     // statinfo
587     vibrateData_->SetSize(statInfo.st_size);
588     vibrateData_->SetDateModified(static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim)));
589 
590     return E_OK;
591 }
592 
ScanFileInternal()593 int32_t RingtoneScannerObj::ScanFileInternal()
594 {
595     if (RingtoneScannerUtils::IsFileHidden(path_)) {
596         RINGTONE_ERR_LOG("the file is hidden");
597         return E_FILE_HIDDEN;
598     }
599 
600     bool flag = (path_.find(ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH) != std::string::npos) ? true : false;
601     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH) != std::string::npos);
602     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH) != std::string::npos);
603     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
604 
605     if (flag) {
606         if (extension.compare("json") == 0) {
607             isVibrateFile_ = true;
608             return ScanVibrateFile();
609         }
610         return E_INVALID_PATH;
611     }
612 
613     int32_t err = GetFileMetadata();
614     if (err != E_OK) {
615         if (err != E_SCANNED) {
616             RINGTONE_ERR_LOG("failed to get file metadata");
617         }
618         return err;
619     }
620     err = GetMediaInfo();
621     if (err != E_OK) {
622         RINGTONE_ERR_LOG("failed to get ringtone info");
623     }
624 
625     err = Commit();
626     if (err != E_OK) {
627         RINGTONE_ERR_LOG("failed to commit err %{public}d", err);
628         return err;
629     }
630 
631     return E_OK;
632 }
633 
ScanVibrateFile()634 int32_t RingtoneScannerObj::ScanVibrateFile()
635 {
636     int32_t err = GetFileMetadata();
637     if (err != E_OK) {
638         if (err != E_SCANNED) {
639             RINGTONE_ERR_LOG("failed to get vibrate file metadata");
640         }
641         isVibrateFile_ = false;
642         return err;
643     }
644 
645     if (type_ == FILE) {
646         err = Commit();
647         if (err != E_OK) {
648             RINGTONE_ERR_LOG("failed to commit err %{public}d", err);
649             isVibrateFile_ = false;
650             return err;
651         }
652     } else {
653         err = AddToTransaction();
654         if (err != E_OK) {
655             RINGTONE_ERR_LOG("failed to add to transaction err %{public}d", err);
656             isVibrateFile_ = false;
657             return err;
658         }
659     }
660 
661     isVibrateFile_ = false;
662     return E_OK;
663 }
664 
Commit()665 int32_t RingtoneScannerObj::Commit()
666 {
667     std::string tab = RINGTONE_TABLE;
668 
669     if (isVibrateFile_) {
670         tab = VIBRATE_TABLE;
671 
672         if (vibrateData_->GetVibrateId() != FILE_ID_DEFAULT) {
673             uri_ = RingtoneScannerDb::UpdateVibrateMetadata(*vibrateData_, tab);
674         } else {
675             uri_ = RingtoneScannerDb::InsertVibrateMetadata(*vibrateData_, tab);
676         }
677     } else {
678         if (data_->GetToneId() != FILE_ID_DEFAULT) {
679             uri_ = RingtoneScannerDb::UpdateMetadata(*data_, tab);
680         } else {
681             uri_ = RingtoneScannerDb::InsertMetadata(*data_, tab);
682         }
683     }
684 
685     return E_OK;
686 }
687 } // namespace Media
688 } // namespace OHOS
689