• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "file_data_handler.h"
17 
18 #include <cstring>
19 #include <filesystem>
20 #include <memory>
21 #include <set>
22 #include <string>
23 #include <tuple>
24 #include <map>
25 #include <dirent.h>
26 #include <sys/statvfs.h>
27 #include <utime.h>
28 
29 #include "cloud_file_utils.h"
30 #include "data_sync_const.h"
31 #include "dfs_error.h"
32 #include "dfsu_timer.h"
33 #include "directory_ex.h"
34 #include "dk_assets_downloader.h"
35 #include "dk_error.h"
36 #include "gallery_album_const.h"
37 #include "gallery_file_const.h"
38 #include "gallery_sysevent.h"
39 #include "media_column.h"
40 #include "medialibrary_errno.h"
41 #include "medialibrary_rdb_utils.h"
42 #include "meta_file.h"
43 #include "thumbnail_const.h"
44 #include "task_state_manager.h"
45 
46 namespace OHOS {
47 namespace FileManagement {
48 namespace CloudSync {
49 using namespace std;
50 using namespace NativeRdb;
51 using namespace DriveKit;
52 using namespace Media;
53 using ChangeType = OHOS::AAFwk::ChangeInfo::ChangeType;
54 using PAC = Media::PhotoAlbumColumns;
55 using PM = Media::PhotoMap;
56 using PC = Media::PhotoColumn;
57 
58 constexpr uint32_t DAY_TO_SECONDS = 24 * 60 * 60;
59 constexpr uint32_t TO_MILLISECONDS = 1000;
60 static const string HMDFS_PATH_PREFIX = "/mnt/hmdfs/";
61 static const string CLOUD_MERGE_VIEW_PATH_SUFFIX = "/account/cloud_merge_view";
62 static const string TMP_SUFFIX = ".temp.download";
63 static const double START_AGING_SIZE = 0.5;
64 static const double STOP_AGING_SIZE = 0.6;
65 static const double LOWEST_START_AGING_SIZE = 0.15;
66 static const double LOWEST_STOP_AGING_SIZE = 0.2;
67 static const int64_t UNIT = 1000;
68 static const int64_t STD_UNIT = 1024;
69 static const int64_t THRESHOLD = 512;
70 
GetCloudMergeViewPath(int32_t userId,const string & relativePath)71 static string GetCloudMergeViewPath(int32_t userId, const string &relativePath)
72 {
73     return HMDFS_PATH_PREFIX + to_string(userId) + CLOUD_MERGE_VIEW_PATH_SUFFIX + relativePath;
74 }
75 
GetTotalSize()76 static int64_t GetTotalSize()
77 {
78     struct statvfs diskInfo;
79     int ret = statvfs("/data", &diskInfo);
80     if (ret != 0) {
81         LOGE("get totalsize failed, errno:%{public}d", errno);
82         return E_GET_SIZE_ERROR;
83     }
84     int64_t totalSize =
85         static_cast<long long>(diskInfo.f_bsize) * static_cast<long long>(diskInfo.f_blocks);
86     return totalSize;
87 }
88 
GetFreeSize()89 static int64_t GetFreeSize()
90 {
91     struct statvfs diskInfo;
92     int ret = statvfs("/data", &diskInfo);
93     if (ret != 0) {
94         LOGE("get feeesize failed, errno:%{public}d", errno);
95         return E_GET_SIZE_ERROR;
96     }
97     int64_t freeSize =
98         static_cast<long long>(diskInfo.f_bsize) * static_cast<long long>(diskInfo.f_bfree);
99     return freeSize;
100 }
101 
GetRoundSize(int64_t size)102 static int64_t GetRoundSize(int64_t size)
103 {
104     uint64_t val = 1;
105     int64_t multple = UNIT;
106     int64_t stdMultiple = STD_UNIT;
107     while (static_cast<int64_t>(val) * stdMultiple < size) {
108         val <<= 1;
109         if (val > THRESHOLD) {
110             val = 1;
111             multple *= UNIT;
112             stdMultiple *= STD_UNIT;
113         }
114     }
115     return static_cast<int64_t>(val) * multple;
116 }
117 
118 constexpr int DEFAULT_DOWNLOAD_THUMB_LIMIT = 500;
FileDataHandler(int32_t userId,const string & bundleName,std::shared_ptr<RdbStore> rdb,shared_ptr<bool> stopFlag)119 FileDataHandler::FileDataHandler(int32_t userId, const string &bundleName,
120                                  std::shared_ptr<RdbStore> rdb, shared_ptr<bool> stopFlag)
121     : RdbDataHandler(userId, bundleName, TABLE_NAME, rdb, stopFlag), userId_(userId), bundleName_(bundleName)
122 {
123     cloudPrefImpl_.GetInt(DOWNLOAD_THUMB_LIMIT, downloadThumbLimit_);
124     if (downloadThumbLimit_ <= 0) {
125         downloadThumbLimit_ = DEFAULT_DOWNLOAD_THUMB_LIMIT;
126         cloudPrefImpl_.SetInt(DOWNLOAD_THUMB_LIMIT, downloadThumbLimit_);
127     }
128 }
129 
GetFetchCondition(FetchCondition & cond)130 void FileDataHandler::GetFetchCondition(FetchCondition &cond)
131 {
132     cond.limitRes = LIMIT_SIZE;
133     cond.recordType = recordType_;
134     cond.desiredKeys = desiredKeys_;
135     cond.fullKeys = desiredKeys_;
136 }
137 
GetRetryRecords(std::vector<DriveKit::DKRecordId> & records)138 int32_t FileDataHandler::GetRetryRecords(std::vector<DriveKit::DKRecordId> &records)
139 {
140     NativeRdb::AbsRdbPredicates retryPredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
141     retryPredicates.SetWhereClause(PhotoColumn::PHOTO_DIRTY + " = ? ");
142     retryPredicates.SetWhereArgs({to_string(static_cast<int32_t>(DirtyType::TYPE_RETRY))});
143     retryPredicates.EqualTo(PC::PHOTO_CLEAN_FLAG, to_string(static_cast<int32_t>(NOT_NEED_CLEAN)));
144     retryPredicates.Limit(LIMIT_SIZE);
145 
146     auto results = Query(retryPredicates, {PhotoColumn::PHOTO_CLOUD_ID});
147     if (results == nullptr) {
148         LOGE("get nullptr modified result");
149         return E_RDB;
150     }
151 
152     while (results->GoToNextRow() == 0) {
153         string record;
154         int ret = DataConvertor::GetString(PhotoColumn::PHOTO_CLOUD_ID, record, *results);
155         if (ret == E_OK) {
156             records.emplace_back(record);
157         }
158     }
159 
160     return E_OK;
161 }
162 
AppendToDownload(NativeRdb::ResultSet & local,const std::string & fieldKey,std::vector<DKDownloadAsset> & assetsToDownload)163 void FileDataHandler::AppendToDownload(NativeRdb::ResultSet &local,
164                                        const std::string &fieldKey,
165                                        std::vector<DKDownloadAsset> &assetsToDownload)
166 {
167     DKDownloadAsset downloadAsset;
168     downloadAsset.recordType = recordType_;
169     downloadAsset.fieldKey = fieldKey;
170     string filePath;
171     int ret = DataConvertor::GetString(PhotoColumn::MEDIA_FILE_PATH, filePath, local);
172     if (ret != E_OK) {
173         LOGE("Get file path failed");
174         return;
175     }
176     string recordId;
177     ret = DataConvertor::GetString(PhotoColumn::PHOTO_CLOUD_ID, recordId, local);
178     if (ret != E_OK) {
179         LOGE("cannot get cloud_id fron result set");
180         return;
181     }
182     downloadAsset.recordId = recordId;
183 
184     const string &suffix = (fieldKey == "lcd") ? LCD_SUFFIX : THUMB_SUFFIX;
185     downloadAsset.downLoadPath = createConvertor_.GetThumbPath(filePath, suffix) + TMP_SUFFIX;
186     downloadAsset.asset.assetName = MetaFile::GetFileName(downloadAsset.downLoadPath);
187     downloadAsset.downLoadPath = MetaFile::GetParentDir(downloadAsset.downLoadPath);
188     ForceCreateDirectory(downloadAsset.downLoadPath);
189     assetsToDownload.push_back(downloadAsset);
190 }
191 
GetAssetsToDownload(vector<DriveKit::DKDownloadAsset> & outAssetsToDownload)192 int32_t FileDataHandler::GetAssetsToDownload(vector<DriveKit::DKDownloadAsset> &outAssetsToDownload)
193 {
194     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
195     predicates.EqualTo(Media::PhotoColumn::PHOTO_SYNC_STATUS,
196                        to_string(static_cast<int32_t>(SyncStatusType::TYPE_DOWNLOAD)));
197     predicates.EqualTo(PC::PHOTO_CLEAN_FLAG, to_string(static_cast<int32_t>(NOT_NEED_CLEAN)));
198     auto results = Query(predicates, MEDIA_CLOUD_SYNC_COLUMNS);
199     if (results == nullptr) {
200         LOGE("get nullptr TYPE_DOWNLOAD result");
201         return E_RDB;
202     }
203 
204     while (results->GoToNextRow() == 0) {
205         AppendToDownload(*results, "lcd", outAssetsToDownload);
206         AppendToDownload(*results, "thumbnail", outAssetsToDownload);
207     }
208     return E_OK;
209 }
210 
211 const std::vector<std::string> PULL_QUERY_COLUMNS = {
212     PhotoColumn::MEDIA_FILE_PATH,
213     PhotoColumn::MEDIA_SIZE,
214     PhotoColumn::MEDIA_DATE_MODIFIED,
215     PhotoColumn::PHOTO_DIRTY,
216     PhotoColumn::MEDIA_DATE_TRASHED,
217     PhotoColumn::PHOTO_POSITION,
218     PhotoColumn::PHOTO_CLOUD_ID,
219     PhotoColumn::PHOTO_CLOUD_VERSION,
220     MediaColumn::MEDIA_ID,
221     PhotoColumn::MEDIA_RELATIVE_PATH,
222     PhotoColumn::MEDIA_DATE_ADDED,
223     PhotoColumn::PHOTO_META_DATE_MODIFIED,
224     PhotoColumn::MEDIA_FILE_PATH,
225     PhotoColumn::PHOTO_SYNC_STATUS,
226     PhotoColumn::PHOTO_THUMB_STATUS,
227 };
228 
QueryLocalByCloudId(const vector<string> & recordIds)229 tuple<shared_ptr<NativeRdb::ResultSet>, map<string, int>> FileDataHandler::QueryLocalByCloudId(
230     const vector<string> &recordIds)
231 {
232     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
233     predicates.In(PhotoColumn::PHOTO_CLOUD_ID, recordIds);
234     auto resultSet = Query(predicates, PULL_QUERY_COLUMNS);
235     auto recordIdRowIdMap = map<string, int>();
236     if (resultSet == nullptr) {
237         LOGE("get nullptr created result");
238         return {nullptr, std::move(recordIdRowIdMap)};
239     }
240     int rowCount = 0;
241     int ret = resultSet->GetRowCount(rowCount);
242     if (ret != 0 || rowCount < 0) {
243         LOGE("result set get row count err %{public}d, rowCount %{public}d", ret, rowCount);
244         return {nullptr, std::move(recordIdRowIdMap)};
245     }
246     int columnIndex = 0;
247     resultSet->GetColumnIndex(PhotoColumn::PHOTO_CLOUD_ID, columnIndex);
248     for (int rowId = 0; rowId < rowCount; ++rowId) {
249         resultSet->GoToNextRow();
250         string recordId = "";
251         resultSet->GetString(columnIndex, recordId);
252         recordIdRowIdMap.insert(make_pair(recordId, rowId));
253     }
254     return {std::move(resultSet), std::move(recordIdRowIdMap)};
255 }
256 
257 const std::vector<std::string> CLEAN_QUERY_COLUMNS = {
258     PhotoColumn::MEDIA_FILE_PATH,
259     PhotoColumn::PHOTO_DIRTY,
260     PhotoColumn::MEDIA_DATE_TRASHED,
261     PhotoColumn::PHOTO_POSITION,
262     PhotoColumn::PHOTO_CLOUD_ID,
263 };
264 
265 
GetFileId(NativeRdb::ResultSet & local)266 static int32_t GetFileId(NativeRdb::ResultSet &local)
267 {
268     int32_t fileId;
269     int ret = DataConvertor::GetInt(MediaColumn::MEDIA_ID, fileId, local);
270     if (ret != E_OK) {
271         LOGE("Get file id failed");
272         return 0; // 0:invalid file id, not exits in db
273     }
274     return fileId;
275 }
276 
HandleRecord(shared_ptr<vector<DKRecord>> & records,OnFetchParams & params,vector<string> & recordIds,const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::map<std::string,int> & recordIdRowIdMap)277 int32_t FileDataHandler::HandleRecord(shared_ptr<vector<DKRecord>> &records, OnFetchParams &params,
278     vector<string> &recordIds, const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
279     const std::map<std::string, int> &recordIdRowIdMap)
280 {
281     int32_t ret = E_OK;
282     uint64_t success = 0;
283     uint64_t rdbFail = 0;
284     uint64_t dataFail = 0;
285 
286     for (auto &record : *records) {
287         int32_t fileId = 0;
288         ChangeType changeType = ChangeType::INVAILD;
289         if ((recordIdRowIdMap.find(record.GetRecordId()) == recordIdRowIdMap.end()) && !record.GetIsDelete()) {
290             CompensateFilePath(record);
291             ret = PullRecordInsert(record, params);
292             InsertAssetToPhotoMap(record, params);
293         } else if (recordIdRowIdMap.find(record.GetRecordId()) != recordIdRowIdMap.end()) {
294             resultSet->GoToRow(recordIdRowIdMap.at(record.GetRecordId()));
295             if (record.GetIsDelete()) {
296                 ret = PullRecordDelete(record, *resultSet);
297                 fileId = GetFileId(*resultSet);
298                 changeType = ChangeType::DELETE;
299             } else {
300                 ret = PullRecordUpdate(record, *resultSet, params);
301                 fileId = GetFileId(*resultSet);
302                 changeType = ChangeType::UPDATE;
303                 UpdateAssetInPhotoMap(record, fileId);
304             }
305         }
306         if (ret != E_OK) {
307             LOGE("recordId %s error %{public}d", record.GetRecordId().c_str(), ret);
308             if (ret == E_RDB) {
309                 rdbFail++;
310                 continue;
311             }
312             /* might need to specifiy which type error */
313             dataFail++;
314             ret = E_OK;
315         } else {
316             if (changeType != ChangeType::INSERT && changeType != ChangeType::INVAILD) {
317                 success++;
318             }
319         }
320         if (changeType != ChangeType::INVAILD) {
321             string notifyUri = PHOTO_URI_PREFIX + to_string(fileId);
322             DataSyncNotifier::GetInstance().TryNotify(notifyUri, changeType, to_string(fileId));
323         }
324     }
325 
326     UpdateMetaStat(INDEX_DL_META_SUCCESS, success);
327     UpdateMetaStat(INDEX_DL_META_ERROR_RDB, rdbFail);
328     UpdateMetaStat(INDEX_DL_META_ERROR_DATA, dataFail);
329 
330     return ret;
331 }
332 
OnFetchRecords(shared_ptr<vector<DKRecord>> & records,OnFetchParams & params)333 int32_t FileDataHandler::OnFetchRecords(shared_ptr<vector<DKRecord>> &records, OnFetchParams &params)
334 {
335     LOGI("on fetch %{public}zu records", records->size());
336     int32_t ret = E_OK;
337     auto recordIds = vector<string>();
338     for (auto &record : *records) {
339         recordIds.push_back(record.GetRecordId());
340     }
341     auto [resultSet, recordIdRowIdMap] = QueryLocalByCloudId(recordIds);
342     if (resultSet == nullptr) {
343         UpdateMetaStat(INDEX_DL_META_ERROR_RDB, recordIds.size());
344         return E_RDB;
345     }
346     ret = FileDataHandler::HandleRecord(records, params, recordIds, resultSet, recordIdRowIdMap);
347     LOGI("before BatchInsert size len %{public}zu, map size %{public}zu", params.insertFiles.size(),
348         params.recordAlbumMaps.size());
349     if (!params.insertFiles.empty() || !params.recordAlbumMaps.empty()) {
350         int64_t rowId;
351         ret = BatchInsert(rowId, TABLE_NAME, params.insertFiles);
352         if (ret != E_OK) {
353             LOGE("batch insert failed return %{public}d", ret);
354             UpdateMetaStat(INDEX_DL_META_ERROR_RDB, params.insertFiles.size());
355             ret = E_RDB;
356             params.assetsToDownload.clear();
357             return ret;
358         } else {
359             UpdateMetaStat(INDEX_DL_META_SUCCESS, params.insertFiles.size());
360             BatchInsertAssetMaps(params);
361         }
362     }
363     UpdateAlbumInternal();
364     LOGI("after BatchInsert ret %{public}d", ret);
365     DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX, ChangeType::INSERT,
366                                               INVALID_ASSET_ID);
367     DataSyncNotifier::GetInstance().FinalNotify();
368     MetaFileMgr::GetInstance().ClearAll();
369     return ret;
370 }
371 
CompensateFilePath(DriveKit::DKRecord & record)372 int32_t FileDataHandler::CompensateFilePath(DriveKit::DKRecord &record)
373 {
374     DKRecordData data;
375     record.GetRecordData(data);
376     if (data.find(FILE_ATTRIBUTES) == data.end() || data.find(FILE_SIZE) == data.end()) {
377         LOGE("record data cannot find attributes or size");
378         return E_INVAL_ARG;
379     }
380     DriveKit::DKRecordFieldMap attributes;
381     data[FILE_ATTRIBUTES].GetRecordMap(attributes);
382     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
383         LOGE("record data cannot find some attributes, may came from old devices");
384         string fullPath;
385         int ret = CalculateFilePath(record, fullPath);
386         if (ret != E_OK) {
387             return ret;
388         }
389         attributes[PhotoColumn::MEDIA_FILE_PATH] = DriveKit::DKRecordField(fullPath);
390         data[FILE_ATTRIBUTES] = DriveKit::DKRecordField(attributes);
391         record.SetRecordData(data);
392     }
393     return E_OK;
394 }
395 
GetDentryPathName(const string & fullPath,string & outPath,string & outFilename)396 static int GetDentryPathName(const string &fullPath, string &outPath, string &outFilename)
397 {
398     const string sandboxPrefix = "/storage/cloud";
399     size_t pos = fullPath.find_first_of(sandboxPrefix);
400     size_t lpos = fullPath.find_last_of("/");
401     if (pos != 0 || pos == string::npos || lpos == string::npos) {
402         LOGE("invalid path %{private}s", fullPath.c_str());
403         return E_INVAL_ARG;
404     }
405 
406     outPath = fullPath.substr(sandboxPrefix.length(), lpos - sandboxPrefix.length());
407     outPath = (outPath == "") ? "/" : outPath;
408     outFilename = fullPath.substr(lpos + 1);
409     return E_OK;
410 }
411 
DentryInsert(int userId,const DKRecord & record)412 static int32_t DentryInsert(int userId, const DKRecord &record)
413 {
414     DKRecordData data;
415     record.GetRecordData(data);
416     if (data.find(FILE_ATTRIBUTES) == data.end() || data.find(FILE_SIZE) == data.end()) {
417         LOGE("record data cannot find attributes or size");
418         return E_INVAL_ARG;
419     }
420     DriveKit::DKRecordFieldMap attibutes;
421     data[FILE_ATTRIBUTES].GetRecordMap(attibutes);
422     if (attibutes.find(PhotoColumn::MEDIA_FILE_PATH) == attibutes.end()) {
423         LOGE("record data cannot find some attributes");
424         return E_OK;
425     }
426 
427     string fullPath;
428     string relativePath;
429     string fileName;
430     if (attibutes[PhotoColumn::MEDIA_FILE_PATH].GetString(fullPath) != DKLocalErrorCode::NO_ERROR) {
431         LOGE("bad file_path in props");
432         return E_INVAL_ARG;
433     }
434     if (GetDentryPathName(fullPath, relativePath, fileName) != E_OK) {
435         LOGE("split to dentry path failed, path:%s", fullPath.c_str());
436         return E_INVAL_ARG;
437     }
438 
439     int64_t isize;
440     if (DataConvertor::GetLongComp(data[PhotoColumn::MEDIA_SIZE], isize) != E_OK) {
441         LOGE("bad size in props");
442         return E_INVAL_ARG;
443     }
444     int64_t mtime = static_cast<int64_t>(record.GetEditedTime()) / MILLISECOND_TO_SECOND;
445     string rawRecordId = record.GetRecordId();
446     string cloudId = MetaFileMgr::RecordIdToCloudId(rawRecordId);
447     auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId, relativePath);
448     MetaBase mBaseLookup(fileName);
449     MetaBase mBase(fileName, cloudId);
450     mBase.size = static_cast<uint64_t>(isize);
451     mBase.mtime = static_cast<uint64_t>(mtime);
452     if (mFile->DoLookup(mBaseLookup) == E_OK) {
453         LOGE("dentry exist when insert, do update instead");
454         return mFile->DoUpdate(mBase);
455     }
456     return mFile->DoCreate(mBase);
457 }
458 
DentryInsertThumb(const string & fullPath,const string & recordId,uint64_t size,uint64_t mtime,const string & type)459 int FileDataHandler::DentryInsertThumb(const string &fullPath,
460                                        const string &recordId,
461                                        uint64_t size,
462                                        uint64_t mtime,
463                                        const string &type)
464 {
465     string thumbnailPath = createConvertor_.GetThumbPathInCloud(fullPath, type);
466     string relativePath;
467     string fileName;
468     if (GetDentryPathName(thumbnailPath, relativePath, fileName) != E_OK) {
469         LOGE("split to dentry path failed, path:%s", thumbnailPath.c_str());
470         return E_INVAL_ARG;
471     }
472 
473     string cloudId = MetaFileMgr::RecordIdToCloudId(recordId);
474     auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
475     MetaBase mBaseLookup(fileName);
476     MetaBase mBase(fileName, cloudId);
477     mBase.size = size;
478     mBase.mtime = mtime;
479     mBase.fileType = (type == THUMB_SUFFIX) ? FILE_TYPE_THUMBNAIL : FILE_TYPE_LCD;
480     if (mFile->DoLookup(mBaseLookup) == E_OK) {
481         LOGI("dentry exist when insert, do update instead");
482         return mFile->DoUpdate(mBase);
483     }
484     return mFile->DoCreate(mBase);
485 }
486 
DentryRemoveThumb(const string & downloadPath)487 int FileDataHandler::DentryRemoveThumb(const string &downloadPath)
488 {
489     string thumbnailPath = createConvertor_.GetLocalPathToCloud(downloadPath);
490     string relativePath;
491     string fileName;
492     if (GetDentryPathName(thumbnailPath, relativePath, fileName) != E_OK) {
493         LOGE("split to dentry path failed, path:%s", thumbnailPath.c_str());
494         return E_INVAL_ARG;
495     }
496     auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
497     MetaBase mBase(fileName, "");
498     int ret = mFile->DoRemove(mBase);
499     if (ret != E_OK) {
500         LOGE("remove dentry failed, ret:%{public}d", ret);
501     }
502 
503     string cloudMergeViewPath = GetCloudMergeViewPath(userId_, relativePath + "/" + mBase.name);
504     if (remove(cloudMergeViewPath.c_str()) != 0) {
505         LOGD("update kernel dentry cache fail, errno: %{public}d, cloudMergeViewPath: %{public}s",
506              errno, cloudMergeViewPath.c_str());
507     }
508     return E_OK;
509 }
510 
AddCloudThumbs(const DKRecord & record)511 int FileDataHandler::AddCloudThumbs(const DKRecord &record)
512 {
513     LOGI("thumbs of %s add to cloud_view", record.GetRecordId().c_str());
514     constexpr uint64_t THUMB_SIZE = 2 * 1024 * 1024; // thumbnail and lcd size show as 2MB
515     uint64_t thumbSize = THUMB_SIZE;
516     uint64_t lcdSize = THUMB_SIZE;
517 
518     DKRecordData data;
519     DKAsset val;
520     record.GetRecordData(data);
521     if ((data.find(FILE_THUMBNAIL) != data.end()) &&
522         (data[FILE_THUMBNAIL].GetAsset(val) == DKLocalErrorCode::NO_ERROR) && (val.size != 0)) {
523         thumbSize = val.size;
524     } else {
525         LOGE("record data cannot get FILE_THUMBNAIL");
526     }
527     if ((data.find(FILE_LCD) != data.end()) &&
528         (data[FILE_LCD].GetAsset(val) == DKLocalErrorCode::NO_ERROR) && (val.size != 0)) {
529         lcdSize = val.size;
530     } else {
531         LOGE("record data cannot get FILE_LCD");
532     }
533     DriveKit::DKRecordFieldMap attributes;
534     string fullPath;
535     if (data.find(FILE_ATTRIBUTES) != data.end()) {
536         data[FILE_ATTRIBUTES].GetRecordMap(attributes);
537     }
538     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end() ||
539         attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(fullPath) != DKLocalErrorCode::NO_ERROR) {
540         LOGE("bad file path in record");
541         return E_INVAL_ARG;
542     }
543 
544     int64_t mtime = static_cast<int64_t>(record.GetEditedTime()) / MILLISECOND_TO_SECOND;
545     int ret = DentryInsertThumb(fullPath, record.GetRecordId(), thumbSize, mtime, THUMB_SUFFIX);
546     if (ret != E_OK) {
547         LOGE("dentry insert of thumb failed ret %{public}d", ret);
548         return ret;
549     }
550     ret = DentryInsertThumb(fullPath, record.GetRecordId(), lcdSize, mtime, LCD_SUFFIX);
551     if (ret != E_OK) {
552         LOGE("dentry insert of lcd failed ret %{public}d", ret);
553         return ret;
554     }
555     return E_OK;
556 }
557 
ConflictRenameThumb(NativeRdb::ResultSet & resultSet,string fullPath,string & tmpPath,string & newPath)558 string FileDataHandler::ConflictRenameThumb(NativeRdb::ResultSet &resultSet,
559                                             string fullPath,
560                                             string &tmpPath,
561                                             string &newPath)
562 {
563     /* thumb new path */
564     tmpPath = cleanConvertor_.GetThumbPath(fullPath, THUMB_SUFFIX);
565     if (tmpPath == "") {
566         LOGE("err tmp Path for GetThumbPath");
567         return "";
568     }
569     size_t tmpfound = tmpPath.find_last_of('/');
570     if (tmpfound == string::npos) {
571         LOGE("err tmp Path found");
572         return "";
573     }
574     tmpPath.resize(tmpfound);
575     size_t found = tmpPath.find_last_of('.');
576     if (found == string::npos) {
577         LOGE("err thumb Path found");
578         return "";
579     }
580     newPath = tmpPath.substr(0, found) + CON_SUFFIX + tmpPath.substr(found);
581     /* new name */
582     size_t namefound = newPath.find_last_of('/');
583     if (namefound == string::npos) {
584         LOGE("err name Path found");
585         return "";
586     }
587     string newName = newPath.substr(namefound + 1);
588     return newName;
589 }
590 
ConflictRenamePath(NativeRdb::ResultSet & resultSet,string & fullPath,string & rdbPath,string & localPath,string & newLocalPath)591 int32_t FileDataHandler::ConflictRenamePath(NativeRdb::ResultSet &resultSet,
592                                             string &fullPath,
593                                             string &rdbPath,
594                                             string &localPath,
595                                             string &newLocalPath)
596 {
597     /* sandbox new path */
598     size_t rdbfound = fullPath.find_last_of('.');
599     if (rdbfound == string::npos) {
600         LOGE("err rdb Path found");
601         return E_INVAL_ARG;
602     }
603     rdbPath = fullPath.substr(0, rdbfound) + CON_SUFFIX + fullPath.substr(rdbfound);
604     /* local new path */
605     localPath = cleanConvertor_.GetHmdfsLocalPath(fullPath);
606     if (localPath == "") {
607         LOGE("err local Path for GetHmdfsLocalPath");
608         return E_INVAL_ARG;
609     }
610     size_t localfound = localPath.find_last_of('.');
611     if (localfound == string::npos) {
612         LOGE("err local Path found");
613         return E_INVAL_ARG;
614     }
615     newLocalPath = localPath.substr(0, localfound) + CON_SUFFIX + localPath.substr(localfound);
616     return E_OK;
617 }
618 
ConflictRename(NativeRdb::ResultSet & resultSet,string & fullPath,string & relativePath)619 int32_t FileDataHandler::ConflictRename(NativeRdb::ResultSet &resultSet, string &fullPath, string &relativePath)
620 {
621     string rdbPath;
622     string tmpPath;
623     string newPath;
624     string localPath;
625     string newLocalPath;
626     int ret = ConflictRenamePath(resultSet, fullPath, rdbPath, tmpPath, newPath);
627     if (ret != E_OK) {
628         LOGE("ConflictRenamePath failed, ret=%{public}d", ret);
629         return E_INVAL_ARG;
630     }
631     /* thumb new path and new name */
632     string newName = ConflictRenameThumb(resultSet, fullPath, localPath, newLocalPath);
633     if (newName == "") {
634         LOGE("err Rename Thumb path");
635         return E_INVAL_ARG;
636     }
637     int updateRows;
638     ValuesBucket values;
639     values.PutString(PhotoColumn::MEDIA_FILE_PATH, rdbPath);
640     values.PutString(PhotoColumn::MEDIA_NAME, newName);
641     if (!relativePath.empty()) {
642         string newvirPath = relativePath + newName;
643         values.PutString(PhotoColumn::MEDIA_VIRTURL_PATH, newvirPath);
644     }
645     string whereClause = PhotoColumn::MEDIA_FILE_PATH + " = ?";
646     ret = Update(updateRows, values, whereClause, {fullPath});
647     if (ret != E_OK) {
648         LOGE("update retry flag failed, ret=%{public}d", ret);
649         return E_RDB;
650     }
651     ret = rename(tmpPath.c_str(), newPath.c_str());
652     if (ret != 0) {
653         LOGE("err rename localPath to newLocalPath, ret = %{public}d", ret);
654         return E_INVAL_ARG;
655     }
656     ret = rename(localPath.c_str(), newLocalPath.c_str());
657     if (ret != 0) {
658         LOGE("err rename tmpPath to newPath, ret = %{public}d", ret);
659         return E_INVAL_ARG;
660     }
661     return E_OK;
662 }
663 
ConflictDataMerge(DKRecord & record,string & fullPath,bool upflag)664 int32_t FileDataHandler::ConflictDataMerge(DKRecord &record, string &fullPath, bool upflag)
665 {
666     int updateRows;
667     ValuesBucket values;
668     values.PutString(PhotoColumn::PHOTO_CLOUD_ID, record.GetRecordId());
669     values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_BOTH);
670     values.PutInt(PC::PHOTO_CLEAN_FLAG, NOT_NEED_CLEAN);
671     if (upflag) {
672         values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_MDIRTY));
673     } else {
674         createConvertor_.RecordToValueBucket(record, values);
675         values.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
676         values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_SYNCED));
677     }
678     string whereClause = PhotoColumn::MEDIA_FILE_PATH + " = ?";
679     int32_t ret = Update(updateRows, values, whereClause, {fullPath});
680     if (ret != E_OK) {
681         LOGE("update retry flag failed, ret=%{public}d", ret);
682         return E_RDB;
683     }
684     return E_OK;
685 }
686 
ConflictHandler(NativeRdb::ResultSet & resultSet,const DKRecord & record,int64_t isize,bool & modifyPathflag)687 int32_t FileDataHandler::ConflictHandler(NativeRdb::ResultSet &resultSet,
688                                          const DKRecord &record,
689                                          int64_t isize,
690                                          bool &modifyPathflag)
691 {
692     string localId;
693     int ret = DataConvertor::GetString(PhotoColumn::PHOTO_CLOUD_ID, localId, resultSet);
694     if (ret != E_OK) {
695         LOGE("Get cloud id failed");
696         return E_INVAL_ARG;
697     }
698     if (ret == E_OK && !localId.empty()) {
699         LOGI("clould id not NULL %{public}s", localId.c_str());
700         modifyPathflag = true;
701     }
702     int64_t localIsize = 0;
703     ret = DataConvertor::GetLong(PhotoColumn::MEDIA_SIZE, localIsize, resultSet);
704     if (ret != E_OK) {
705         LOGE("Get local isize failed");
706         return E_INVAL_ARG;
707     }
708     int64_t localCrtime = 0;
709     ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_ADDED, localCrtime, resultSet);
710     if (ret != E_OK) {
711         LOGE("Get local ctime failed");
712         return E_INVAL_ARG;
713     }
714     int64_t crTime = static_cast<int64_t>(record.GetCreateTime());
715     if (localIsize == isize && localCrtime == crTime) {
716         LOGI("Possible duplicate files");
717     } else {
718         modifyPathflag = true;
719     }
720     return E_OK;
721 }
722 
ConflictDifferent(NativeRdb::ResultSet & resultSet,const DKRecord & record,string & fullPath,string & relativePath)723 int32_t FileDataHandler::ConflictDifferent(NativeRdb::ResultSet &resultSet,
724                                            const DKRecord &record,
725                                            string &fullPath,
726                                            string &relativePath)
727 {
728     LOGI("Different files with the same name");
729     /* Modify path */
730     int ret = ConflictRename(resultSet, fullPath, relativePath);
731     if (ret != E_OK) {
732         LOGE("Conflict dataMerge rename fail");
733         return ret;
734     }
735     return E_OK;
736 }
737 
ConflictMerge(NativeRdb::ResultSet & resultSet,DKRecord & record,string & fullPath,bool & comflag,int64_t & imetaModified)738 int32_t FileDataHandler::ConflictMerge(NativeRdb::ResultSet &resultSet,
739                                        DKRecord &record,
740                                        string &fullPath,
741                                        bool &comflag,
742                                        int64_t &imetaModified)
743 {
744     LOGI("Unification of the same document");
745     /* flag for update local data */
746     bool upflag = false;
747     int64_t localMeta = 0;
748     int ret = DataConvertor::GetLong(PhotoColumn::PHOTO_META_DATE_MODIFIED, localMeta, resultSet);
749     if (ret != E_OK) {
750         LOGE("Get local meta data modified failed");
751         return E_INVAL_ARG;
752     }
753     if (imetaModified < localMeta) {
754         upflag = true;
755     }
756     /* update database */
757     ret = ConflictDataMerge(record, fullPath, upflag);
758     if (ret != E_OK) {
759         LOGE("Conflict dataMerge fail");
760         return ret;
761     }
762     comflag = true;
763     return E_OK;
764 }
765 
GetConflictData(const DKRecord & record,string & fullPath,int64_t & isize,int64_t & imetaModified,string & relativePath)766 int32_t FileDataHandler::GetConflictData(const DKRecord &record,
767                                          string &fullPath,
768                                          int64_t &isize,
769                                          int64_t &imetaModified,
770                                          string &relativePath)
771 {
772     DKRecordData data;
773     record.GetRecordData(data);
774     if (data.find(FILE_ATTRIBUTES) == data.end() || data.find(FILE_SIZE) == data.end()) {
775         LOGE("record data cannot find attributes or size");
776         return E_INVAL_ARG;
777     }
778     DriveKit::DKRecordFieldMap attributes;
779     data[FILE_ATTRIBUTES].GetRecordMap(attributes);
780     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
781         LOGE("record data cannot find some attributes, may came from old devices");
782         return E_INVAL_ARG;
783     }
784     if (attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(fullPath) != DKLocalErrorCode::NO_ERROR) {
785         LOGE("bad file_path in attributes");
786         return E_INVAL_ARG;
787     }
788     if (attributes[PhotoColumn::MEDIA_RELATIVE_PATH].GetString(relativePath) != DKLocalErrorCode::NO_ERROR) {
789         LOGE("bad virtual_Path in attributes");
790         return E_INVAL_ARG;
791     }
792     if (DataConvertor::GetLongComp(data[PhotoColumn::MEDIA_SIZE], isize) != E_OK) {
793         LOGE("bad size in data");
794         return E_INVAL_ARG;
795     }
796     if (attributes[PhotoColumn::PHOTO_META_DATE_MODIFIED].GetLong(imetaModified) != DKLocalErrorCode::NO_ERROR) {
797         LOGE("bad meta data modified in attributes");
798         return E_INVAL_ARG;
799     }
800     return E_OK;
801 }
802 
CalculateFilePath(DKRecord & record,string & filePath)803 int32_t FileDataHandler::CalculateFilePath(DKRecord &record, string &filePath)
804 {
805     // method reference from medialibrary
806     int32_t mediaType;
807     int32_t ret = GetMediaType(record, mediaType);
808     if (ret != E_OK) {
809         return E_INVAL_ARG;
810     }
811     int32_t uniqueId = GetAssetUniqueId(mediaType);
812     if (uniqueId < 0) {
813         return E_RDB;
814     }
815     int32_t errCode = CreateAssetPathById(record, uniqueId, mediaType, filePath);
816     return errCode;
817 }
818 
GetMediaType(DKRecord & record,int32_t & mediaType)819 int32_t FileDataHandler::GetMediaType(DKRecord &record, int32_t &mediaType)
820 {
821     DKRecordData data;
822     record.GetRecordData(data);
823     if (data.find(FILE_FILETYPE) == data.end()) {
824         LOGE("record data cannot find properties");
825         return E_INVAL_ARG;
826     }
827     int32_t fileType;
828     if (data[FILE_FILETYPE].GetInt(fileType) != DKLocalErrorCode::NO_ERROR) {
829         LOGE("record data cannot find fileType");
830         return E_INVAL_ARG;
831     }
832     mediaType = fileType == FILE_TYPE_VIDEO ? MediaType::MEDIA_TYPE_VIDEO : MediaType::MEDIA_TYPE_IMAGE;
833     return E_OK;
834 }
835 
GetAssetUniqueId(int32_t & type)836 int32_t FileDataHandler::GetAssetUniqueId(int32_t &type)
837 {
838     string typeString;
839     switch (type) {
840         case MediaType::MEDIA_TYPE_IMAGE:
841             typeString += IMAGE_ASSET_TYPE;
842             break;
843         case MediaType::MEDIA_TYPE_VIDEO:
844             typeString += VIDEO_ASSET_TYPE;
845             break;
846         default:
847             LOGE("This type %{public}d can not get unique id", type);
848             return MediaType::MEDIA_TYPE_FILE;
849     }
850     std::lock_guard<std::mutex> lock(rdbMutex_);
851     string sql = " UPDATE UniqueNumber SET unique_number = unique_number + 1  WHERE media_type = ?";
852     std::vector<NativeRdb::ValueObject> bingArgs;
853     bingArgs.emplace_back(typeString);
854     int32_t ret = ExecuteSql(sql, bingArgs);
855     if (ret != E_OK) {
856         LOGI("update unique number fail");
857         return -1;
858     }
859     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(ASSET_UNIQUE_NUMBER_TABLE);
860     predicates.SetWhereClause(ASSET_MEDIA_TYPE + " = ?");
861     predicates.SetWhereArgs({typeString});
862     auto resultSet = Query(predicates, {UNIQUE_NUMBER});
863     int32_t uniqueId = 0;
864     if (resultSet->GoToNextRow() == 0) {
865         if (DataConvertor::GetInt(UNIQUE_NUMBER, uniqueId, *resultSet) != E_OK) {
866             LOGI("query unique number fail");
867             return -1;
868         }
869     }
870     return uniqueId;
871 }
872 
CreateAssetPathById(DKRecord & record,int32_t & uniqueId,int32_t & mediaType,string & filePath)873 int32_t FileDataHandler::CreateAssetPathById(DKRecord &record, int32_t &uniqueId,
874     int32_t &mediaType, string &filePath)
875 {
876     string mediaDirPath = "Photo/";
877     int32_t bucketNum = 0;
878     int32_t errCode = CreateAssetBucket(uniqueId, bucketNum);
879     if (errCode != E_OK) {
880         return errCode;
881     }
882 
883     string realName;
884     errCode = CreateAssetRealName(uniqueId, mediaType, GetFileExtension(record), realName);
885     if (errCode != E_OK) {
886         return errCode;
887     }
888     string dirPath = ROOT_MEDIA_DIR + mediaDirPath + to_string(bucketNum);
889     filePath = dirPath + "/" + realName;
890     return E_OK;
891 }
892 
CreateAssetBucket(int32_t & uniqueId,int32_t & bucketNum)893 int32_t FileDataHandler::CreateAssetBucket(int32_t &uniqueId, int32_t &bucketNum)
894 {
895     if (uniqueId < 0) {
896         LOGE("input uniqueId [%{private}d] is invalid", uniqueId);
897         return E_INVAL_ARG;
898     }
899     int start = ASSET_DIR_START_NUM;
900     int divider = ASSET_DIR_START_NUM;
901     while (uniqueId > start * ASSET_IN_BUCKET_NUM_MAX) {
902         divider = start;
903         start <<= 1;
904     }
905 
906     int fileIdRemainder = uniqueId % divider;
907     if (fileIdRemainder == 0) {
908         bucketNum = start + fileIdRemainder;
909     } else {
910         bucketNum = (start - divider) + fileIdRemainder;
911     }
912     return E_OK;
913 }
914 
CreateAssetRealName(int32_t & fileId,int32_t & mediaType,const string & extension,string & name)915 int32_t FileDataHandler::CreateAssetRealName(int32_t &fileId, int32_t &mediaType,
916     const string &extension, string &name)
917 {
918     string fileNumStr = to_string(fileId);
919     if (fileId <= ASSET_MAX_COMPLEMENT_ID) {
920         size_t fileIdLen = fileNumStr.length();
921         fileNumStr = ("00" + fileNumStr).substr(fileIdLen - 1);
922     }
923 
924     string mediaTypeStr;
925     switch (mediaType) {
926         case MediaType::MEDIA_TYPE_IMAGE:
927             mediaTypeStr = DEFAULT_IMAGE_NAME;
928             break;
929         case MediaType::MEDIA_TYPE_VIDEO:
930             mediaTypeStr = DEFAULT_VIDEO_NAME;
931             break;
932         default:
933             LOGE("This mediatype %{public}d can not get real name", mediaType);
934             return E_INVAL_ARG;
935     }
936 
937     name = mediaTypeStr + to_string(UTCTimeSeconds()) + "_" + fileNumStr + "." + extension;
938     return E_OK;
939 }
940 
PullRecordConflict(DKRecord & record,bool & comflag)941 int32_t FileDataHandler::PullRecordConflict(DKRecord &record, bool &comflag)
942 {
943     LOGD("judgment downlode conflict");
944     string fullPath, relativePath;
945     int64_t isize, imetaModified;
946     int32_t ret = GetConflictData(record, fullPath, isize, imetaModified, relativePath);
947     if (ret != E_OK) {
948         LOGE("Getdata fail");
949         return ret;
950     }
951     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
952     predicates.SetWhereClause(PhotoColumn::MEDIA_FILE_PATH + " = ?");
953     predicates.SetWhereArgs({fullPath});
954     predicates.Limit(LIMIT_SIZE);
955     auto resultSet = Query(predicates, PULL_QUERY_COLUMNS);
956     if (resultSet == nullptr) {
957         LOGE("get nullptr created result");
958         return E_RDB;
959     }
960     int32_t rowCount = 0;
961     ret = resultSet->GetRowCount(rowCount);
962     if (ret != 0) {
963         LOGE("result set get row count err %{public}d", ret);
964         return E_RDB;
965     }
966     if (rowCount == 0) {
967         LOGD("Normal download process");
968         return E_OK;
969     }
970     if (rowCount == 1) {
971         resultSet->GoToNextRow();
972         bool modifyPathflag = false;
973         ret = ConflictHandler(*resultSet, record, isize, modifyPathflag);
974         if (ret != E_OK) {
975             return ret;
976         }
977         if (modifyPathflag) {
978             ret = ConflictDifferent(*resultSet, record, fullPath, relativePath);
979         } else {
980             ret = ConflictMerge(*resultSet, record, fullPath, comflag, imetaModified);
981         }
982         if (comflag) {
983             UpdateAssetInPhotoMap(record, GetFileId(*resultSet));
984         }
985     } else {
986         LOGE("unknown error: PullRecordConflict(),same path rowCount = %{public}d", rowCount);
987         ret = E_RDB;
988     }
989     return ret;
990 }
991 
GetFileExtension(DKRecord & record)992 string FileDataHandler::GetFileExtension(DKRecord &record)
993 {
994     DKRecordData data;
995     record.GetRecordData(data);
996     if (data.find(FILE_FILE_NAME) == data.end()) {
997         LOGE("record data cannot find properties");
998         return "";
999     }
1000     string displayName;
1001     if (data[FILE_FILE_NAME].GetString(displayName) != DKLocalErrorCode::NO_ERROR) {
1002         LOGE("record data cannot find fileType");
1003         return "";
1004     }
1005     string extension;
1006     if (!displayName.empty()) {
1007         string::size_type pos = displayName.find_last_of('.');
1008         if (pos == string::npos) {
1009             return "";
1010         }
1011         extension = displayName.substr(pos + 1);
1012     }
1013     return extension;
1014 }
1015 
IfContainsFullField(const DriveKit::DKRecord & record)1016 static bool IfContainsFullField(const DriveKit::DKRecord &record)
1017 {
1018     DriveKit::DKRecordData data;
1019     record.GetRecordData(data);
1020     if (data.find(FILE_ATTRIBUTES) != data.end()) {
1021         DriveKit::DKRecordFieldMap attributes;
1022         data[FILE_ATTRIBUTES].GetRecordMap(attributes);
1023         return !(attributes.find(PhotoColumn::MEDIA_TITLE) == attributes.end());
1024     }
1025     return false;
1026 }
1027 
PullRecordInsert(DKRecord & record,OnFetchParams & params)1028 int32_t FileDataHandler::PullRecordInsert(DKRecord &record, OnFetchParams &params)
1029 {
1030     RETURN_ON_ERR(IsStop());
1031     LOGI("insert of record %{public}s", record.GetRecordId().c_str());
1032     /* check local file conflict */
1033     bool comflag = false;
1034     int ret = PullRecordConflict(record, comflag);
1035     if (comflag) {
1036         LOGI("Conflict:same document no Insert");
1037         return E_OK;
1038     } else if (ret != E_OK) {
1039         LOGE("MetaFile Conflict failed %{public}d", ret);
1040     }
1041     ret = DentryInsert(userId_, record);
1042     if (ret != E_OK) {
1043         LOGE("MetaFile Create failed %{public}d", ret);
1044         return ret;
1045     }
1046 
1047     ValuesBucket values;
1048     ret = createConvertor_.RecordToValueBucket(record, values);
1049     if (ret != E_OK) {
1050         LOGE("record to valuebucket failed, ret=%{public}d", ret);
1051         return ret;
1052     }
1053     if (!IfContainsFullField(record)) {
1054         values.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY));
1055     } else {
1056         values.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
1057     }
1058     values.PutInt(PC::PHOTO_CLEAN_FLAG, static_cast<int32_t>(NOT_NEED_CLEAN));
1059     values.PutInt(Media::PhotoColumn::PHOTO_POSITION, POSITION_CLOUD);
1060     values.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
1061     values.PutInt(Media::PhotoColumn::PHOTO_THUMB_STATUS, static_cast<int32_t>(ThumbState::TO_DOWNLOAD));
1062     values.PutString(Media::PhotoColumn::PHOTO_CLOUD_ID, record.GetRecordId());
1063     if (IsPullRecords()) {
1064         values.PutInt(Media::PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
1065     } else {
1066         values.PutInt(Media::PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_DOWNLOAD));
1067     }
1068     params.insertFiles.push_back(values);
1069     if (AddCloudThumbs(record) != E_OK || !IsPullRecords()) {
1070         AppendToDownload(record, "lcd", params.assetsToDownload);
1071         AppendToDownload(record, "thumbnail", params.assetsToDownload);
1072     } else if ((++params.totalPullCount <= downloadThumbLimit_)) {
1073         // the first 500 thms when pull records.
1074         AppendToDownload(record, "thumbnail", params.assetsToDownload);
1075     }
1076     return E_OK;
1077 }
1078 
OnDownloadAssets(const map<DKDownloadAsset,DKDownloadResult> & resultMap)1079 int32_t FileDataHandler::OnDownloadAssets(const map<DKDownloadAsset, DKDownloadResult> &resultMap)
1080 {
1081     RETURN_ON_ERR(IsStop());
1082     uint64_t thumbError = 0;
1083     uint64_t lcdError = 0;
1084 
1085     for (const auto &it : resultMap) {
1086         auto asset = it.first;
1087         if (it.second.IsSuccess()) {
1088             LOGI("%{public}s %{public}s %{public}s download succeed", asset.recordId.c_str(),
1089                 asset.asset.assetName.c_str(), asset.fieldKey.c_str());
1090             continue;
1091         }
1092 
1093         if (it.first.fieldKey == FILE_THUMBNAIL) {
1094             thumbError++;
1095             if (IsPullRecords()) {
1096                 continue;
1097             }
1098             // set visible when download failed
1099             LOGI("update sync_status to visible of record %s", it.first.recordId.c_str());
1100             int updateRows;
1101             ValuesBucket values;
1102             values.PutInt(Media::PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
1103 
1104             string whereClause = Media::PhotoColumn::PHOTO_CLOUD_ID + " = ?";
1105             int32_t ret = Update(updateRows, values, whereClause, {it.first.recordId});
1106             if (ret != E_OK) {
1107                 LOGE("update retry flag failed, ret=%{public}d", ret);
1108             }
1109             DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX, ChangeType::INSERT,
1110                                                       to_string(updateRows));
1111         } else if (it.first.fieldKey == FILE_LCD) {
1112             lcdError++;
1113         }
1114         LOGE("%{public}s %{public}s %{public}s download fail, localErr: %{public}d, serverErr: %{public}d",
1115             asset.recordId.c_str(), asset.asset.assetName.c_str(), asset.fieldKey.c_str(),
1116             static_cast<int>(it.second.GetDKError().dkErrorCode), it.second.GetDKError().serverErrorCode);
1117     }
1118 
1119     if (thumbError > 0) {
1120         UpdateAttachmentStat(INDEX_THUMB_ERROR_SDK, thumbError);
1121     }
1122 
1123     if (lcdError > 0) {
1124         UpdateAttachmentStat(INDEX_LCD_ERROR_SDK, lcdError);
1125     }
1126 
1127     return E_OK;
1128 }
1129 
OnDownloadAssets(const DKDownloadAsset & asset)1130 int32_t FileDataHandler::OnDownloadAssets(const DKDownloadAsset &asset)
1131 {
1132     RETURN_ON_ERR(IsStop());
1133     if (asset.fieldKey == "thumbnail") {
1134         std::lock_guard<std::mutex> lock(thmMutex_);
1135         thmVec_.emplace_back(asset.recordId);
1136     }
1137     if (asset.fieldKey == "lcd") {
1138         std::lock_guard<std::mutex> lock(lcdMutex_);
1139         lcdVec_.emplace_back(asset.recordId);
1140     }
1141     string tempPath = asset.downLoadPath + "/" + asset.asset.assetName;
1142     string localPath = CloudDisk::CloudFileUtils::GetPathWithoutTmp(tempPath);
1143     DentryRemoveThumb(localPath);
1144     if (rename(tempPath.c_str(), localPath.c_str()) != 0) {
1145         LOGE("err rename, errno: %{public}d, tmpLocalPath: %s, localPath: %s",
1146              errno, tempPath.c_str(), localPath.c_str());
1147     }
1148     MetaFileMgr::GetInstance().ClearAll();
1149     return E_OK;
1150 }
1151 
OnDownloadAssetsFailure(const std::vector<DriveKit::DKDownloadAsset> & assets)1152 int32_t FileDataHandler::OnDownloadAssetsFailure(const std::vector<DriveKit::DKDownloadAsset> &assets)
1153 {
1154     uint64_t thumbError = 0;
1155     uint64_t lcdError = 0;
1156 
1157     /* account first */
1158     for (auto &asset : assets) {
1159         if (asset.fieldKey == FILE_THUMBNAIL) {
1160             thumbError++;
1161         } else if (asset.fieldKey == FILE_LCD) {
1162             lcdError++;
1163         }
1164     }
1165 
1166     /* update atomic value at once */
1167     if (thumbError > 0) {
1168         UpdateAttachmentStat(INDEX_THUMB_ERROR_SDK, thumbError);
1169     }
1170 
1171     if (lcdError > 0) {
1172         UpdateAttachmentStat(INDEX_LCD_ERROR_SDK, lcdError);
1173     }
1174 
1175     return E_OK;
1176 }
1177 
IsLocalDirty(NativeRdb::ResultSet & local)1178 static bool IsLocalDirty(NativeRdb::ResultSet &local)
1179 {
1180     int dirty;
1181     int ret = DataConvertor::GetInt(PhotoColumn::PHOTO_DIRTY, dirty, local);
1182     if (ret != E_OK) {
1183         LOGE("Get dirty int failed");
1184         return false;
1185     }
1186     return (dirty == static_cast<int32_t>(DirtyType::TYPE_MDIRTY)) ||
1187            (dirty == static_cast<int32_t>(DirtyType::TYPE_FDIRTY)) ||
1188            (dirty == static_cast<int32_t>(DirtyType::TYPE_DELETED));
1189 }
1190 
GetFilePath(NativeRdb::ResultSet & local)1191 static string GetFilePath(NativeRdb::ResultSet &local)
1192 {
1193     string filePath;
1194     int ret = DataConvertor::GetString(PhotoColumn::MEDIA_FILE_PATH, filePath, local);
1195     if (ret != E_OK) {
1196         LOGE("Get file path failed");
1197         return "";
1198     }
1199     return filePath;
1200 }
1201 
GetLocalPath(int userId,const string & filePath)1202 static string GetLocalPath(int userId, const string &filePath)
1203 {
1204     const string sandboxPrefix = "/storage/cloud";
1205     const string dfsPrefix = "/mnt/hmdfs/";
1206     const string dfsSuffix = "/account/cloud_merge_view";
1207     size_t pos = filePath.find_first_of(sandboxPrefix);
1208     if (pos != 0 || pos == string::npos) {
1209         LOGE("invalid path %{private}s", filePath.c_str());
1210         return "";
1211     }
1212 
1213     string dfsPath = dfsPrefix + to_string(userId) + dfsSuffix + filePath.substr(sandboxPrefix.length());
1214     return dfsPath;
1215 }
SetRetry(vector<NativeRdb::ValueObject> & retryList)1216 int32_t FileDataHandler::SetRetry(vector<NativeRdb::ValueObject> &retryList)
1217 {
1218     if (retryList.empty()) {
1219         return E_OK;
1220     }
1221     LOGE("abnormal data set retry!");
1222     std::stringstream ss;
1223     for (unsigned int i = 0; i < retryList.size(); i++) {
1224         if (ss.tellp() != 0) {
1225             ss << ",";
1226         }
1227         ss <<" ? ";
1228     }
1229     string sql = "UPDATE " + PC::PHOTOS_TABLE + " SET " + PC::PHOTO_DIRTY + " = " +
1230         to_string(static_cast<int32_t>(Media::DirtyType::TYPE_RETRY)) + " WHERE " + PC::PHOTO_CLOUD_ID +
1231         " IN ( " + ss.str() + " )";
1232     int32_t ret = ExecuteSql(sql, retryList);
1233     if (ret != E_OK) {
1234         LOGE("update retry flag failed, ret=%{public}d", ret);
1235         return E_RDB;
1236     }
1237     retryList.clear();
1238     return E_OK;
1239 }
1240 
1241 /**
1242  * Add locks to prevent multiple threads from updating albums at the same time.
1243  * Only set a flag in media library while using this function.
1244  * When data number is large, use this function.
1245  */
UpdateAlbumInternal()1246 void FileDataHandler::UpdateAlbumInternal()
1247 {
1248     std::lock_guard<std::mutex> lock(rdbMutex_);
1249     MediaLibraryRdbUtils::UpdateSystemAlbumCountInternal(GetRaw());
1250     MediaLibraryRdbUtils::UpdateUserAlbumCountInternal(GetRaw());
1251 }
1252 
1253 /**
1254  * Add locks to prevent multiple threads from updating albums at the same time.
1255  * Check Photos table to update all photo albums (system and user) in a synchronous operation.
1256  * When clean user data, use this function
1257  */
UpdateAllAlbums()1258 void FileDataHandler::UpdateAllAlbums()
1259 {
1260     std::lock_guard<std::mutex> lock(rdbMutex_);
1261     MediaLibraryRdbUtils::UpdateSystemAlbumInternal(GetRaw());
1262     MediaLibraryRdbUtils::UpdateUserAlbumInternal(GetRaw());
1263 }
1264 
SetRetry(const string & recordId)1265 int FileDataHandler::SetRetry(const string &recordId)
1266 {
1267     LOGI("set retry of record %s", recordId.c_str());
1268     int updateRows;
1269     ValuesBucket values;
1270     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_RETRY));
1271     string whereClause = PhotoColumn::PHOTO_CLOUD_ID + " = ?";
1272     int32_t ret = Update(updateRows, values, whereClause, {recordId});
1273     if (ret != E_OK) {
1274         LOGE("update retry flag failed, ret=%{public}d", ret);
1275         return E_RDB;
1276     }
1277     return E_OK;
1278 }
1279 
FileIsLocal(NativeRdb::ResultSet & local)1280 static bool FileIsLocal(NativeRdb::ResultSet &local)
1281 {
1282     int position = 0;
1283     int ret = DataConvertor::GetInt(PhotoColumn::PHOTO_POSITION, position, local);
1284     if (ret != E_OK) {
1285         LOGE("Get local position failed");
1286         return false;
1287     }
1288 
1289     return !!(static_cast<uint32_t>(position) & 1);
1290 }
1291 
GetCloudMtime(const DKRecord & record,int64_t & dateModified)1292 static inline int GetCloudMtime(const DKRecord &record, int64_t &dateModified)
1293 {
1294     DriveKit::DKRecordData data;
1295     record.GetRecordData(data);
1296     if (data.find(FILE_ATTRIBUTES) == data.end()) {
1297         return E_INVAL_ARG;
1298     }
1299     DriveKit::DKRecordFieldMap attributes;
1300     data[FILE_ATTRIBUTES].GetRecordMap(attributes);
1301     if (attributes.find(FILE_EDITED_TIME_MS) == data.end()) {
1302         return E_INVAL_ARG;
1303     }
1304     if (attributes[FILE_EDITED_TIME_MS].GetLong(dateModified) !=  DKLocalErrorCode::NO_ERROR) {
1305         return E_INVAL_ARG;
1306     }
1307     return E_OK;
1308 }
1309 
IsMtimeChanged(const DKRecord & record,NativeRdb::ResultSet & local,bool & changed)1310 static int IsMtimeChanged(const DKRecord &record, NativeRdb::ResultSet &local, bool &changed)
1311 {
1312     int64_t localMtime = 0;
1313     int64_t dateModified = 0;
1314     int ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_MODIFIED, localMtime, local);
1315     if ((ret == E_OK) && (GetCloudMtime(record, dateModified) == E_OK)) {
1316         LOGI("dateModified %{public}llu, localMtime %{public}llu",
1317             static_cast<unsigned long long>(dateModified), static_cast<unsigned long long>(localMtime));
1318         changed = !(dateModified == localMtime);
1319         return E_OK;
1320     }
1321 
1322     // get local mtime
1323     int64_t localCrtime = 0;
1324     ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_ADDED, localCrtime, local);
1325     if (ret != E_OK) {
1326         LOGE("Get local ctime failed");
1327         return E_INVAL_ARG;
1328     }
1329 
1330     // get record mtime
1331     int64_t crTime = static_cast<int64_t>(record.GetCreateTime());
1332     LOGI("cloudMtime %{public}llu, localMtime %{public}llu",
1333          static_cast<unsigned long long>(crTime), static_cast<unsigned long long>(localCrtime));
1334     changed = !(crTime == localCrtime);
1335     return E_OK;
1336 }
1337 
PullRecordUpdate(DKRecord & record,NativeRdb::ResultSet & local,OnFetchParams & params)1338 int32_t FileDataHandler::PullRecordUpdate(DKRecord &record, NativeRdb::ResultSet &local, OnFetchParams &params)
1339 {
1340     RETURN_ON_ERR(IsStop());
1341     LOGI("update of record %s", record.GetRecordId().c_str());
1342     if (IsLocalDirty(local)) {
1343         LOGI("local record dirty, ignore cloud update");
1344         return E_OK;
1345     }
1346     bool mtimeChanged = false;
1347     if (IsMtimeChanged(record, local, mtimeChanged) != E_OK) {
1348         return E_INVAL_ARG;
1349     }
1350     if (FileIsLocal(local)) {
1351         string filePath = GetFilePath(local);
1352         string localPath = GetLocalPath(userId_, filePath);
1353         if (CloudDisk::CloudFileUtils::LocalWriteOpen(localPath)) {
1354             return SetRetry(record.GetRecordId());
1355         }
1356         if (mtimeChanged) {
1357             LOGI("cloud file DATA changed, %s", record.GetRecordId().c_str());
1358             int ret = unlink(localPath.c_str());
1359             if (ret != 0) {
1360                 LOGE("unlink local failed, errno %{public}d", errno);
1361             }
1362             DentryInsert(userId_, record);
1363         }
1364     }
1365     LOGI("cloud file META changed, %s", record.GetRecordId().c_str());
1366     ValuesBucket values;
1367     createConvertor_.RecordToValueBucket(record, values);
1368     int ret = UpdateMediaFilePath(record, local);
1369     if (ret != E_OK) {
1370         LOGE("update media file path fail, ret = %{public}d", ret);
1371         values.Delete(PC::MEDIA_FILE_PATH);
1372     }
1373     values.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
1374     values.PutInt(PhotoMap::DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_SYNCED));
1375     values.PutInt(PC::PHOTO_CLEAN_FLAG, static_cast<int32_t>(NOT_NEED_CLEAN));
1376     int32_t changedRows;
1377     string whereClause = PhotoColumn::PHOTO_CLOUD_ID + " = ?";
1378     ret = Update(changedRows, values, whereClause, {record.GetRecordId()});
1379     if (ret != E_OK) {
1380         return E_RDB;
1381     }
1382     if (mtimeChanged && (ThumbsAtLocal(record) || (AddCloudThumbs(record) != E_OK))) {
1383         AppendToDownload(record, "lcd", params.assetsToDownload);
1384         AppendToDownload(record, "thumbnail", params.assetsToDownload);
1385     }
1386     LOGI("update of record success");
1387     return E_OK;
1388 }
1389 
CheckContentConsistency(NativeRdb::ResultSet & resultSet)1390 int32_t FileDataHandler::CheckContentConsistency(NativeRdb::ResultSet &resultSet)
1391 {
1392     string filePath = GetFilePath(resultSet);
1393     string localPath = createConvertor_.GetLowerPath(filePath);
1394 
1395     /* local */
1396     bool local = access(localPath.c_str(), F_OK) == 0;
1397     if (!local && errno != ENOENT) {
1398         LOGE("fail to access %{public}d", errno);
1399         return E_SYSCALL;
1400     }
1401 
1402     /* cloud */
1403     string relativePath;
1404     string fileName;
1405     int ret = GetDentryPathName(filePath, relativePath, fileName);
1406     if (ret != E_OK) {
1407         LOGE("split to dentry path failed, path:%s", filePath.c_str());
1408         return ret;
1409     }
1410     auto dir = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
1411     if (dir == nullptr) {
1412         return E_DATA;
1413     }
1414     MetaBase file(fileName);
1415     bool cloud = dir->DoLookup(file) == E_OK;
1416 
1417     /* check */
1418     if (local && cloud) {
1419         LOGE("[CHECK AND FIX] try to delete cloud dentry %{public}s", filePath.c_str());
1420         UpdateCheckAttachment(INDEX_CHECK_FOUND, 1);
1421 
1422         struct stat st;
1423         ret = stat(localPath.c_str(), &st);
1424         if (ret != 0) {
1425             LOGE("stat local file error %{public}d", errno);
1426             return E_SYSCALL;
1427         }
1428 
1429         if (st.st_size != static_cast<long>(file.size)) {
1430             ret = unlink(localPath.c_str());
1431             if (ret != 0) {
1432                 LOGE("unlink local file error %{public}d", errno);
1433                 return E_SYSCALL;
1434             }
1435         } else {
1436             ret = dir->DoRemove(file);
1437             if (ret != E_OK) {
1438                 LOGE("remove cloud dentry fail %{public}d", ret);
1439                 return ret;
1440             }
1441         }
1442 
1443         UpdateCheckAttachment(INDEX_CHECK_FIXED, 1);
1444     } else if (!local && !cloud) {
1445         LOGE("[CHECK AND FIX] try to fill in cloud dentry %{public}s", filePath.c_str());
1446         UpdateCheckAttachment(INDEX_CHECK_FOUND, 1);
1447 
1448         string cloudId;
1449         ret = DataConvertor::GetString(PhotoColumn::PHOTO_CLOUD_ID, cloudId, resultSet);
1450         if (ret != E_OK) {
1451             return ret;
1452         }
1453         file.cloudId = MetaFileMgr::RecordIdToCloudId(cloudId);
1454 
1455         int64_t val;
1456         ret = DataConvertor::GetLong(PhotoColumn::MEDIA_SIZE, val, resultSet);
1457         if (ret != E_OK) {
1458             return ret;
1459         }
1460         file.size = val;
1461 
1462         ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_MODIFIED, val, resultSet);
1463         if (ret != E_OK) {
1464             return ret;
1465         }
1466         file.mtime = val;
1467 
1468         ret = dir->DoCreate(file);
1469         if (ret != E_OK) {
1470             LOGE("create cloud dentry fail %{public}d", ret);
1471             return ret;
1472         }
1473 
1474         UpdateCheckAttachment(INDEX_CHECK_FIXED, 1);
1475     }
1476 
1477     return E_OK;
1478 }
1479 
CheckThumbConsistency(NativeRdb::ResultSet & resultSet,const string & suffix)1480 int32_t FileDataHandler::CheckThumbConsistency(NativeRdb::ResultSet &resultSet, const string &suffix)
1481 {
1482     string filePath;
1483     int32_t ret = DataConvertor::GetString(PhotoColumn::MEDIA_FILE_PATH, filePath, resultSet);
1484     if (ret != E_OK) {
1485         LOGE("Get file path failed %{public}d", ret);
1486         return ret;
1487     }
1488     string thumb = createConvertor_.GetThumbPath(filePath, suffix);
1489 
1490     /* local */
1491     bool local = access(thumb.c_str(), F_OK) == 0;
1492     if (!local && errno != ENOENT) {
1493         LOGE("fail to access %{public}d", errno);
1494         return E_SYSCALL;
1495     }
1496 
1497     /* cloud */
1498     string relativePath;
1499     string fileName;
1500     string cloudPath = createConvertor_.GetThumbPathInCloud(filePath, suffix);
1501     if (GetDentryPathName(cloudPath, relativePath, fileName) != E_OK) {
1502         LOGE("split to dentry path failed, path: %s", cloudPath.c_str());
1503         return E_INVAL_ARG;
1504     }
1505 
1506     auto dir = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
1507     if (dir == nullptr) {
1508         return E_DATA;
1509     }
1510     MetaBase file(fileName);
1511     bool cloud = dir->DoLookup(file) == E_OK;
1512     if (local && cloud) {
1513         LOGE("[CHECK AND FIX] try to delete cloud dentry %{public}s", cloudPath.c_str());
1514         UpdateCheckAttachment(INDEX_CHECK_FOUND, 1);
1515 
1516         struct stat st;
1517         ret = stat(thumb.c_str(), &st);
1518         if (ret != 0) {
1519             LOGE("stat local file error %{public}d", errno);
1520             return E_SYSCALL;
1521         }
1522 
1523         if (st.st_size != static_cast<long>(file.size)) {
1524             ret = unlink(thumb.c_str());
1525             if (ret != 0) {
1526                 LOGE("unlink local file error %{public}d", errno);
1527                 return E_SYSCALL;
1528             }
1529         } else {
1530             ret = dir->DoRemove(file);
1531             if (ret != E_OK) {
1532                 LOGE("remove cloud dentry fail %{public}d", ret);
1533                 return ret;
1534             }
1535         }
1536 
1537         UpdateCheckAttachment(INDEX_CHECK_FIXED, 1);
1538     } else if (!local && !cloud) {
1539         /* FIX ME: hardcode thumbnail size show as 2MB */
1540         constexpr uint64_t THUMB_SIZE = 2 * 1024 * 1024;
1541         file.size = THUMB_SIZE;
1542 
1543         LOGE("[CHECK AND FIX] try to fill in cloud dentry %{public}s", thumb.c_str());
1544         UpdateCheckAttachment(INDEX_CHECK_FOUND, 1);
1545 
1546         string cloudId;
1547         ret = DataConvertor::GetString(PhotoColumn::PHOTO_CLOUD_ID, cloudId, resultSet);
1548         if (ret != E_OK) {
1549             return ret;
1550         }
1551         file.cloudId = MetaFileMgr::RecordIdToCloudId(cloudId);
1552 
1553         int64_t val;
1554         ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_MODIFIED, val, resultSet);
1555         if (ret != E_OK) {
1556             return ret;
1557         }
1558         file.mtime = val;
1559 
1560         file.fileType = (suffix == THUMB_SUFFIX) ? FILE_TYPE_THUMBNAIL : FILE_TYPE_LCD;
1561 
1562         ret = dir->DoCreate(file);
1563         if (ret != E_OK) {
1564             LOGE("dir create file error %{public}d", ret);
1565             return ret;
1566         }
1567 
1568         UpdateCheckAttachment(INDEX_CHECK_FIXED, 1);
1569     }
1570 
1571     return E_OK;
1572 }
1573 
CheckAssetConsistency(NativeRdb::ResultSet & resultSet)1574 int32_t FileDataHandler::CheckAssetConsistency(NativeRdb::ResultSet &resultSet)
1575 {
1576     /* content */
1577     int32_t ret = CheckContentConsistency(resultSet);
1578     if (ret != E_OK) {
1579         return ret;
1580     }
1581 
1582     /* thumb */
1583     ret = CheckThumbConsistency(resultSet, THUMB_SUFFIX);
1584     if (ret != E_OK) {
1585         return ret;
1586     }
1587 
1588     /* lcd */
1589     ret = CheckThumbConsistency(resultSet, LCD_SUFFIX);
1590     if (ret != E_OK) {
1591         return ret;
1592     }
1593 
1594     return E_OK;
1595 }
1596 
CheckDirtyConsistency(NativeRdb::ResultSet & resultSet)1597 int32_t FileDataHandler::CheckDirtyConsistency(NativeRdb::ResultSet &resultSet)
1598 {
1599     int32_t dirty;
1600     int32_t ret = DataConvertor::GetInt(PhotoColumn::PHOTO_DIRTY, dirty, resultSet);
1601     if (ret != E_OK) {
1602         return ret;
1603     }
1604 
1605     if (dirty == static_cast<int32_t>(DirtyType::TYPE_FDIRTY)) {
1606         string filePath = GetFilePath(resultSet);
1607         string localPath = createConvertor_.GetLowerPath(filePath);
1608 
1609         bool local = access(localPath.c_str(), F_OK) == 0;
1610         if (!local && errno != ENOENT) {
1611             LOGE("fail to access %{public}d", errno);
1612             return E_SYSCALL;
1613         }
1614         if (!local) {
1615             LOGE("[CHECK AND FIX] try to set dirty as synced %{public}s", filePath.c_str());
1616             UpdateCheckFile(INDEX_CHECK_FOUND, 1);
1617 
1618             ValuesBucket values;
1619             values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_SYNCED));
1620             int32_t changedRows;
1621             string whereClause = PhotoColumn::MEDIA_FILE_PATH + " = ?";
1622             ret = Update(changedRows, values, whereClause, { filePath });
1623             if (ret != E_OK) {
1624                 LOGE("rdb update failed, err = %{public}d", ret);
1625                 return E_RDB;
1626             }
1627 
1628             UpdateCheckFile(INDEX_CHECK_FIXED, 1);
1629         }
1630     }
1631 
1632     return E_OK;
1633 }
1634 
CheckPositionConsistency(NativeRdb::ResultSet & resultSet)1635 int32_t FileDataHandler::CheckPositionConsistency(NativeRdb::ResultSet &resultSet)
1636 {
1637     int32_t pos;
1638     int32_t ret = DataConvertor::GetInt(PhotoColumn::PHOTO_POSITION, pos, resultSet);
1639     if (ret != E_OK) {
1640         return ret;
1641     }
1642 
1643     string filePath = GetFilePath(resultSet);
1644     string localPath = createConvertor_.GetLowerPath(filePath);
1645     bool local = access(localPath.c_str(), F_OK) == 0;
1646     if (!local && errno != ENOENT) {
1647         LOGE("fail to access %{public}d", errno);
1648         return E_SYSCALL;
1649     }
1650 
1651     ValuesBucket values;
1652     if (pos == POSITION_CLOUD && local) {
1653         values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_BOTH);
1654     } else if (pos == POSITION_BOTH && !local) {
1655         values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_CLOUD);
1656     } else {
1657         return E_OK;
1658     }
1659 
1660     LOGE("[CHECK AND FIX] try to change position %{public}s", filePath.c_str());
1661     UpdateCheckFile(INDEX_CHECK_FOUND, 1);
1662 
1663     int32_t changedRows;
1664     string whereClause = PhotoColumn::MEDIA_FILE_PATH + " = ?";
1665     ret = Update(changedRows, values, whereClause, { filePath });
1666     if (ret != E_OK) {
1667         LOGE("rdb update failed, err = %{public}d", ret);
1668         return E_RDB;
1669     }
1670 
1671     UpdateCheckFile(INDEX_CHECK_FIXED, 1);
1672 
1673     return E_OK;
1674 }
1675 
CheckSyncStatusConsistency(NativeRdb::ResultSet & resultSet)1676 int32_t FileDataHandler::CheckSyncStatusConsistency(NativeRdb::ResultSet &resultSet)
1677 {
1678     int32_t syncStatus;
1679     int32_t ret = DataConvertor::GetInt(PhotoColumn::PHOTO_SYNC_STATUS, syncStatus, resultSet);
1680     if (ret != E_OK) {
1681         return ret;
1682     }
1683     if (syncStatus != static_cast<int32_t>(SyncStatusType::TYPE_DOWNLOAD)) {
1684         return E_OK;
1685     }
1686 
1687     int32_t thumbStatus;
1688     ret = DataConvertor::GetInt(PhotoColumn::PHOTO_THUMB_STATUS, thumbStatus, resultSet);
1689     if (ret != E_OK) {
1690         return ret;
1691     }
1692     if (thumbStatus <= static_cast<int32_t>(ThumbState::LCD_TO_DOWNLOAD)) {
1693         return E_OK;
1694     }
1695 
1696     string filePath = GetFilePath(resultSet);
1697     string thumbLocalPath = createConvertor_.GetThumbPath(filePath, THUMB_SUFFIX);
1698     bool local = access(thumbLocalPath.c_str(), F_OK) == 0;
1699     if (!local && errno != ENOENT) {
1700         LOGE("fail to access %{public}d", errno);
1701         return E_SYSCALL;
1702     }
1703 
1704     LOGE("[CHECK AND FIX] try to change sync status %{public}s", filePath.c_str());
1705     UpdateCheckFile(INDEX_CHECK_FOUND, 1);
1706 
1707     ValuesBucket values;
1708     if (local) {
1709         values.PutInt(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
1710     } else {
1711         values.PutInt(PhotoColumn::PHOTO_THUMB_STATUS, static_cast<int32_t>(ThumbState::THM_TO_DOWNLOAD));
1712     }
1713     int32_t changedRows;
1714     string whereClause = PhotoColumn::MEDIA_FILE_PATH + " = ?";
1715     ret = Update(changedRows, values, whereClause, { filePath });
1716     if (ret != E_OK) {
1717         LOGE("rdb update failed, err = %{public}d", ret);
1718         return E_RDB;
1719     }
1720 
1721     UpdateCheckFile(INDEX_CHECK_FIXED, 1);
1722 
1723     return E_OK;
1724 }
1725 
CheckStatusConsistency(NativeRdb::ResultSet & resultSet)1726 int32_t FileDataHandler::CheckStatusConsistency(NativeRdb::ResultSet &resultSet)
1727 {
1728     /* dirty */
1729     int32_t ret = CheckDirtyConsistency(resultSet);
1730     if (ret != E_OK) {
1731         return ret;
1732     }
1733 
1734     /* postion */
1735     ret = CheckPositionConsistency(resultSet);
1736     if (ret != E_OK) {
1737         return ret;
1738     }
1739 
1740     /* sync status */
1741     ret = CheckSyncStatusConsistency(resultSet);
1742     if (ret != E_OK) {
1743         return ret;
1744     }
1745 
1746     return E_OK;
1747 }
1748 
CheckDataConsistency(NativeRdb::ResultSet & resultSet)1749 int32_t FileDataHandler::CheckDataConsistency(NativeRdb::ResultSet &resultSet)
1750 {
1751     /* asset */
1752     int32_t ret = CheckAssetConsistency(resultSet);
1753     if (ret == E_STOP) {
1754         return ret;
1755     }
1756 
1757     /* status */
1758     ret = CheckStatusConsistency(resultSet);
1759     if (ret == E_STOP) {
1760         return ret;
1761     }
1762 
1763     return E_OK;
1764 }
1765 
GetCheckRecords(vector<DriveKit::DKRecordId> & checkRecords,const shared_ptr<std::vector<DriveKit::DKRecord>> & records)1766 int32_t FileDataHandler::GetCheckRecords(vector<DriveKit::DKRecordId> &checkRecords,
1767     const shared_ptr<std::vector<DriveKit::DKRecord>> &records)
1768 {
1769     auto recordIds = vector<string>();
1770     shared_ptr<std::vector<DriveKit::DKRecord>> fetchRecords = make_shared<std::vector<DriveKit::DKRecord>>();
1771     for (const auto &record : *records) {
1772         fetchRecords->emplace_back(record);
1773     }
1774     auto [resultSet, recordIdRowIdMap] = QueryLocalByCloudId(recordIds);
1775     if (resultSet == nullptr) {
1776         return E_RDB;
1777     }
1778 
1779     for (const auto &record : *records) {
1780         if ((recordIdRowIdMap.find(record.GetRecordId()) == recordIdRowIdMap.end()) && !record.GetIsDelete()) {
1781             fetchRecords->emplace_back(record);
1782         } else if (recordIdRowIdMap.find(record.GetRecordId()) != recordIdRowIdMap.end()) {
1783             int32_t ret = resultSet->GoToRow(recordIdRowIdMap.at(record.GetRecordId()));
1784             if (ret != NativeRdb::E_OK) {
1785                 LOGE("got to row error %{public}d", ret);
1786                 continue;
1787             }
1788 
1789             ret = CheckDataConsistency(*resultSet);
1790             if (ret != E_OK) {
1791                 LOGE("data check error");
1792                 /* implies continue if returning non-ok */
1793                 continue;
1794             }
1795 
1796             int64_t version = 0;
1797             DataConvertor::GetLong(PhotoColumn::PHOTO_CLOUD_VERSION, version, *resultSet);
1798             if (record.GetVersion() != static_cast<unsigned long>(version) &&
1799                 (!IsLocalDirty(*resultSet) || record.GetIsDelete())) {
1800                 fetchRecords->emplace_back(record);
1801             }
1802         } else {
1803             LOGE("recordId %s has multiple file in db!", record.GetRecordId().c_str());
1804         }
1805     }
1806 
1807     OnFetchParams params;
1808     OnFetchRecords(fetchRecords, params);
1809 
1810     return E_OK;
1811 }
1812 
ThumbsAtLocal(const DKRecord & record)1813 bool FileDataHandler::ThumbsAtLocal(const DKRecord &record)
1814 {
1815     DKRecordData datas;
1816     record.GetRecordData(datas);
1817     if (datas.find(FILE_ATTRIBUTES) == datas.end()) {
1818         LOGE("record data cannot find attributes");
1819         return false;
1820     }
1821     DriveKit::DKRecordFieldMap attributes;
1822     datas[FILE_ATTRIBUTES].GetRecordMap(attributes);
1823 
1824     string fullPath;
1825     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end() ||
1826         attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(fullPath) != DKLocalErrorCode::NO_ERROR) {
1827         LOGE("bad file path in record");
1828         return false;
1829     }
1830 
1831     string thumbLocalPath = createConvertor_.GetThumbPath(fullPath, THUMB_SUFFIX);
1832     return access(thumbLocalPath.c_str(), F_OK) == 0;
1833 }
1834 
FileIsRecycled(NativeRdb::ResultSet & local)1835 static bool FileIsRecycled(NativeRdb::ResultSet &local)
1836 {
1837     int64_t localDateTrashed = 0;
1838     int ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_TRASHED, localDateTrashed, local);
1839     if (ret != E_OK) {
1840         LOGE("Get local recycled failed");
1841         return false;
1842     }
1843 
1844     return localDateTrashed > 0;
1845 }
1846 
UTCTimeMilliSeconds()1847 static int64_t UTCTimeMilliSeconds()
1848 {
1849     struct timespec t;
1850     clock_gettime(CLOCK_REALTIME, &t);
1851     return t.tv_sec * SECOND_TO_MILLISECOND + t.tv_nsec / SECOND_TO_MILLISECOND;
1852 }
1853 
1854 // if cloud delete but local exist, we would do recycle instead of delete
RecycleFile(const string & recordId)1855 int FileDataHandler::RecycleFile(const string &recordId)
1856 {
1857     LOGI("recycle of record %s", recordId.c_str());
1858 
1859     ValuesBucket values;
1860     values.PutNull(PhotoColumn::PHOTO_CLOUD_ID);
1861     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_NEW));
1862     values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_LOCAL);
1863     values.PutLong(PhotoColumn::MEDIA_DATE_TRASHED, UTCTimeMilliSeconds());
1864     values.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, 0);
1865     int32_t changedRows;
1866     string whereClause = PhotoColumn::PHOTO_CLOUD_ID + " = ?";
1867     int ret = Update(changedRows, values, whereClause, {recordId});
1868     if (ret != E_OK) {
1869         LOGE("rdb update failed, err=%{public}d", ret);
1870         return E_RDB;
1871     }
1872     return E_OK;
1873 }
1874 
RemoveThmParentPath(const string & filePath)1875 void FileDataHandler::RemoveThmParentPath(const string &filePath)
1876 {
1877     string thmbFile = cleanConvertor_.GetThumbPath(filePath, THUMB_SUFFIX);
1878     filesystem::path thmbFilePath(thmbFile.c_str());
1879     filesystem::path thmbFileParentPath = thmbFilePath.parent_path();
1880     LOGD("filePath: %s, thmbFile: %s, thmbFileParentDir: %s", filePath.c_str(), thmbFile.c_str(),
1881          thmbFileParentPath.string().c_str());
1882     ForceRemoveDirectory(thmbFileParentPath.string());
1883 }
1884 
PullRecordDelete(DKRecord & record,NativeRdb::ResultSet & local)1885 int32_t FileDataHandler::PullRecordDelete(DKRecord &record, NativeRdb::ResultSet &local)
1886 {
1887     LOGI("delete of record %s", record.GetRecordId().c_str());
1888     string filePath = GetFilePath(local);
1889     string localPath = GetLocalPath(userId_, filePath);
1890 
1891     bool isLocal = FileIsLocal(local);
1892     if (FileIsRecycled(local) || !isLocal) {
1893         if (isLocal) {
1894             LOGI("force delete instead");
1895             int ret = unlink(localPath.c_str());
1896             if (ret != 0) {
1897                 LOGE("unlink local failed, errno %{public}d", errno);
1898             }
1899         } else { // delete dentry
1900             string relativePath;
1901             string fileName;
1902             if (GetDentryPathName(filePath, relativePath, fileName) != E_OK) {
1903                 LOGE("split to dentry path failed, path:%s", filePath.c_str());
1904                 return E_INVAL_ARG;
1905             }
1906             auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
1907             MetaBase mBase(fileName);
1908             int ret = mFile->DoRemove(mBase);
1909             if (ret != E_OK) {
1910                 LOGE("remove dentry failed, ret:%{public}d", ret);
1911             }
1912         }
1913         // delete THM
1914         RemoveThmParentPath(filePath);
1915         // delete rdb
1916         int32_t deletedRows;
1917         int ret = Delete(deletedRows, Media::PhotoColumn::PHOTO_CLOUD_ID + " = ?", {record.GetRecordId()});
1918         if (ret != E_OK) {
1919             LOGE("delete in rdb failed, ret:%{public}d", ret);
1920             return E_INVAL_ARG;
1921         }
1922         DeleteAssetInPhotoMap(GetFileId(local));
1923         return E_OK;
1924     }
1925 
1926     if (IsLocalDirty(local)) {
1927         LOGI("local record dirty, ignore cloud delete");
1928         return ClearCloudInfo(record.GetRecordId());
1929     }
1930 
1931     if (CloudDisk::CloudFileUtils::LocalWriteOpen(localPath)) {
1932         return SetRetry(record.GetRecordId());
1933     }
1934     return RecycleFile(record.GetRecordId());
1935 }
1936 
DeleteMetaFile(const string & sboxPath,const int32_t & userId)1937 static int32_t DeleteMetaFile(const string &sboxPath, const int32_t &userId)
1938 {
1939     // delete dentry
1940     string fileName;
1941     string relativePath;
1942     if (GetDentryPathName(sboxPath, relativePath, fileName) != E_OK) {
1943         LOGE("split to dentry path failed, path:%s", sboxPath.c_str());
1944         return E_INVAL_ARG;
1945     }
1946 
1947     auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId, relativePath);
1948     MetaBase mBase(fileName);
1949     int ret = mFile->DoRemove(mBase);
1950     if (ret != E_OK) {
1951         LOGE("remove dentry failed, ret:%{public}d", ret);
1952     }
1953 
1954     /*
1955      * after removing file item from dentryfile, we should delete file
1956      * of cloud merge view to update kernel dentry cache.
1957      */
1958     string cloudMergeViewPath = GetCloudMergeViewPath(userId, relativePath + "/" + mBase.name);
1959     if (remove(cloudMergeViewPath.c_str()) != 0) {
1960         LOGE("update kernel dentry cache fail, errno: %{public}d, cloudMergeViewPath: %{public}s",
1961              errno, cloudMergeViewPath.c_str());
1962     }
1963 
1964     return E_OK;
1965 }
1966 
OnDownloadSuccess(const DriveKit::DKDownloadAsset & asset)1967 int32_t FileDataHandler::OnDownloadSuccess(const DriveKit::DKDownloadAsset &asset)
1968 {
1969     string tmpLocalPath = asset.downLoadPath + "/" + asset.asset.assetName;
1970     string localPath = CloudDisk::CloudFileUtils::GetPathWithoutTmp(tmpLocalPath);
1971     string tmpSboxPath = localConvertor_.GetSandboxPath(tmpLocalPath);
1972     string sboxPath = CloudDisk::CloudFileUtils::GetPathWithoutTmp(tmpSboxPath);
1973 
1974     // delete dentry
1975     int ret = DeleteMetaFile(sboxPath, userId_);
1976     if (ret != E_OK) {
1977         return ret;
1978     }
1979 
1980     if (rename(tmpLocalPath.c_str(), localPath.c_str()) != 0) {
1981         LOGE("err rename, errno: %{public}d, tmpLocalPath: %s, localPath: %s",
1982              errno, tmpLocalPath.c_str(), localPath.c_str());
1983     }
1984 
1985     auto recordIds = vector<string>();
1986     recordIds.push_back(asset.recordId);
1987     auto [resultSet, recordIdRowIdMap] = QueryLocalByCloudId(recordIds);
1988     if (resultSet == nullptr || recordIdRowIdMap.size() != 1) {
1989         LOGE("QueryLocalByCloudId failed rowCount %{public}zu", recordIdRowIdMap.size());
1990         return E_INVAL_ARG;
1991     }
1992     resultSet->GoToNextRow();
1993     int64_t localMtime = 0;
1994     ret = DataConvertor::GetLong(PhotoColumn::MEDIA_DATE_MODIFIED, localMtime, *resultSet);
1995     if (ret == E_OK) {
1996         struct utimbuf ubuf {
1997             .actime = localMtime / MILLISECOND_TO_SECOND, .modtime = localMtime / MILLISECOND_TO_SECOND
1998         };
1999         LOGI("update downloaded file mtime %{public}llu", static_cast<unsigned long long>(localMtime));
2000         if (utime(localPath.c_str(), &ubuf) < 0) {
2001             LOGE("utime failed return %{public}d, localPath: %{public}s", errno, localPath.c_str());
2002         }
2003     }
2004 
2005     // update rdb
2006     ValuesBucket valuesBucket;
2007     valuesBucket.PutInt(Media::PhotoColumn::PHOTO_POSITION, POSITION_BOTH);
2008 
2009     int32_t changedRows;
2010     string whereClause = Media::PhotoColumn::MEDIA_FILE_PATH + " = ?";
2011     vector<string> whereArgs = {sboxPath};
2012     ret = Update(changedRows, valuesBucket, whereClause, whereArgs);
2013     if (ret != 0) {
2014         LOGE("on download file from cloud err %{public}d", ret);
2015     }
2016     return ret;
2017 }
2018 
AppendToDownload(const DKRecord & record,const std::string & fieldKey,std::vector<DKDownloadAsset> & assetsToDownload)2019 void FileDataHandler::AppendToDownload(const DKRecord &record,
2020                                        const std::string &fieldKey,
2021                                        std::vector<DKDownloadAsset> &assetsToDownload)
2022 {
2023     DKDownloadAsset downloadAsset;
2024     downloadAsset.recordType = record.GetRecordType();
2025     downloadAsset.recordId = record.GetRecordId();
2026     downloadAsset.fieldKey = fieldKey;
2027     DKRecordData data;
2028     record.GetRecordData(data);
2029     if (data.find(FILE_ATTRIBUTES) == data.end()) {
2030         LOGE("record data cannot find attributes");
2031         return;
2032     }
2033     DKRecordFieldMap attributes;
2034     data[FILE_ATTRIBUTES].GetRecordMap(attributes);
2035 
2036     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
2037         LOGE("record prop cannot find file path");
2038         return;
2039     }
2040     string path;
2041     attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(path);
2042     if (fieldKey != "content") {
2043         const string &suffix = fieldKey == "lcd" ? LCD_SUFFIX : THUMB_SUFFIX;
2044         downloadAsset.downLoadPath = createConvertor_.GetThumbPath(path, suffix) + TMP_SUFFIX;
2045     } else {
2046         downloadAsset.downLoadPath = createConvertor_.GetLowerTmpPath(path);
2047     }
2048     downloadAsset.asset.assetName = MetaFile::GetFileName(downloadAsset.downLoadPath);
2049     downloadAsset.downLoadPath = MetaFile::GetParentDir(downloadAsset.downLoadPath);
2050     ForceCreateDirectory(downloadAsset.downLoadPath);
2051     assetsToDownload.push_back(downloadAsset);
2052 }
2053 
UpdateAssetInPhotoMap(const DKRecord & record,int32_t fileId)2054 int32_t FileDataHandler::UpdateAssetInPhotoMap(const DKRecord &record, int32_t fileId)
2055 {
2056     NativeRdb::AbsRdbPredicates updatePredicates = NativeRdb::AbsRdbPredicates(PhotoMap::TABLE);
2057     updatePredicates.EqualTo(PhotoMap::ASSET_ID, to_string(fileId));
2058     auto resultSet = Query(updatePredicates, CLEAN_QUERY_COLUMNS);
2059 
2060     DKRecordData data;
2061     record.GetRecordData(data);
2062     if (data.find(FILE_LOGIC_ALBUM_IDS) == data.end()) {
2063         LOGE("record data cannot find properties");
2064         return E_INVAL_ARG;
2065     }
2066     DKRecordFieldList list;
2067     if (data[FILE_LOGIC_ALBUM_IDS].GetRecordList(list) != DKLocalErrorCode::NO_ERROR) {
2068         LOGE("cannot get album ids from record");
2069         return E_INVAL_ARG;
2070     }
2071 
2072     set<int> cloudMapIds;
2073     for (const auto &it : list) {
2074         DKReference ref;
2075         if (it.GetReference(ref) != DKLocalErrorCode::NO_ERROR) {
2076             LOGE("id list member not a reference");
2077             continue;
2078         }
2079         int albumId = GetAlbumIdFromCloudId(ref.recordId);
2080         if (albumId < 0) {
2081             LOGE("cannot get album id from album name %{public}s, ignore", ref.recordId.c_str());
2082             continue;
2083         }
2084         LOGI("record get albumId %{public}d", albumId);
2085         cloudMapIds.insert(albumId);
2086         QueryAndInsertMap(albumId, fileId);
2087     }
2088 
2089     QueryAndDeleteMap(fileId, cloudMapIds);
2090     return E_OK;
2091 }
2092 
InsertAssetToPhotoMap(const DKRecord & record,OnFetchParams & params)2093 int32_t FileDataHandler::InsertAssetToPhotoMap(const DKRecord &record, OnFetchParams &params)
2094 {
2095     DKRecordData data;
2096     record.GetRecordData(data);
2097     if (data.find(FILE_LOGIC_ALBUM_IDS) == data.end()) {
2098         LOGE("record data cannot find properties");
2099         return E_INVAL_ARG;
2100     }
2101     DKRecordFieldList list;
2102     if (data[FILE_LOGIC_ALBUM_IDS].GetRecordList(list) != DKLocalErrorCode::NO_ERROR) {
2103         LOGE("cannot get album ids from record");
2104         return E_INVAL_ARG;
2105     }
2106 
2107     set<int> cloudMapIds;
2108     for (const auto &it : list) {
2109         DKReference ref;
2110         if (it.GetReference(ref) != DKLocalErrorCode::NO_ERROR) {
2111             LOGE("id list member not a reference");
2112             continue;
2113         }
2114         int albumId = GetAlbumIdFromCloudId(ref.recordId);
2115         if (albumId < 0) {
2116             LOGD("cannot get album id from album name %{public}s, ignore", ref.recordId.c_str());
2117             continue;
2118         }
2119         LOGI("record get albumId %{public}d", albumId);
2120         cloudMapIds.insert(albumId);
2121     }
2122 
2123     params.recordAlbumMaps[record.GetRecordId()] = cloudMapIds;
2124     return E_OK;
2125 }
2126 
BatchInsertAssetMaps(OnFetchParams & params)2127 int32_t FileDataHandler::BatchInsertAssetMaps(OnFetchParams &params)
2128 {
2129     auto recordIds = vector<string>();
2130     for (const auto &it : params.recordAlbumMaps) {
2131         recordIds.push_back(it.first);
2132     }
2133     auto [resultSet, recordIdRowIdMap] = QueryLocalByCloudId(recordIds);
2134     if (resultSet == nullptr) {return E_RDB;}
2135     for (const auto &it : params.recordAlbumMaps) {
2136         if (recordIdRowIdMap.find(it.first) == recordIdRowIdMap.end()) {
2137             continue;
2138         }
2139         resultSet->GoToRow(recordIdRowIdMap.at(it.first));
2140         int fileId = 0;
2141         int ret = DataConvertor::GetInt(MediaColumn::MEDIA_ID, fileId, *resultSet);
2142         if (ret != E_OK) {
2143             LOGE("Get media id failed");
2144             continue;
2145         }
2146 
2147         for (auto albumId : it.second) {
2148             int64_t rowId;
2149             ValuesBucket values;
2150             values.PutInt(PhotoMap::ALBUM_ID, albumId);
2151             values.PutInt(PhotoMap::ASSET_ID, fileId);
2152             values.PutInt(PhotoMap::DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_SYNCED));
2153             ret = Insert(rowId, PhotoMap::TABLE, values);
2154             if (ret != E_OK) {
2155                 LOGE("fail to insert albumId %{public}d - fileId %{public}d mapping, ret %{public}d",
2156                      albumId, fileId, ret);
2157                 continue;
2158             }
2159             LOGI("albumId %{public}d - fileId %{public}d add mapping success", albumId, fileId);
2160         }
2161     }
2162     return E_OK;
2163 }
2164 
GetAlbumIdFromCloudId(const std::string & cloudId)2165 int32_t FileDataHandler::GetAlbumIdFromCloudId(const std::string &cloudId)
2166 {
2167     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoAlbumColumns::TABLE);
2168     predicates.EqualTo(PhotoAlbumColumns::ALBUM_CLOUD_ID, cloudId);
2169     auto resultSet = Query(predicates, {PhotoAlbumColumns::ALBUM_ID});
2170     int rowCount = 0;
2171     int ret = -1;
2172     if (resultSet) {
2173         ret = resultSet->GetRowCount(rowCount);
2174     }
2175     if (resultSet == nullptr || ret != E_OK || rowCount < 0) {
2176         LOGE("get nullptr result or rowcount %{public}d", rowCount);
2177         return -1;
2178     }
2179     if (resultSet->GoToNextRow() == 0) {
2180         int albumId;
2181         ret = DataConvertor::GetInt(PhotoAlbumColumns::ALBUM_ID, albumId, *resultSet);
2182         if (ret == E_OK) {
2183             return albumId;
2184         }
2185     }
2186     LOGD("fail to get ALBUM_ID value");
2187     return -1;
2188 }
2189 
BatchGetFileIdFromCloudId(const std::vector<NativeRdb::ValueObject> & recordIds,std::vector<int> & fileIds)2190 int32_t FileDataHandler::BatchGetFileIdFromCloudId(const std::vector<NativeRdb::ValueObject> &recordIds,
2191     std::vector<int> &fileIds)
2192 {
2193     uint32_t size = 0;
2194     if (recordIds.size() <= BATCH_LIMIT_SIZE) {
2195         size = recordIds.size();
2196     } else {
2197         uint32_t remain = recordIds.size() % BATCH_LIMIT_SIZE;
2198         if (remain == 0) {
2199             size = recordIds.size() - BATCH_LIMIT_SIZE;
2200         } else {
2201             size = recordIds.size() - remain;
2202         }
2203     }
2204 
2205     std::vector<std::string> thmStrVec;
2206     thmStrVec.reserve(size);
2207     for (uint32_t recordIndex = 0; recordIndex < size; recordIndex++) {
2208         std::string cloudId;
2209         int valueErr = recordIds[recordIndex].GetString(cloudId);
2210         if (valueErr == E_OK) {
2211             thmStrVec.push_back(cloudId);
2212         }
2213     }
2214 
2215     return QueryWithBatchCloudId(fileIds, thmStrVec);
2216 }
2217 
QueryWithBatchCloudId(std::vector<int> & fileIds,std::vector<std::string> & thmStrVec)2218 int32_t FileDataHandler::QueryWithBatchCloudId(std::vector<int> &fileIds, std::vector<std::string> &thmStrVec)
2219 {
2220     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoColumn::PHOTOS_TABLE);
2221     predicates.In(PhotoColumn::PHOTO_CLOUD_ID, thmStrVec);
2222     auto resultSet = Query(predicates, {MediaColumn::MEDIA_ID});
2223     int rowCount = 0;
2224     int ret = -1;
2225     if (resultSet) {
2226         ret = resultSet->GetRowCount(rowCount);
2227     }
2228     if (resultSet == nullptr || ret != E_OK || rowCount < 0) {
2229         LOGE("get nullptr result or rowcount %{public}d", rowCount);
2230         return E_RDB;
2231     }
2232 
2233     int err = 0;
2234     err = resultSet->GoToFirstRow();
2235     if (err != E_OK) {
2236         LOGE("get first result of file id fail %{public}d", err);
2237         return E_RDB;
2238     }
2239 
2240     do {
2241         int fileId;
2242         ret = DataConvertor::GetInt(MediaColumn::MEDIA_ID, fileId, *resultSet);
2243         if (ret == E_OK) {
2244             fileIds.push_back(fileId);
2245         }
2246     } while (resultSet->GoToNextRow() == E_OK);
2247 
2248     return E_OK;
2249 }
2250 
QueryAndInsertMap(int32_t albumId,int32_t fileId)2251 void FileDataHandler::QueryAndInsertMap(int32_t albumId, int32_t fileId)
2252 {
2253     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoMap::TABLE);
2254     predicates.EqualTo(PhotoMap::ALBUM_ID, to_string(albumId))->And()->EqualTo(PhotoMap::ASSET_ID, to_string(fileId));
2255     auto resultSet = Query(predicates, {});
2256     int rowCount = 0;
2257     int ret = -1;
2258     if (resultSet) {
2259         ret = resultSet->GetRowCount(rowCount);
2260     }
2261     if (resultSet == nullptr || ret != E_OK || rowCount < 0) {
2262         LOGE("get nullptr result or rowcount %{public}d", rowCount);
2263         return;
2264     }
2265     if (rowCount > 0) {
2266         LOGI("albumId %{public}d - fileId %{public}d already mapped", albumId, fileId);
2267         return;
2268     }
2269 
2270     int64_t rowId;
2271     ValuesBucket values;
2272     values.PutInt(PhotoMap::ALBUM_ID, albumId);
2273     values.PutInt(PhotoMap::ASSET_ID, fileId);
2274     values.PutInt(PhotoMap::DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_SYNCED));
2275     ret = Insert(rowId, PhotoMap::TABLE, values);
2276     if (ret != E_OK) {
2277         LOGE("fail to insert albumId %{public}d - fileId %{public}d mapping, ret %{public}d", albumId, fileId, ret);
2278         return;
2279     }
2280     LOGI("albumId %{public}d - fileId %{public}d add mapping success", albumId, fileId);
2281 }
2282 
QueryAndDeleteMap(int32_t fileId,const set<int> & cloudMapIds)2283 void FileDataHandler::QueryAndDeleteMap(int32_t fileId, const set<int> &cloudMapIds)
2284 {
2285     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoMap::TABLE);
2286     predicates.EqualTo(PhotoMap::ASSET_ID, to_string(fileId));
2287 
2288     auto resultSet = Query(predicates, {});
2289     int rowCount = 0;
2290     int ret = -1;
2291     if (resultSet) {
2292         ret = resultSet->GetRowCount(rowCount);
2293     }
2294     if (resultSet == nullptr || ret != E_OK || rowCount < 0) {
2295         LOGE("get nullptr result or rowcount %{public}d", rowCount);
2296         return;
2297     }
2298     while (resultSet->GoToNextRow() == 0) {
2299         int albumId;
2300         ret = DataConvertor::GetInt(PhotoMap::ALBUM_ID, albumId, *resultSet);
2301         if (ret != E_OK) {
2302             LOGE("fail to get ALBUM_ID value");
2303             continue;
2304         }
2305         int localDirty  = 0;
2306         ret = DataConvertor::GetInt(PhotoMap::DIRTY, localDirty, *resultSet);
2307         if (ret != E_OK) {
2308             LOGE("fail to get Dirty value");
2309             continue;
2310         }
2311 
2312         if (localDirty != static_cast<int32_t>(DirtyTypes::TYPE_SYNCED)) {
2313             LOGI("mapping albumId %{public}d - fileId %{public}d local dirty %{public}d, skip",
2314                 albumId, fileId, localDirty);
2315             continue;
2316         }
2317         if (cloudMapIds.find(albumId) == cloudMapIds.end()) {
2318             LOGE("delete mapping albumId %{public}d - fileId %{public}d", albumId, fileId);
2319             int deletedRows;
2320             ret = Delete(deletedRows, PhotoMap::TABLE, PhotoMap::ASSET_ID + " = ? AND " + PhotoMap::ALBUM_ID + " = ?",
2321                          {to_string(fileId), to_string(albumId)});
2322             if (ret != E_OK) {
2323                 LOGE("delete mapping failed %{public}d", ret);
2324                 continue;
2325             }
2326         }
2327     }
2328 }
2329 
DeleteAssetInPhotoMap(int32_t fileId)2330 int32_t FileDataHandler::DeleteAssetInPhotoMap(int32_t fileId)
2331 {
2332     if (fileId <= 0) {
2333         return E_INVAL_ARG;
2334     }
2335 
2336     int32_t deletedRows;
2337     int ret = Delete(deletedRows, PhotoMap::TABLE, PhotoMap::ASSET_ID + " = ?", {to_string(fileId)});
2338     if (ret != E_OK) {
2339         LOGE("delete in rdb failed, ret: %{public}d", ret);
2340         return E_RDB;
2341     }
2342     return E_OK;
2343 }
2344 
DeleteDentryFile(void)2345 int32_t FileDataHandler::DeleteDentryFile(void)
2346 {
2347     std::string cacheDir =
2348         "/data/service/el2/" + std::to_string(userId_) + "/hmdfs/cache/account_cache/dentry_cache/cloud/";
2349     LOGD("cacheDir: %s", cacheDir.c_str());
2350     ForceRemoveDirectory(cacheDir);
2351     MetaFileMgr::GetInstance().ClearAll();
2352     return E_OK;
2353 }
2354 
ClearCloudInfo(const string & cloudId)2355 int32_t FileDataHandler::ClearCloudInfo(const string &cloudId)
2356 {
2357     ValuesBucket values;
2358     values.PutNull(PhotoColumn::PHOTO_CLOUD_ID);
2359     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_NEW));
2360     values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_LOCAL);
2361     values.PutLong(PhotoColumn::PHOTO_CLOUD_VERSION, 0);
2362     int32_t updateRows = 0;
2363     std::string whereClause = PhotoColumn::PHOTO_CLOUD_ID + " = ?";
2364     int ret = Update(updateRows, values, whereClause, {cloudId});
2365     if (ret != E_OK) {
2366         LOGE("Update in rdb failed, ret:%{public}d", ret);
2367     }
2368     return ret;
2369 }
2370 
DeleteAsset(const string & assetPath)2371 static int32_t DeleteAsset(const string &assetPath)
2372 {
2373     int ret = E_OK;
2374     if (access(assetPath.c_str(), F_OK) == 0) {
2375         LOGD("assetPath exist");
2376         ret = remove(assetPath.c_str());
2377         if (ret != 0) {
2378             LOGE("Clean remove assetPath failed, errno %{public}d", errno);
2379             return errno;
2380         }
2381     }
2382     return ret;
2383 }
2384 
Clean(const int action)2385 int32_t FileDataHandler::Clean(const int action)
2386 {
2387     std::lock_guard<std::mutex> lck(cleanMutex_);
2388     RETURN_ON_ERR(CleanPureCloudRecord());
2389     int32_t res = DeleteDentryFile();
2390     if (res != E_OK) {
2391         LOGE("Clean remove dentry failed, res:%{public}d", res);
2392         return res;
2393     }
2394     UpdateAllAlbums();
2395     DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX, ChangeType::INSERT,
2396                                               INVALID_ASSET_ID);
2397     DataSyncNotifier::GetInstance().FinalNotify();
2398 
2399     return E_OK;
2400 }
2401 
CleanPureCloudRecord(bool isReamin)2402 int32_t FileDataHandler::CleanPureCloudRecord(bool isReamin)
2403 {
2404     LOGI("begin clean pure cloud record");
2405     int32_t ret = E_OK;
2406     NativeRdb::AbsRdbPredicates cleanPredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2407     cleanPredicates.EqualTo(PhotoColumn::PHOTO_POSITION, POSITION_CLOUD);
2408     cleanPredicates.EqualTo(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_SYNCED));
2409     if (isReamin) {
2410         cleanPredicates.EqualTo(PhotoColumn::PHOTO_CLEAN_FLAG, NEED_CLEAN);
2411     }
2412     cleanPredicates.Limit(BATCH_LIMIT_SIZE);
2413     vector<ValueObject> deleteFileId;
2414     shared_ptr<vector<string>> filePaths = make_shared<vector<string>>();
2415     int32_t removeCount = 0;
2416     do {
2417         deleteFileId.clear();
2418         filePaths->clear();
2419         GetFilePathAndId(cleanPredicates, deleteFileId, *filePaths);
2420         RemoveCloudRecord(filePaths);
2421         ret = BatchDetete(PC::PHOTOS_TABLE, MediaColumn::MEDIA_ID, deleteFileId);
2422         ret = BatchDetete(PhotoMap::TABLE, PhotoMap::ASSET_ID, deleteFileId);
2423         if (ret != E_OK) {
2424             LOGW("BatchDetete fail, remove count is %{public}d", removeCount);
2425             return ret;
2426         }
2427         removeCount += deleteFileId.size();
2428     } while (deleteFileId.size() != 0);
2429     LOGI("end clean pure cloud record, remove count is %{public}d", removeCount);
2430     return ret;
2431 }
2432 
CleanNotPureCloudRecord(const int32_t action)2433 int32_t FileDataHandler::CleanNotPureCloudRecord(const int32_t action)
2434 {
2435     int32_t ret = E_OK;
2436     LOGD("Clean not Pure CloudRecord");
2437     if (action == CleanAction::CLEAR_DATA) {
2438         ret = CleanNotDirtyData();
2439     }
2440     ret = CleanAllCloudInfo();
2441     return ret;
2442 }
2443 
CleanRemainRecord()2444 int32_t FileDataHandler::CleanRemainRecord()
2445 {
2446     if (!IsPullRecords()) {
2447         std::lock_guard<std::mutex> lck(cleanMutex_);
2448         int32_t ret = CleanPureCloudRecord(true);
2449         if (ret != E_OK) {
2450             LOGW("clean pure cloud record fail, try next time");
2451         }
2452         ret = CleanNotDirtyData(true);
2453         if (ret != E_OK) {
2454             LOGW("Clean not dirty data fail, try next time");
2455         }
2456     }
2457     return E_OK;
2458 }
2459 
CleanNotDirtyData(bool isReamin)2460 int32_t FileDataHandler::CleanNotDirtyData(bool isReamin)
2461 {
2462     LOGI("begin clean not dirty data");
2463     int32_t ret = E_OK;
2464     NativeRdb::AbsRdbPredicates cleanPredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2465     cleanPredicates.EqualTo(PhotoColumn::PHOTO_POSITION, POSITION_BOTH);
2466     cleanPredicates.EqualTo(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_SYNCED));
2467     if (isReamin) {
2468         cleanPredicates.EqualTo(PhotoColumn::PHOTO_CLEAN_FLAG, NEED_CLEAN);
2469     }
2470     cleanPredicates.Limit(BATCH_LIMIT_SIZE);
2471     vector<ValueObject> deleteFileId;
2472     shared_ptr<vector<string>> filePaths = make_shared<vector<string>>();
2473     int32_t removeCount = 0;
2474     do {
2475         deleteFileId.clear();
2476         filePaths->clear();
2477         GetFilePathAndId(cleanPredicates, deleteFileId, *filePaths);
2478         RemoveBothRecord(filePaths);
2479         ret = BatchDetete(PC::PHOTOS_TABLE, MediaColumn::MEDIA_ID, deleteFileId);
2480         ret = BatchDetete(PhotoMap::TABLE, PhotoMap::ASSET_ID, deleteFileId);
2481         if (ret != E_OK) {
2482             LOGW("BatchDetete fail, remove count is %{public}d", removeCount);
2483             return ret;
2484         }
2485         removeCount += deleteFileId.size();
2486     } while (deleteFileId.size() != 0);
2487     LOGI("end clean not dirty data, remove count is %{public}d", removeCount);
2488     return ret;
2489 }
2490 
CleanAllCloudInfo()2491 int32_t FileDataHandler::CleanAllCloudInfo()
2492 {
2493     LOGD("Clean Pure CloudRecord");
2494     ValuesBucket values;
2495     values.PutNull(PhotoColumn::PHOTO_CLOUD_ID);
2496     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_NEW));
2497     values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_LOCAL);
2498     values.PutLong(PhotoColumn::PHOTO_CLOUD_VERSION, 0);
2499     int32_t updateRows = 0;
2500     std::string whereClause = PhotoColumn::PHOTO_POSITION + " = ?";
2501     vector<string> whereArgs = {to_string(POSITION_BOTH)};
2502     int32_t ret = Update(updateRows, values, whereClause, whereArgs);
2503     if (ret != E_OK) {
2504         LOGE("Update in rdb failed, ret:%{public}d", ret);
2505     }
2506     return ret;
2507 }
2508 
GetFilePathAndId(NativeRdb::AbsRdbPredicates cleanPredicates,vector<ValueObject> & deleteFileId,vector<string> & filePaths)2509 int32_t FileDataHandler::GetFilePathAndId(NativeRdb::AbsRdbPredicates cleanPredicates,
2510                                           vector<ValueObject> &deleteFileId,
2511                                           vector<string> &filePaths)
2512 {
2513     int32_t count = 0;
2514     auto result = Query(cleanPredicates, {MediaColumn::MEDIA_ID, PC::MEDIA_FILE_PATH});
2515     if (result == nullptr) {
2516         LOGE("get result fail");
2517         return E_RDB;
2518     }
2519     int32_t ret = result->GetRowCount(count);
2520     if (ret != E_OK || count < 0) {
2521         LOGE("get row count error , ret: %{public}d", ret);
2522         return E_RDB;
2523     }
2524     while (result->GoToNextRow() == 0) {
2525         string filePath;
2526         string fileId;
2527         ret = DataConvertor::GetString(PC::MEDIA_ID, fileId, *result);
2528         ret = DataConvertor::GetString(PC::MEDIA_FILE_PATH, filePath, *result);
2529         if (ret != E_OK) {
2530             LOGE("Get path wrong");
2531             return E_INVAL_ARG;
2532         }
2533         filePaths.emplace_back(filePath);
2534         deleteFileId.emplace_back(fileId);
2535     }
2536     return E_OK;
2537 }
2538 
RemoveCloudRecord(shared_ptr<vector<string>> filePaths)2539 void FileDataHandler::RemoveCloudRecord(shared_ptr<vector<string>> filePaths)
2540 {
2541     for (auto &filePath : *filePaths) {
2542         RemoveThmParentPath(filePath);
2543     }
2544     LOGI("remove count is %{public}zu", filePaths->size());
2545 }
2546 
RemoveBothRecord(shared_ptr<vector<string>> filePaths)2547 void FileDataHandler::RemoveBothRecord(shared_ptr<vector<string>> filePaths)
2548 {
2549     for (auto &filePath : *filePaths) {
2550         RemoveThmParentPath(filePath);
2551         string lowerPath = cleanConvertor_.GetLowerPath(filePath);
2552         string thmbFileParentPath = cleanConvertor_.GetThumbParentPath(filePath);
2553         ForceRemoveDirectory(thmbFileParentPath);
2554         DeleteAsset(lowerPath);
2555     }
2556     LOGI("remove count is %{public}zu", filePaths->size());
2557 }
2558 
MarkClean(const int32_t action)2559 int32_t FileDataHandler::MarkClean(const int32_t action)
2560 {
2561     cloudPrefImpl_.SetInt("cleanAction", action);
2562     int32_t changedRows;
2563     NativeRdb::ValuesBucket values;
2564     values.PutInt(PC::PHOTO_CLEAN_FLAG, NEED_CLEAN);
2565     values.PutInt(PC::PHOTO_DIRTY, static_cast<int32_t>(DirtyType::TYPE_SYNCED));
2566     string whereClause = PC::PHOTO_POSITION + " = ?";
2567     vector<string> whereArgs = {to_string(static_cast<int32_t>(POSITION_CLOUD))};
2568     if (action == CleanAction::CLEAR_DATA) {
2569         whereClause += " OR ( " + PC::PHOTO_POSITION + " = ? AND " + PC::PHOTO_DIRTY + " = ? )";
2570         whereArgs.push_back(to_string(static_cast<int32_t>(POSITION_BOTH)));
2571         whereArgs.push_back(to_string(static_cast<int32_t>(DirtyType::TYPE_SYNCED)));
2572     }
2573     int32_t ret =
2574         Update(changedRows, PC::PHOTOS_TABLE, values, whereClause, whereArgs);
2575     if (ret != E_OK) {
2576         LOGW("mark clean error %{public}d", ret);
2577     }
2578     UpdateAllAlbums();
2579     DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX, ChangeType::INSERT,
2580                                               INVALID_ASSET_ID);
2581     DataSyncNotifier::GetInstance().FinalNotify();
2582     RETURN_ON_ERR(CleanNotPureCloudRecord(action));
2583     return ret;
2584 }
2585 
HandleCreateConvertErr(int32_t err,NativeRdb::ResultSet & resultSet)2586 void FileDataHandler::HandleCreateConvertErr(int32_t err, NativeRdb::ResultSet &resultSet)
2587 {
2588     string path;
2589     int32_t ret = createConvertor_.GetString(PC::MEDIA_FILE_PATH, path, resultSet);
2590     if (ret != E_OK) {
2591         LOGE("get path err");
2592         return;
2593     }
2594     createFailSet_.push_back(path);
2595 }
2596 
HandleFdirtyConvertErr(int32_t err,NativeRdb::ResultSet & resultSet)2597 void FileDataHandler::HandleFdirtyConvertErr(int32_t err, NativeRdb::ResultSet &resultSet)
2598 {
2599     string cloudId;
2600     int32_t ret = createConvertor_.GetString(PC::PHOTO_CLOUD_ID, cloudId, resultSet);
2601     if (ret != E_OK) {
2602         LOGE("get cloud id err");
2603         return;
2604     }
2605     if (err == E_PATH) {
2606         retrySet_.push_back(cloudId);
2607     }
2608     modifyFailSet_.push_back(cloudId);
2609 }
2610 
GetCreatedRecords(vector<DKRecord> & records)2611 int32_t FileDataHandler::GetCreatedRecords(vector<DKRecord> &records)
2612 {
2613     while (records.size() == 0) {
2614         /* build predicates */
2615         NativeRdb::AbsRdbPredicates createPredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2616         createPredicates
2617             .EqualTo(Media::PhotoColumn::PHOTO_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_NEW)))
2618             ->And()->EqualTo(Media::PhotoColumn::MEDIA_DATE_TRASHED, "0")
2619             ->BeginWrap()
2620             ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_IMAGE))
2621             ->Or()
2622             ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_VIDEO))
2623             ->EndWrap();
2624         if (!createFailSet_.empty()) {
2625             createPredicates.And()->NotIn(Media::PhotoColumn::MEDIA_FILE_PATH, createFailSet_);
2626         }
2627         /* small-size first */
2628         createPredicates.OrderByAsc(Media::PhotoColumn::MEDIA_SIZE);
2629         createPredicates.Limit(LIMIT_SIZE);
2630         /* query */
2631         auto results = Query(createPredicates, MEDIA_CLOUD_SYNC_COLUMNS);
2632         if (results == nullptr) {
2633             LOGE("get nullptr created result");
2634             return E_RDB;
2635         }
2636         /* results to records */
2637         int32_t ret = createConvertor_.ResultSetToRecords(move(results), records);
2638         if (ret != E_OK) {
2639             if (ret == E_STOP) {
2640                 return E_OK;
2641             }
2642             LOGE("result set to records err %{public}d", ret);
2643             return ret;
2644         }
2645     }
2646 
2647     /* bind album */
2648     int32_t ret = BindAlbums(records);
2649     if (ret != E_OK) {
2650         LOGE("bind albums err %{public}d", ret);
2651         return ret;
2652     }
2653 
2654     /* erase local info */
2655     ret = EraseLocalInfo(records);
2656     if (ret != 0) {
2657         LOGE("erase local info err %{public}d", ret);
2658         return ret;
2659     }
2660 
2661     return E_OK;
2662 }
2663 
GetDeletedRecords(vector<DKRecord> & records)2664 int32_t FileDataHandler::GetDeletedRecords(vector<DKRecord> &records)
2665 {
2666     /* build predicates */
2667     NativeRdb::AbsRdbPredicates deletePredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2668     deletePredicates
2669         .EqualTo(Media::PhotoColumn::PHOTO_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_DELETED)))
2670         ->BeginWrap()
2671         ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_IMAGE))
2672         ->Or()
2673         ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_VIDEO))
2674         ->EndWrap();
2675     if (!modifyFailSet_.empty()) {
2676         deletePredicates.And()->NotIn(Media::PhotoColumn::PHOTO_CLOUD_ID, modifyFailSet_);
2677     }
2678     deletePredicates.Limit(DELETE_BATCH_NUM);
2679 
2680     /* query */
2681     auto results = Query(deletePredicates, MEDIA_CLOUD_SYNC_COLUMNS);
2682     if (results == nullptr) {
2683         LOGE("get nullptr deleted result");
2684         return E_RDB;
2685     }
2686 
2687     /* results to records */
2688     int ret = deleteConvertor_.ResultSetToRecords(move(results), records);
2689     if (ret != 0) {
2690         LOGE("result set to records err %{public}d", ret);
2691         return ret;
2692     }
2693 
2694     return E_OK;
2695 }
2696 
GetMetaModifiedRecords(vector<DKRecord> & records)2697 int32_t FileDataHandler::GetMetaModifiedRecords(vector<DKRecord> &records)
2698 {
2699     /* build predicates */
2700     NativeRdb::AbsRdbPredicates updatePredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2701     updatePredicates
2702         .EqualTo(Media::PhotoColumn::PHOTO_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY)))
2703         ->BeginWrap()
2704         ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_IMAGE))
2705         ->Or()
2706         ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_VIDEO))
2707         ->EndWrap();
2708     if (!modifyFailSet_.empty()) {
2709         updatePredicates.And()->NotIn(Media::PhotoColumn::PHOTO_CLOUD_ID, modifyFailSet_);
2710     }
2711     updatePredicates.Limit(MODIFY_BATCH_NUM);
2712 
2713     /* query */
2714     auto results = Query(updatePredicates, MEDIA_CLOUD_SYNC_COLUMNS);
2715     if (results == nullptr) {
2716         LOGE("get nullptr modified result");
2717         return E_RDB;
2718     }
2719 
2720     /* results to records */
2721     int ret = mdirtyConvertor_.ResultSetToRecords(move(results), records);
2722     if (ret != 0) {
2723         LOGE("result set to records err %{public}d", ret);
2724         return ret;
2725     }
2726 
2727     /* album map change */
2728     ret = BindAlbumChanges(records);
2729     if (ret != E_OK) {
2730         LOGE("update album map change err %{public}d", ret);
2731         return ret;
2732     }
2733 
2734     /* erase local info */
2735     ret = EraseLocalInfo(records);
2736     if (ret != 0) {
2737         LOGE("erase local info err %{public}d", ret);
2738         return ret;
2739     }
2740 
2741     return E_OK;
2742 }
2743 
GetFileIdFromRecord(DKRecord & record,int32_t & fileId)2744 static inline int32_t GetFileIdFromRecord(DKRecord &record, int32_t &fileId)
2745 {
2746     DKRecordData data;
2747     record.GetRecordData(data);
2748     if (data.find(FILE_ATTRIBUTES) == data.end()) {
2749         LOGE("file attributes is no exit");
2750         return E_INVAL_ARG;
2751     }
2752     DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
2753     if (attributes.find(Media::MediaColumn::MEDIA_ID) == attributes.end()) {
2754         LOGE("media id is no exit");
2755         return E_INVAL_ARG;
2756     }
2757     fileId = attributes[Media::MediaColumn::MEDIA_ID];
2758     return E_OK;
2759 }
2760 
InsertAlbumIds(DKRecord & record,vector<string> & cloudIds)2761 static inline void InsertAlbumIds(DKRecord &record, vector<string> &cloudIds)
2762 {
2763     DKRecordData data;
2764     DKRecordFieldList list;
2765     record.StealRecordData(data);
2766     for (auto &id : cloudIds) {
2767         list.push_back(DKRecordField(DKReference{ id, "album" }));
2768     }
2769     data[FILE_LOGIC_ALBUM_IDS] = DKRecordField(list);
2770     record.SetRecordData(data);
2771 }
2772 
InsertAlbumIdChanges(DKRecord & record,vector<string> & add,vector<string> & rm)2773 static inline void InsertAlbumIdChanges(DKRecord &record, vector<string> &add, vector<string> &rm)
2774 {
2775     DKRecordData data;
2776     record.StealRecordData(data);
2777     /* add */
2778     DKRecordFieldList addList;
2779     for (auto &id : add) {
2780         addList.push_back(DKRecordField(DKReference{ id, "album" }));
2781     }
2782     data[FILE_ADD_LOGIC_ALBUM_IDS] = DKRecordField(addList);
2783     /* remove */
2784     DKRecordFieldList rmList;
2785     for (auto &id : rm) {
2786         rmList.push_back(DKRecordField(DKReference{ id, "album" }));
2787     }
2788     data[FILE_RM_LOGIC_ALBUM_IDS] = DKRecordField(rmList);
2789     record.SetRecordData(data);
2790 }
2791 
2792 /* need optimization: IN or JOIN */
GetAlbumCloudIds(vector<int32_t> & localIds,vector<string> & cloudIds)2793 int32_t FileDataHandler::GetAlbumCloudIds(vector<int32_t> &localIds, vector<string> &cloudIds)
2794 {
2795     for (auto localId : localIds) {
2796         NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PAC::TABLE);
2797         predicates.EqualTo(PAC::ALBUM_ID, to_string(localId));
2798         /* query map */
2799         auto results = Query(predicates, {});
2800         if (results == nullptr) {
2801             LOGE("get nullptr result");
2802             return E_RDB;
2803         }
2804         if (results->GoToNextRow() != NativeRdb::E_OK) {
2805             LOGE("failed to go to next row");
2806             return E_RDB;
2807         }
2808         string cloudId;
2809         int32_t ret = createConvertor_.GetString(PAC::ALBUM_CLOUD_ID, cloudId, *results);
2810         if (ret != E_OK) {
2811             return ret;
2812         }
2813         if (!cloudId.empty()) {
2814             cloudIds.push_back(cloudId);
2815         }
2816     }
2817     return E_OK;
2818 }
2819 
GetAlbumIdsFromResultSet(const shared_ptr<NativeRdb::ResultSet> resultSet,vector<int32_t> & ids)2820 int32_t FileDataHandler::GetAlbumIdsFromResultSet(const shared_ptr<NativeRdb::ResultSet> resultSet,
2821     vector<int32_t> &ids)
2822 {
2823     while (resultSet->GoToNextRow() == 0) {
2824         int32_t id;
2825         int32_t ret = createConvertor_.GetInt(PM::ALBUM_ID, id, *resultSet);
2826         if (ret != E_OK) {
2827             return ret;
2828         }
2829         ids.push_back(id);
2830     }
2831     return E_OK;
2832 }
2833 
BindAlbums(std::vector<DriveKit::DKRecord> & records)2834 int32_t FileDataHandler::BindAlbums(std::vector<DriveKit::DKRecord> &records)
2835 {
2836     for (auto &record : records) {
2837         NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PM::TABLE);
2838         /* map exceed limit? */
2839         int32_t fileId;
2840         int32_t ret = GetFileIdFromRecord(record, fileId);
2841         if (ret != E_OK) {
2842             continue;
2843         }
2844         predicates.EqualTo(PM::ASSET_ID, to_string(fileId));
2845         /* query map */
2846         auto results = Query(predicates, {});
2847         if (results == nullptr) {
2848             LOGE("get nullptr result");
2849             return E_RDB;
2850         }
2851         vector<int32_t> albumIds;
2852         ret = GetAlbumIdsFromResultSet(results, albumIds);
2853         if (ret != E_OK) {
2854             LOGE("get album ids from result set err %{public}d", ret);
2855             return ret;
2856         }
2857         /* query album */
2858         vector<string> cloudIds;
2859         ret = GetAlbumCloudIds(albumIds, cloudIds);
2860         if (ret != E_OK) {
2861             LOGE("get album cloud id err %{public}d", ret);
2862             return ret;
2863         }
2864         /* insert album ids */
2865         InsertAlbumIds(record, cloudIds);
2866     }
2867     return E_OK;
2868 }
2869 
GetAlbumIdsFromResultSet(const shared_ptr<NativeRdb::ResultSet> resultSet,vector<int32_t> & add,vector<int32_t> & rm)2870 int32_t FileDataHandler::GetAlbumIdsFromResultSet(const shared_ptr<NativeRdb::ResultSet> resultSet,
2871     vector<int32_t> &add, vector<int32_t> &rm)
2872 {
2873     while (resultSet->GoToNextRow() == 0) {
2874         int32_t id;
2875         int32_t ret = createConvertor_.GetInt(PM::ALBUM_ID, id, *resultSet);
2876         if (ret != E_OK) {
2877             return ret;
2878         }
2879         int32_t state;
2880         ret = createConvertor_.GetInt(PM::DIRTY, state, *resultSet);
2881         if (ret != E_OK) {
2882             return ret;
2883         }
2884         if (state == static_cast<int32_t>(Media::DirtyType::TYPE_NEW)) {
2885             add.push_back(id);
2886         } else if (state == static_cast<int32_t>(Media::DirtyType::TYPE_DELETED)) {
2887             rm.push_back(id);
2888         }
2889     }
2890     return E_OK;
2891 }
2892 
BindAlbumChanges(std::vector<DriveKit::DKRecord> & records)2893 int32_t FileDataHandler::BindAlbumChanges(std::vector<DriveKit::DKRecord> &records)
2894 {
2895     for (auto &record : records) {
2896         NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PM::TABLE);
2897         /* map exceed limit? */
2898         int32_t fileId;
2899         int32_t ret = GetFileIdFromRecord(record, fileId);
2900         if (ret != E_OK) {
2901             continue;
2902         }
2903         predicates.EqualTo(PM::ASSET_ID, to_string(fileId))
2904             ->And()
2905             ->NotEqualTo(PM::DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED)));
2906         /* query map */
2907         auto results = Query(predicates, {});
2908         if (results == nullptr) {
2909             LOGE("get nullptr result");
2910             return E_RDB;
2911         }
2912         /* new or delete */
2913         vector<int32_t> add, remove;
2914         ret = GetAlbumIdsFromResultSet(results, add, remove);
2915         if (ret != E_OK) {
2916             LOGE("get album ids from result set err %{public}d", ret);
2917             return ret;
2918         }
2919         /* query album */
2920         vector<string> addCloud, removeCloud;
2921         ret = GetAlbumCloudIds(add, addCloud);
2922         if (ret != E_OK) {
2923             LOGE("get album cloud id err %{public}d", ret);
2924             return ret;
2925         }
2926         ret = GetAlbumCloudIds(remove, removeCloud);
2927         if (ret != E_OK) {
2928             LOGE("get album cloud id err %{public}d", ret);
2929             return ret;
2930         }
2931         /* update */
2932         InsertAlbumIdChanges(record, addCloud, removeCloud);
2933     }
2934     return E_OK;
2935 }
2936 
GetDownloadAsset(std::string cloudId,vector<DriveKit::DKDownloadAsset> & outAssetsToDownload)2937 int32_t FileDataHandler::GetDownloadAsset(std::string cloudId, vector<DriveKit::DKDownloadAsset> &outAssetsToDownload)
2938 {
2939     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2940     predicates.SetWhereClause(Media::PhotoColumn::MEDIA_FILE_PATH + " = ?");
2941     predicates.SetWhereArgs({cloudId});
2942     predicates.Limit(LIMIT_SIZE);
2943     auto resultSet = Query(predicates, {PC::PHOTO_CLOUD_ID, PC::MEDIA_FILE_PATH});
2944     if (resultSet == nullptr) {
2945         LOGE("get nullptr created result");
2946         return E_RDB;
2947     }
2948     int32_t rowCount = 0;
2949     int32_t ret = resultSet->GetRowCount(rowCount);
2950     if (ret != 0) {
2951         LOGE("result set get row count err %{public}d", ret);
2952         return E_RDB;
2953     }
2954     while (resultSet->GoToNextRow() == 0) {
2955         DKRecord record;
2956         localConvertor_.ConvertAsset(record, *resultSet);
2957         if (record.GetRecordId().empty()) {
2958             continue;
2959         }
2960         AppendToDownload(record, "content", outAssetsToDownload);
2961     }
2962     return E_OK;
2963 }
GetFileModifiedRecords(vector<DKRecord> & records)2964 int32_t FileDataHandler::GetFileModifiedRecords(vector<DKRecord> &records)
2965 {
2966     while (records.size() == 0) {
2967         /* build predicates */
2968         NativeRdb::AbsRdbPredicates updatePredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
2969         updatePredicates
2970             .EqualTo(Media::PhotoColumn::PHOTO_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_FDIRTY)))
2971             ->And()
2972             ->BeginWrap()
2973             ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_IMAGE))
2974             ->Or()
2975             ->EqualTo(Media::PhotoColumn::MEDIA_TYPE, to_string(Media::MEDIA_TYPE_VIDEO))
2976             ->EndWrap();
2977         if (!modifyFailSet_.empty()) {
2978             updatePredicates.And()->NotIn(Media::PhotoColumn::PHOTO_CLOUD_ID, modifyFailSet_);
2979         }
2980         updatePredicates.OrderByAsc(Media::PhotoColumn::MEDIA_SIZE);
2981         updatePredicates.Limit(LIMIT_SIZE);
2982         /* query */
2983         auto results = Query(updatePredicates, MEDIA_CLOUD_SYNC_COLUMNS);
2984         if (results == nullptr) {
2985             LOGE("get nullptr modified result");
2986             return E_RDB;
2987         }
2988         /* results to records */
2989         int32_t ret = fdirtyConvertor_.ResultSetToRecords(move(results), records);
2990         if (ret != E_OK) {
2991             if (ret == E_STOP) {
2992                 return E_OK;
2993             }
2994             LOGE("result set to records err %{public}d", ret);
2995             return ret;
2996         }
2997         SetRetry(retrySet_);
2998     }
2999 
3000     /* album map change */
3001     int32_t ret = BindAlbumChanges(records);
3002     if (ret != E_OK) {
3003         LOGE("update album map change err %{public}d", ret);
3004         return ret;
3005     }
3006 
3007     /* erase local info */
3008     ret = EraseLocalInfo(records);
3009     if (ret != E_OK) {
3010         LOGE("erase local info err %{public}d", ret);
3011         return ret;
3012     }
3013 
3014     return E_OK;
3015 }
3016 
EraseLocalInfo(vector<DriveKit::DKRecord> & records)3017 int32_t FileDataHandler::EraseLocalInfo(vector<DriveKit::DKRecord> &records)
3018 {
3019     for (auto &record : records) {
3020         DKRecordData data;
3021         record.GetRecordData(data);
3022         DKRecordFieldMap attributes;
3023         data[FILE_ATTRIBUTES].GetRecordMap(attributes);
3024         attributes.erase(Media::MediaColumn::MEDIA_ID);
3025         attributes.erase(Media::PhotoColumn::PHOTO_CLOUD_ID);
3026         data[FILE_ATTRIBUTES] = DKRecordField(attributes);
3027         record.SetRecordData(data);
3028     }
3029     return E_OK;
3030 }
3031 
GetFilePathFromRecord(const DKRecord & record)3032 static string GetFilePathFromRecord(const DKRecord &record)
3033 {
3034     DKRecordData data;
3035     record.GetRecordData(data);
3036     if (data.find(FILE_ATTRIBUTES) == data.end()) {
3037         LOGE("record data cannot find attributes");
3038         return "";
3039     }
3040     DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
3041     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
3042         LOGE("record data cannot find file path");
3043         return "";
3044     }
3045     string path;
3046     if (attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(path) != DKLocalErrorCode::NO_ERROR) {
3047         LOGE("bad file_path in props");
3048         return "";
3049     }
3050     return path;
3051 }
3052 
UpdateMediaFilePath(DriveKit::DKRecord & record,NativeRdb::ResultSet & local)3053 int32_t FileDataHandler::UpdateMediaFilePath(DriveKit::DKRecord &record, NativeRdb::ResultSet &local)
3054 {
3055     string newFileName = "";
3056     string relativePath = "";
3057     DKRecordData data;
3058     record.GetRecordData(data);
3059     string filePath = GetFilePathFromRecord(record);
3060     if (filePath.empty()) {
3061         return E_INVAL_ARG;
3062     }
3063     if (GetDentryPathName(filePath, relativePath, newFileName) != E_OK) {
3064         LOGE("split filePath to dentry path failed, path:%s", filePath.c_str());
3065         return E_INVAL_ARG;
3066     }
3067     string newThumbParentPath = createConvertor_.GetThumbParentPath(filePath);
3068     bool isDataChanged = access(newThumbParentPath.c_str(), F_OK) == 0;
3069     if (!isDataChanged) {
3070         LOGI("media file path change");
3071         string oldFilePath = "";
3072         string oldFileName = "";
3073         int32_t ret = DataConvertor::GetString(PC::MEDIA_FILE_PATH, oldFilePath, local);
3074         if (ret != E_OK) {
3075             return ret;
3076         }
3077         if (GetDentryPathName(oldFilePath, relativePath, oldFileName) != E_OK) {
3078             LOGE("split old filePath to dentry path failed, path:%s", oldFilePath.c_str());
3079             return E_INVAL_ARG;
3080         }
3081         LOGI("update media file path, old path is %{public}s, new path is %{public}s",
3082             oldFilePath.c_str(), filePath.c_str());
3083         auto mFile = MetaFileMgr::GetInstance().GetMetaFile(userId_, relativePath);
3084         MetaBase mBase(oldFileName);
3085         ret = mFile->DoRename(mBase, newFileName);
3086         if (ret != E_OK) {
3087             LOGE("rename dentry failed, ret:%{public}d", ret);
3088         }
3089         string oldThumbParentPath = createConvertor_.GetThumbParentPath(oldFilePath);
3090         ret = rename(oldThumbParentPath.c_str(), newThumbParentPath.c_str());
3091         if (ret != E_OK) {
3092             MetaBase mBase(newFileName);
3093             ret = mFile->DoRename(mBase, oldFileName);
3094             LOGE("rename thmbPath faill, errno is %{public}d, restore dentry file ret is %{public}d", errno, ret);
3095             return E_RENAME_FAIL;
3096         }
3097     }
3098     return E_OK;
3099 }
3100 
OnCreateRecords(const map<DKRecordId,DKRecordOperResult> & map)3101 int32_t FileDataHandler::OnCreateRecords(const map<DKRecordId, DKRecordOperResult> &map)
3102 {
3103     unordered_map<string, LocalInfo> localMap;
3104     uint64_t success = 0;
3105     uint64_t failure = 0;
3106 
3107     int32_t ret = GetLocalInfo(map, localMap, Media::PhotoColumn::MEDIA_FILE_PATH);
3108     if (ret != E_OK) {
3109         LOGE("get local match info err %{public}d", ret);
3110         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, map.size());
3111         return ret;
3112     }
3113 
3114     for (auto &entry : map) {
3115         int32_t err;
3116         const DKRecordOperResult &result = entry.second;
3117         if (result.IsSuccess()) {
3118             err = OnCreateRecordSuccess(entry, localMap);
3119         } else {
3120             err = OnRecordFailed(entry);
3121             failure++;
3122         }
3123         if (err != E_OK) {
3124             string filePath = GetFilePathFromRecord(entry.second.GetDKRecord());
3125             if (!filePath.empty()) {
3126                 createFailSet_.push_back(filePath);
3127             }
3128             LOGE("create record fail: file path %{private}s", filePath.c_str());
3129         } else {
3130             success++;
3131         }
3132         GetReturn(err, ret);
3133     }
3134     (void)DataSyncNotifier::GetInstance().FinalNotify();
3135 
3136     UpdateMetaStat(INDEX_UL_META_ERROR_SDK, failure);
3137     UpdateMetaStat(INDEX_UL_META_SUCCESS, success);
3138 
3139     return ret;
3140 }
3141 
OnDeleteRecords(const map<DKRecordId,DKRecordOperResult> & map)3142 int32_t FileDataHandler::OnDeleteRecords(const map<DKRecordId, DKRecordOperResult> &map)
3143 {
3144     uint64_t success = 0;
3145     uint64_t failure = 0;
3146     int32_t ret = E_OK;
3147 
3148     for (auto &entry : map) {
3149         const DKRecordOperResult &result = entry.second;
3150         int32_t err;
3151         if (result.IsSuccess()) {
3152             err = OnDeleteRecordSuccess(entry);
3153         } else {
3154             err = OnRecordFailed(entry);
3155             failure++;
3156         }
3157         if (err != E_OK) {
3158             modifyFailSet_.push_back(entry.first);
3159             LOGE("delete record fail: cloud id: %{private}s", entry.first.c_str());
3160         } else {
3161             success++;
3162         }
3163         GetReturn(err, ret);
3164     }
3165 
3166     UpdateMetaStat(INDEX_UL_META_ERROR_SDK, failure);
3167     UpdateMetaStat(INDEX_UL_META_SUCCESS, success);
3168 
3169     return ret;
3170 }
3171 
OnModifyMdirtyRecords(const map<DKRecordId,DKRecordOperResult> & map)3172 int32_t FileDataHandler::OnModifyMdirtyRecords(const map<DKRecordId, DKRecordOperResult> &map)
3173 {
3174     unordered_map<string, LocalInfo> localMap;
3175     uint64_t success = 0;
3176     uint64_t failure = 0;
3177 
3178     int32_t ret = GetLocalInfo(map, localMap, Media::PhotoColumn::PHOTO_CLOUD_ID);
3179     if (ret != E_OK) {
3180         LOGE("get local match info err %{public}d", ret);
3181         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, map.size());
3182         return ret;
3183     }
3184 
3185     for (auto &entry : map) {
3186         int32_t err;
3187         const DKRecordOperResult &result = entry.second;
3188         if (result.IsSuccess()) {
3189             err = OnMdirtyRecordSuccess(entry, localMap);
3190         } else {
3191             err = OnRecordFailed(entry);
3192             failure++;
3193         }
3194         if (err != E_OK) {
3195             modifyFailSet_.push_back(entry.first);
3196             LOGE("modify mdirty record fail: cloud id: %{private}s", entry.first.c_str());
3197         } else {
3198             success++;
3199         }
3200         GetReturn(err, ret);
3201     }
3202 
3203     UpdateMetaStat(INDEX_UL_META_ERROR_SDK, failure);
3204     UpdateMetaStat(INDEX_UL_META_SUCCESS, success);
3205 
3206     return ret;
3207 }
3208 
OnModifyFdirtyRecords(const map<DKRecordId,DKRecordOperResult> & map)3209 int32_t FileDataHandler::OnModifyFdirtyRecords(const map<DKRecordId, DKRecordOperResult> &map)
3210 {
3211     unordered_map<string, LocalInfo> localMap;
3212     uint64_t success = 0;
3213     uint64_t failure = 0;
3214 
3215     int32_t ret = GetLocalInfo(map, localMap, Media::PhotoColumn::PHOTO_CLOUD_ID);
3216     if (ret != E_OK) {
3217         LOGE("get local match info err %{public}d", ret);
3218         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, map.size());
3219         return ret;
3220     }
3221 
3222     for (auto &entry : map) {
3223         int32_t err;
3224         const DKRecordOperResult &result = entry.second;
3225         if (result.IsSuccess()) {
3226             err = OnFdirtyRecordSuccess(entry, localMap);
3227         } else {
3228             err = OnRecordFailed(entry);
3229             failure++;
3230         }
3231         if (err != E_OK) {
3232             modifyFailSet_.push_back(entry.first);
3233             LOGE("modify fdirty record fail: cloud id: %{public}s", entry.first.c_str());
3234         } else {
3235             success++;
3236         }
3237         GetReturn(err, ret);
3238     }
3239 
3240     UpdateMetaStat(INDEX_UL_META_ERROR_SDK, failure);
3241     UpdateMetaStat(INDEX_UL_META_SUCCESS, success);
3242 
3243     return ret;
3244 }
3245 
Reset()3246 void FileDataHandler::Reset()
3247 {
3248     modifyFailSet_.clear();
3249     createFailSet_.clear();
3250 }
3251 
CheckRecordData(DKRecordData & data,string & path)3252 int32_t FileDataHandler::CheckRecordData(DKRecordData &data, string &path)
3253 {
3254     if (data.find(FILE_ATTRIBUTES) == data.end()) {
3255         LOGE("record data cannot find attributes");
3256         return E_INVAL_ARG;
3257     }
3258     DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
3259     if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
3260         LOGE("record data cannot find file path");
3261         return E_INVAL_ARG;
3262     }
3263     if (attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(path) != DKLocalErrorCode::NO_ERROR) {
3264         LOGE("bad file_path in props");
3265         return E_INVAL_ARG;
3266     }
3267 
3268     return E_OK;
3269 }
3270 
OnCreateRecordSuccess(const pair<DKRecordId,DKRecordOperResult> & entry,const unordered_map<string,LocalInfo> & localMap)3271 int32_t FileDataHandler::OnCreateRecordSuccess(const pair<DKRecordId, DKRecordOperResult> &entry,
3272     const unordered_map<string, LocalInfo> &localMap)
3273 {
3274     auto record = entry.second.GetDKRecord();
3275     DKRecordData data;
3276     record.GetRecordData(data);
3277     string path;
3278     int32_t checkResult = FileDataHandler::CheckRecordData(data, path);
3279     if (checkResult != E_OK) {
3280         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3281         return checkResult;
3282     }
3283 
3284     /* local file deleted */
3285     if (localMap.find(path) == localMap.end()) {
3286         return E_OK;
3287     }
3288 
3289     ValuesBucket valuesBucket;
3290     valuesBucket.PutString(Media::PhotoColumn::PHOTO_CLOUD_ID, entry.first);
3291     valuesBucket.PutInt(Media::PhotoColumn::PHOTO_POSITION, POSITION_BOTH);
3292     valuesBucket.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
3293     /**
3294      * Fix me: Non-atomic compare
3295      * A file can be modify after the local match query.
3296      * Possible Solution: if-else in SQL update
3297      */
3298     if (IsTimeChanged(record, localMap, path, Media::PhotoColumn::MEDIA_DATE_MODIFIED)) {
3299         valuesBucket.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_FDIRTY));
3300     } else if (IsTimeChanged(record, localMap, path, PhotoColumn::PHOTO_META_DATE_MODIFIED)) {
3301         valuesBucket.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY));
3302     } else {
3303         valuesBucket.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
3304     }
3305 
3306     /* Fix me: might need a transaction to do an atomic update for files and their album maps */
3307     int32_t ret = UpdateLocalAlbumMap(entry.first);
3308     if (ret != E_OK) {
3309         LOGE("update local album map err %{public}d", ret);
3310         UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3311         return ret;
3312     }
3313 
3314     /* update file */
3315     int32_t changedRows;
3316     string whereClause = PC::MEDIA_FILE_PATH + " = ? AND " + PC::PHOTO_DIRTY + " = ?";
3317     vector<string> whereArgs = { path, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_NEW)) };
3318     ret = Update(changedRows, valuesBucket, whereClause, whereArgs);
3319     if (ret != 0) {
3320         LOGE("on create records update synced err %{public}d", ret);
3321         UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3322         return ret;
3323     }
3324 
3325     /* notify */
3326     int32_t fileId;
3327     if (data[FILE_LOCAL_ID].GetInt(fileId) == DKLocalErrorCode::NO_ERROR) {
3328         (void)DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX + to_string(fileId),
3329             ChangeType::UPDATE, to_string(fileId));
3330     }
3331 
3332     return E_OK;
3333 }
3334 
OnDeleteRecordSuccess(const std::pair<DKRecordId,DKRecordOperResult> & entry)3335 int32_t FileDataHandler::OnDeleteRecordSuccess(const std::pair<DKRecordId, DKRecordOperResult> &entry)
3336 {
3337     string cloudId = entry.first;
3338     /* delete local */
3339     int32_t deletedRows;
3340     string whereClause = Media::PhotoColumn::PHOTO_CLOUD_ID + " = ?";
3341     int32_t ret = Delete(deletedRows, whereClause, { cloudId });
3342     if (ret != 0) {
3343         LOGE("on delete records update err %{public}d", ret);
3344         UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3345         return ret;
3346     }
3347 
3348     /* no error handler! */
3349     DeleteAssetInPhotoMap(deletedRows);
3350     return E_OK;
3351 }
3352 
OnMdirtyRecordSuccess(const pair<DKRecordId,DKRecordOperResult> & entry,const unordered_map<string,LocalInfo> & localMap)3353 int32_t FileDataHandler::OnMdirtyRecordSuccess(
3354     const pair<DKRecordId, DKRecordOperResult> &entry,
3355     const unordered_map<string, LocalInfo> &localMap)
3356 {
3357     auto record = entry.second.GetDKRecord();
3358     DKRecordData data;
3359     record.GetRecordData(data);
3360     string cloudId = entry.first;
3361 
3362     /* Fix me: might need a transaction to do an atomic update for files and their album maps */
3363     int32_t ret = UpdateLocalAlbumMap(entry.first);
3364     if (ret != E_OK) {
3365         LOGE("update local album map err %{public}d", ret);
3366         UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3367         return ret;
3368     }
3369 
3370     record.GetRecordData(data);
3371     if (data.find(FILE_ATTRIBUTES) == data.end()) {
3372         LOGE("record data cannot find attributes");
3373         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3374         return E_INVAL_ARG;
3375     }
3376     DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
3377     if (attributes.find(PhotoColumn::PHOTO_META_DATE_MODIFIED) == attributes.end()) {
3378         LOGE("record data cannot find file path");
3379         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3380         return E_INVAL_ARG;
3381     }
3382     int64_t meta_date_modified;
3383     if (attributes[PhotoColumn::PHOTO_META_DATE_MODIFIED].GetLong(meta_date_modified) != DKLocalErrorCode::NO_ERROR) {
3384         LOGE("bad file_path in props");
3385         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3386         return E_INVAL_ARG;
3387     }
3388 
3389     int32_t changedRows;
3390     ValuesBucket valuesBucket;
3391     valuesBucket.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
3392     valuesBucket.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
3393     /* mdirty -> synced: only if no change in meta_date_modified */
3394     ret = Update(changedRows, valuesBucket, PC::PHOTO_CLOUD_ID + " = ? AND " +
3395         PC::PHOTO_META_DATE_MODIFIED + " = ?", { cloudId, to_string(meta_date_modified) });
3396     if (ret != E_OK) {
3397         LOGE("on modify records update synced err %{public}d", ret);
3398         /* update record version anyway */
3399         valuesBucket.Clear();
3400         valuesBucket.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
3401         ret = Update(changedRows, valuesBucket, PC::PHOTO_CLOUD_ID + " = ?", { cloudId });
3402         if (ret != E_OK) {
3403             LOGE("update record version err %{public}d", ret);
3404             UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3405             return ret;
3406         }
3407     }
3408 
3409     return E_OK;
3410 }
3411 
OnFdirtyRecordSuccess(const pair<DKRecordId,DKRecordOperResult> & entry,const unordered_map<string,LocalInfo> & localMap)3412 int32_t FileDataHandler::OnFdirtyRecordSuccess(
3413     const pair<DKRecordId, DKRecordOperResult> &entry,
3414     const unordered_map<string, LocalInfo> &localMap)
3415 {
3416     auto record = entry.second.GetDKRecord();
3417     DKRecordData data;
3418     record.GetRecordData(data);
3419     string cloudId = entry.first;
3420 
3421     /* Fix me: might need a transaction to do an atomic update for files and their album maps */
3422     int32_t ret = UpdateLocalAlbumMap(entry.first);
3423     if (ret != E_OK) {
3424         LOGE("update local album map err %{public}d", ret);
3425         UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3426         return ret;
3427     }
3428 
3429     record.GetRecordData(data);
3430     if (data.find(FILE_ATTRIBUTES) == data.end()) {
3431         LOGE("record data cannot find attributes");
3432         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3433         return E_INVAL_ARG;
3434     }
3435     DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
3436     if (attributes.find(PhotoColumn::PHOTO_META_DATE_MODIFIED) == attributes.end()) {
3437         LOGE("record data cannot find file path");
3438         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3439         return E_INVAL_ARG;
3440     }
3441     int64_t meta_date_modified;
3442     if (attributes[PhotoColumn::PHOTO_META_DATE_MODIFIED].GetLong(meta_date_modified) != DKLocalErrorCode::NO_ERROR) {
3443         LOGE("bad file_path in props");
3444         UpdateMetaStat(INDEX_UL_META_ERROR_DATA, 1);
3445         return E_INVAL_ARG;
3446     }
3447 
3448     int32_t changedRows;
3449     ValuesBucket valuesBucket;
3450     valuesBucket.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
3451     valuesBucket.PutInt(Media::PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
3452     /**
3453      * fdirty -> synced: only if no change in meta_date_modified.
3454      * Fix me: if date_modified unchanged, update fdirty -> mdirty
3455      */
3456     ret = Update(changedRows, valuesBucket, PC::PHOTO_CLOUD_ID + " = ? AND " +
3457         PC::PHOTO_META_DATE_MODIFIED + " = ?", { cloudId, to_string(meta_date_modified) });
3458     if (ret != E_OK) {
3459         LOGE("on modify records update synced err %{public}d", ret);
3460         /* update record version anyway */
3461         valuesBucket.Clear();
3462         valuesBucket.PutLong(Media::PhotoColumn::PHOTO_CLOUD_VERSION, record.GetVersion());
3463         ret = Update(changedRows, valuesBucket, PC::PHOTO_CLOUD_ID + " = ?", { cloudId });
3464         if (ret != E_OK) {
3465             LOGE("update record version err %{public}d", ret);
3466             UpdateMetaStat(INDEX_UL_META_ERROR_RDB, 1);
3467             return ret;
3468         }
3469     }
3470 
3471     return E_OK;
3472 }
3473 
UpdateLocalAlbumMap(const string & cloudId)3474 int32_t FileDataHandler::UpdateLocalAlbumMap(const string &cloudId)
3475 {
3476     /* update deleted */
3477     string deleteSql = "DELETE FROM " + PM::TABLE + " WHERE " + PM::DIRTY + " = " +
3478         to_string(static_cast<int32_t>(Media::DirtyType::TYPE_DELETED)) + " AND " + PM::ASSET_ID +
3479         " IN (SELECT " + PC::MEDIA_ID + " FROM " + PC::PHOTOS_TABLE + " WHERE " +
3480         PC::PHOTO_CLOUD_ID + " = '" + cloudId + "')";
3481     int32_t ret = ExecuteSql(deleteSql);
3482     if (ret != NativeRdb::E_OK) {
3483         LOGE("delete local album map err %{public}d", ret);
3484         return ret;
3485     }
3486 
3487     /* update new */
3488     string newSql = "UPDATE " + PM::TABLE + " SET " + PM::DIRTY + " = " +
3489         to_string(static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED)) + " WHERE " + PM::ASSET_ID +
3490         " IN (SELECT " + PC::MEDIA_ID + " FROM " + PC::PHOTOS_TABLE + " WHERE " +
3491         PC::PHOTO_CLOUD_ID + " = '" + cloudId + "')";
3492     ret = ExecuteSql(newSql);
3493     if (ret != NativeRdb::E_OK) {
3494         LOGE("Update local album map err %{public}d", ret);
3495         return ret;
3496     }
3497     return ret;
3498 }
3499 
IsTimeChanged(const DriveKit::DKRecord & record,const unordered_map<string,LocalInfo> & localMap,const string & path,const string & type)3500 bool FileDataHandler::IsTimeChanged(const DriveKit::DKRecord &record,
3501     const unordered_map<string, LocalInfo> &localMap, const string &path, const string &type)
3502 {
3503     int64_t cloudtime = 0;
3504     int64_t localtime = 0;
3505     auto it = localMap.find(path);
3506     if (it == localMap.end()) {
3507         return true;
3508     }
3509     DKRecordData data;
3510     record.GetRecordData(data);
3511     if (data.find(FILE_ATTRIBUTES) == data.end()) {
3512         LOGE("record data cannot find attributes");
3513         return false;
3514     }
3515     DriveKit::DKRecordFieldMap attributes;
3516     data[FILE_ATTRIBUTES].GetRecordMap(attributes);
3517     /* get mtime or metatime */
3518     if (type == Media::PhotoColumn::MEDIA_DATE_MODIFIED) {
3519         localtime = it->second.fdirtyTime;
3520         if (attributes[FILE_EDITED_TIME_MS].GetLong(cloudtime) != DKLocalErrorCode::NO_ERROR) {
3521             LOGE("obtain MEDIA_DATE_MODIFIED error");
3522             return false;
3523         }
3524     } else {
3525         localtime = it->second.mdirtyTime;
3526         if (attributes[PhotoColumn::PHOTO_META_DATE_MODIFIED].GetLong(cloudtime) != DKLocalErrorCode::NO_ERROR) {
3527             LOGE("obtain PHOTO_META_DATE_MODIFIED error");
3528             return false;
3529         }
3530     }
3531     if (localtime == cloudtime) {
3532         return false;
3533     }
3534     return true;
3535 }
3536 
GetLocalInfo(const map<DKRecordId,DKRecordOperResult> & map,unordered_map<string,LocalInfo> & infoMap,const string & type)3537 int32_t FileDataHandler::GetLocalInfo(const map<DKRecordId, DKRecordOperResult> &map,
3538     unordered_map<string, LocalInfo> &infoMap, const string &type)
3539 {
3540     vector<string> path;
3541     for (auto &entry : map) {
3542         if (type == Media::PhotoColumn::PHOTO_CLOUD_ID) {
3543             path.push_back(entry.first);
3544         } else {
3545             auto record = entry.second.GetDKRecord();
3546             DKRecordData data;
3547             record.GetRecordData(data);
3548             if (data.find(FILE_ATTRIBUTES) == data.end()) {
3549                 LOGE("record data cannot find attributes");
3550                 return E_DATA;
3551             }
3552             DriveKit::DKRecordFieldMap attributes = data[FILE_ATTRIBUTES];
3553             if (attributes.find(PhotoColumn::MEDIA_FILE_PATH) == attributes.end()) {
3554                 LOGE("record data cannot find some attributes");
3555                 return E_DATA;
3556             }
3557             string curPath;
3558             if (attributes[PhotoColumn::MEDIA_FILE_PATH].GetString(curPath) != DKLocalErrorCode::NO_ERROR) {
3559                 LOGE("bad file_path in props");
3560                 return E_DATA;
3561             }
3562             path.push_back(curPath);
3563         }
3564     }
3565 
3566     NativeRdb::AbsRdbPredicates createPredicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
3567     createPredicates.And()->In(type, path);
3568     auto resultSet = Query(createPredicates, ON_UPLOAD_COLUMNS);
3569     if (resultSet == nullptr) {
3570         LOGE("query rdb err");
3571         return E_RDB;
3572     }
3573 
3574     return BuildInfoMap(move(resultSet), infoMap, type);
3575 }
3576 
BuildInfoMap(const shared_ptr<NativeRdb::ResultSet> resultSet,unordered_map<string,LocalInfo> & infoMap,const string & type)3577 int32_t FileDataHandler::BuildInfoMap(const shared_ptr<NativeRdb::ResultSet> resultSet,
3578     unordered_map<string, LocalInfo> &infoMap, const string &type)
3579 {
3580     int32_t idIndex = -1;
3581     int32_t mtimeIndex = -1;
3582     int32_t metatimeIndex = -1;
3583     RETURN_ON_ERR(resultSet->GetColumnIndex(type, idIndex));
3584     RETURN_ON_ERR(resultSet->GetColumnIndex(PC::MEDIA_DATE_MODIFIED, mtimeIndex));
3585     RETURN_ON_ERR(resultSet->GetColumnIndex(PC::PHOTO_META_DATE_MODIFIED, metatimeIndex));
3586 
3587     /* iterate all rows compare mtime metatime */
3588     while (resultSet->GoToNextRow() == 0) {
3589         string idValue;
3590         int64_t mtime;
3591         int64_t metatime;
3592         if (resultSet->GetString(idIndex, idValue) == 0 && resultSet->GetLong(mtimeIndex, mtime) == 0 &&
3593             resultSet->GetLong(metatimeIndex, metatime) == 0) {
3594             infoMap.insert({ idValue, { metatime, mtime } });
3595         }
3596     }
3597     return E_OK;
3598 }
3599 
UTCTimeSeconds()3600 int64_t FileDataHandler::UTCTimeSeconds()
3601 {
3602     struct timespec ts;
3603     ts.tv_sec = 0;
3604     ts.tv_nsec = 0;
3605     clock_gettime(CLOCK_REALTIME, &ts);
3606     return static_cast<int64_t>(ts.tv_sec);
3607 }
3608 
OptimizeStorage(const int32_t agingDays)3609 int32_t FileDataHandler::OptimizeStorage(const int32_t agingDays)
3610 {
3611     int64_t totalSize = GetTotalSize();
3612     totalSize = GetRoundSize(totalSize);
3613     int64_t freeSize = GetFreeSize();
3614     int64_t agingTime = 0;
3615     int64_t deleteSize = 0;
3616     int ret = 0;
3617     if (totalSize * START_AGING_SIZE > static_cast<double>(freeSize)) {
3618         agingTime = agingDays * DAY_TO_SECONDS;
3619         deleteSize = int64_t(totalSize * STOP_AGING_SIZE - static_cast<double>(freeSize));
3620         ret = FileAgingDelete(agingTime, deleteSize);
3621         if (ret != E_OK) {
3622             LOGE("OptimizeStorage Error");
3623             return ret;
3624         }
3625     }
3626 
3627     freeSize = GetFreeSize();
3628     if (totalSize * LOWEST_START_AGING_SIZE > static_cast<double>(freeSize)) {
3629         agingTime = 0;
3630         deleteSize = int64_t(totalSize * LOWEST_STOP_AGING_SIZE - static_cast<double>(freeSize));
3631         ret = FileAgingDelete(agingTime, deleteSize);
3632         if (ret != E_OK) {
3633             LOGE("OptimizeStorage Error");
3634             return ret;
3635         }
3636     }
3637     return E_OK;
3638 }
3639 
GetAgingFile(const int64_t agingTime,int32_t & rowCount)3640 std::shared_ptr<NativeRdb::ResultSet> FileDataHandler::GetAgingFile(const int64_t agingTime,
3641                                                                     int32_t &rowCount)
3642 {
3643     auto time = UTCTimeSeconds();
3644     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
3645     predicates.LessThanOrEqualTo(PC::PHOTO_LAST_VISIT_TIME, to_string(TO_MILLISECONDS * (time - agingTime)));
3646     predicates.And()->EqualTo(PC::PHOTO_POSITION, POSITION_BOTH);
3647     predicates.OrderByAsc(PC::PHOTO_LAST_VISIT_TIME);
3648     auto results = Query(predicates, MEDIA_CLOUD_SYNC_COLUMNS);
3649     if (results == nullptr) {
3650         LOGE("get nullptr result");
3651         return results;
3652     }
3653     int ret = results->GetRowCount(rowCount);
3654     LOGE("rowCount = %{public}d", rowCount);
3655     if (ret != 0) {
3656         LOGE("get rowCount error");
3657         return nullptr;
3658     }
3659     return results;
3660 }
3661 
UpdateAgingFile(const string cloudId)3662 int32_t FileDataHandler::UpdateAgingFile(const string cloudId)
3663 {
3664     ValuesBucket values;
3665     values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_CLOUD);
3666     int32_t changedRows;
3667     string whereClause = PhotoColumn::PHOTO_CLOUD_ID + " = ?";
3668     int ret = Update(changedRows, values, whereClause, {cloudId});
3669     if (ret != E_OK) {
3670         LOGE("rdb update failed, err=%{public}d", ret);
3671         return E_RDB;
3672     }
3673     return E_OK;
3674 }
3675 
FileAgingDelete(const int64_t agingTime,const int64_t deleteSize)3676 int32_t FileDataHandler::FileAgingDelete(const int64_t agingTime, const int64_t deleteSize)
3677 {
3678     int rowCount = 0;
3679     int64_t totalSize = 0;
3680     auto results = GetAgingFile(agingTime, rowCount);
3681     if (results == nullptr) {
3682         LOGE("get nullptr result");
3683         return E_RDB;
3684     }
3685     if (rowCount == 0) {
3686         LOGE("get null file");
3687         return E_OK;
3688     }
3689     while (results->GoToNextRow() == 0) {
3690         string path;
3691         int64_t size;
3692         string cloudId;
3693         int ret = DataConvertor::GetString(MEDIA_DATA_DB_FILE_PATH, path, *results);
3694         if (ret != E_OK) {
3695             LOGE("get path error");
3696             continue;
3697         }
3698         ret = DataConvertor::GetString(MEDIA_DATA_DB_CLOUD_ID, cloudId, *results);
3699         if (ret != E_OK) {
3700             LOGE("get cloudId error");
3701             continue;
3702         }
3703         ret = DataConvertor::GetLong(MEDIA_DATA_DB_SIZE, size, *results);
3704         if (ret != E_OK) {
3705             LOGE("get size error");
3706             continue;
3707         }
3708         string filePath = GetLocalPath(userId_, path);
3709         ret = unlink(filePath.c_str());
3710         if (ret != 0) {
3711             LOGE("fail to delete");
3712             continue;
3713         }
3714         ret = UpdateAgingFile(cloudId);
3715         if (ret != E_OK) {
3716             LOGE("update failed");
3717             continue;
3718         }
3719         totalSize += size;
3720         if (totalSize > deleteSize) {
3721             break;
3722         }
3723     }
3724     return E_OK;
3725 }
3726 
GetThumbToDownload(std::vector<DriveKit::DKDownloadAsset> & outAssetsToDownload)3727 int32_t FileDataHandler::GetThumbToDownload(std::vector<DriveKit::DKDownloadAsset> &outAssetsToDownload)
3728 {
3729     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(TABLE_NAME);
3730     predicates.EqualTo(PC::PHOTO_SYNC_STATUS, to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)));
3731     predicates.EqualTo(PC::PHOTO_CLEAN_FLAG, to_string(static_cast<int32_t>(NOT_NEED_CLEAN)))
3732         ->And()->BeginWrap()
3733         ->EqualTo(PC::PHOTO_THUMB_STATUS, to_string(static_cast<int32_t>(ThumbState::TO_DOWNLOAD)))
3734         ->Or()->EqualTo(PC::PHOTO_THUMB_STATUS, to_string(static_cast<int32_t>(ThumbState::THM_TO_DOWNLOAD)))
3735         ->Or()->EqualTo(PC::PHOTO_THUMB_STATUS, to_string(static_cast<int32_t>(ThumbState::LCD_TO_DOWNLOAD)))
3736         ->EndWrap();
3737     predicates.Limit(DOWNLOAD_LIMIT_SIZE);
3738     auto results = Query(predicates, { PC::MEDIA_FILE_PATH, PC::PHOTO_CLOUD_ID, PC::PHOTO_THUMB_STATUS });
3739     if (results == nullptr) {
3740         LOGE("get nullptr TYPE_DOWNLOAD result");
3741         return E_RDB;
3742     }
3743 
3744     while (results->GoToNextRow() == 0) {
3745         int32_t thmState = 0;
3746         int32_t ret = DataConvertor::GetInt(PC::PHOTO_THUMB_STATUS, thmState, *results);
3747         if (ret != E_OK) {
3748             LOGE("Get file path failed");
3749             continue;
3750         }
3751         if (thmState == static_cast<int32_t>(ThumbState::TO_DOWNLOAD)) {
3752             AppendToDownload(*results, "thumbnail", outAssetsToDownload);
3753             AppendToDownload(*results, "lcd", outAssetsToDownload);
3754         } else if (thmState == static_cast<int32_t>(ThumbState::LCD_TO_DOWNLOAD)) {
3755             AppendToDownload(*results, "lcd", outAssetsToDownload);
3756         } else if (thmState == static_cast<int32_t>(ThumbState::THM_TO_DOWNLOAD)) {
3757             AppendToDownload(*results, "thumbnail", outAssetsToDownload);
3758         }
3759     }
3760     return E_OK;
3761 }
3762 
UpdateThmVec()3763 void FileDataHandler::UpdateThmVec()
3764 {
3765     if (!thmVec_.empty()) {
3766         LOGI("thmVec_ size is %{public}zu", thmVec_.size());
3767         string sql = "UPDATE " + PC::PHOTOS_TABLE + " SET " + PC::PHOTO_SYNC_STATUS + " = " +
3768             to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)) + " , " + PC::PHOTO_THUMB_STATUS +
3769             " = CASE WHEN " + PC::PHOTO_THUMB_STATUS + " - " +
3770             to_string(static_cast<int32_t>(ThumbState::THM_TO_DOWNLOAD)) + " < 0 THEN 0 ELSE " + PC::PHOTO_THUMB_STATUS
3771             + " - " + to_string(static_cast<int32_t>(ThumbState::THM_TO_DOWNLOAD)) + " END ";
3772         int32_t ret = E_OK;
3773         uint64_t count = 0;
3774         uint32_t size = 0;
3775         vector<ValueObject> tmp;
3776         {
3777             std::lock_guard<std::mutex> lock(thmMutex_);
3778             size = thmVec_.size();
3779             tmp.assign(thmVec_.begin(), thmVec_.begin() + size);
3780             thmVec_.erase(thmVec_.begin(), thmVec_.begin() + size);
3781         }
3782         vector<int> fileIds = vector<int>(size);
3783         BatchGetFileIdFromCloudId(tmp, fileIds);
3784         ret = BatchUpdate(sql, PC::PHOTO_CLOUD_ID, tmp, count);
3785         LOGI("update size is %{public}zu, success count is %{public}lld, fail count is %{public}zu",
3786             size, count, tmp.size());
3787         if (ret != E_OK) {
3788             LOGW("update thm fail");
3789             std::lock_guard<std::mutex> lock(thmMutex_);
3790             thmVec_.insert(thmVec_.end(), tmp.begin(), tmp.end());
3791         }
3792         if (count != 0) {
3793             UpdateAttachmentStat(INDEX_THUMB_SUCCESS, count);
3794         }
3795         if (!IsPullRecords()) {
3796             UpdateAlbumInternal();
3797         }
3798         for (auto &fileId : fileIds) {
3799             DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX + to_string(fileId), ChangeType::INSERT, "");
3800         }
3801         DataSyncNotifier::GetInstance().TryNotify(PHOTO_URI_PREFIX, ChangeType::INSERT, "");
3802         DataSyncNotifier::GetInstance().FinalNotify();
3803     }
3804 }
3805 
UpdateLcdVec()3806 void FileDataHandler::UpdateLcdVec()
3807 {
3808     if (!lcdVec_.empty()) {
3809         LOGI("lcdVec_ size is %{public}zu", lcdVec_.size());
3810         string sql = "UPDATE " + PC::PHOTOS_TABLE + " SET " + PC::PHOTO_THUMB_STATUS + " = CASE WHEN " +
3811             PC::PHOTO_THUMB_STATUS + " - " + to_string(static_cast<int32_t>(ThumbState::LCD_TO_DOWNLOAD)) +
3812             " < 0 THEN 0 ELSE " + PC::PHOTO_THUMB_STATUS + " - " +
3813             to_string(static_cast<int32_t>(ThumbState::LCD_TO_DOWNLOAD)) + " END ";
3814         int32_t ret = E_OK;
3815         uint64_t count = 0;
3816         uint32_t size = 0;
3817         vector<ValueObject> tmp;
3818         {
3819             std::lock_guard<std::mutex> lock(lcdMutex_);
3820             size = lcdVec_.size();
3821             tmp.assign(lcdVec_.begin(), lcdVec_.begin() + size);
3822             lcdVec_.erase(lcdVec_.begin(), lcdVec_.begin() + size);
3823         }
3824         ret = BatchUpdate(sql, PC::PHOTO_CLOUD_ID, tmp, count);
3825         LOGI("update size is %{public}zu, success count is %{public}lld, fail count is %{public}zu",
3826             size, count, tmp.size());
3827         if (ret != E_OK) {
3828             LOGW("update thm fail");
3829             std::lock_guard<std::mutex> lock(lcdMutex_);
3830             lcdVec_.insert(lcdVec_.end(), tmp.begin(), tmp.end());
3831         }
3832         if (count != 0) {
3833             UpdateAttachmentStat(INDEX_LCD_SUCCESS, count);
3834         }
3835     }
3836 }
3837 
PeriodicUpdataFiles(uint32_t & timeId)3838 void FileDataHandler::PeriodicUpdataFiles(uint32_t &timeId)
3839 {
3840     const uint32_t TIMER_INTERVAL = 2000;
3841     auto timerCallBack = [this]() {
3842         if (thmVec_.empty() && lcdVec_.empty()) {
3843             waitCount_ ++;
3844             LOGI("no thumbnail is downloading, wait %{public}d times", waitCount_);
3845             if (waitCount_ >= 30) {
3846                 TaskStateManager::GetInstance().CompleteTask(bundleName_, TaskType::DOWNLOAD_THUMB_TASK);
3847                 StopUpdataFiles(timeId_);
3848                 waitCount_ = 0;
3849             }
3850         } else {
3851             waitCount_ = 0;
3852         }
3853         UpdateThmVec();
3854         UpdateLcdVec();
3855     };
3856     if (timeId == 0) {
3857         LOGI("start update timer");
3858         DfsuTimer::GetInstance().Register(timerCallBack, timeId, TIMER_INTERVAL);
3859         timeId_ = timeId;
3860     } else {
3861         LOGI("timer is running");
3862     }
3863 }
3864 
StopUpdataFiles(uint32_t & timeId)3865 void FileDataHandler::StopUpdataFiles(uint32_t &timeId)
3866 {
3867     const uint32_t MAX_TRY_TIMES = 5;
3868     uint32_t tryCount = 1;
3869     if (timeId != 0) {
3870         LOGI("stop update timer");
3871         DfsuTimer::GetInstance().Unregister(timeId);
3872         while (tryCount <= MAX_TRY_TIMES && (!lcdVec_.empty() || !thmVec_.empty())) {
3873             UpdateThmVec();
3874             UpdateLcdVec();
3875             tryCount++;
3876         }
3877         timeId = 0;
3878         timeId_ = 0;
3879     }
3880 
3881     UpdateAttachmentStat(INDEX_THUMB_ERROR_RDB, thmVec_.size());
3882     UpdateAttachmentStat(INDEX_LCD_ERROR_RDB, lcdVec_.size());
3883 }
3884 } // namespace CloudSync
3885 } // namespace FileManagement
3886 } // namespace OHOS
3887