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 ¶ms,
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 ¶ms)
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 ¶ms)
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 ¶ms)
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 ¶ms)
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 ¶ms)
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