• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #define MLOG_TAG "FileOperation"
16 
17 #include "medialibrary_file_operations.h"
18 
19 #include "datashare_predicates.h"
20 #include "datashare_values_bucket.h"
21 #include "file_asset.h"
22 #include "hitrace_meter.h"
23 #include "media_file_utils.h"
24 #include "media_log.h"
25 #include "medialibrary_data_manager_utils.h"
26 #include "medialibrary_db_const.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_notify.h"
29 #include "medialibrary_object_utils.h"
30 #include "medialibrary_smartalbum_map_operations.h"
31 #include "medialibrary_tracer.h"
32 #include "medialibrary_unistore_manager.h"
33 #include "native_album_asset.h"
34 #include "rdb_utils.h"
35 
36 using namespace std;
37 using namespace OHOS::NativeRdb;
38 using namespace OHOS::DataShare;
39 using namespace OHOS::RdbDataShareAdapter;
40 
41 namespace OHOS {
42 namespace Media {
43 using ChangeType = AAFwk::ChangeInfo::ChangeType;
44 
HandleFileOperation(MediaLibraryCommand & cmd)45 int32_t MediaLibraryFileOperations::HandleFileOperation(MediaLibraryCommand &cmd)
46 {
47     int32_t errCode = E_FAIL;
48     auto values = cmd.GetValueBucket();
49     string actualUri;
50 
51     ValueObject valueObject;
52     if (values.GetObject(MEDIA_DATA_DB_URI, valueObject)) {
53         valueObject.GetString(actualUri);
54     }
55 
56     // only support CloseAsset when networkId is not empty
57     string networkId = MediaLibraryDataManagerUtils::GetNetworkIdFromUri(actualUri);
58     if (!networkId.empty() && cmd.GetOprnType() != OperationType::CLOSE) {
59         return E_PERMISSION_DENIED;
60     }
61 
62     switch (cmd.GetOprnType()) {
63         case OperationType::CREATE:
64             errCode = CreateFileOperation(cmd);
65             break;
66         case OperationType::CLOSE:
67             errCode = CloseFileOperation(cmd);
68             break;
69         case OperationType::GETCAPACITY:
70             errCode = GetAlbumCapacityOperation(cmd);
71             break;
72         case OperationType::COPY:
73             errCode = CopyFileOperation(cmd);
74             break;
75         default:
76             MEDIA_ERR_LOG("unknown operation type %{public}d", cmd.GetOprnType());
77             break;
78     }
79     return errCode;
80 }
81 
CreateFileOperation(MediaLibraryCommand & cmd)82 int32_t MediaLibraryFileOperations::CreateFileOperation(MediaLibraryCommand &cmd)
83 {
84     return MediaLibraryObjectUtils::CreateFileObj(cmd);
85 }
86 
CloseFileOperation(MediaLibraryCommand & cmd)87 int32_t MediaLibraryFileOperations::CloseFileOperation(MediaLibraryCommand &cmd)
88 {
89     return MediaLibraryObjectUtils::CloseFile(cmd);
90 }
91 
QueryFavFiles(MediaLibraryCommand & cmd)92 shared_ptr<NativeRdb::ResultSet> MediaLibraryFileOperations::QueryFavFiles(MediaLibraryCommand &cmd)
93 {
94     cmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_IS_FAV, "1");
95     cmd.GetAbsRdbPredicates()->And()->NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, std::to_string(MEDIA_TYPE_ALBUM));
96 
97     return MediaLibraryObjectUtils::QueryWithCondition(cmd, {});
98 }
99 
QueryTrashFiles(MediaLibraryCommand & cmd)100 shared_ptr<NativeRdb::ResultSet> MediaLibraryFileOperations::QueryTrashFiles(MediaLibraryCommand &cmd)
101 {
102     cmd.GetAbsRdbPredicates()
103         ->GreaterThan(MEDIA_DATA_DB_DATE_TRASHED, std::to_string(NOT_TRASHED))
104         ->And()
105         ->NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, std::to_string(MEDIA_TYPE_ALBUM));
106 
107     return MediaLibraryObjectUtils::QueryWithCondition(cmd, {});
108 }
109 
GetAlbumCapacityOperation(MediaLibraryCommand & cmd)110 int32_t MediaLibraryFileOperations::GetAlbumCapacityOperation(MediaLibraryCommand &cmd)
111 {
112     int32_t errorCode = E_FAIL;
113     shared_ptr<NativeRdb::ResultSet> resultSet = nullptr;
114 
115     auto values = cmd.GetValueBucket();
116     ValueObject valueObject;
117     int32_t isFavourite = 0;
118     bool isTrash = false;
119     if (values.GetObject(MEDIA_DATA_DB_IS_FAV, valueObject)) {
120         valueObject.GetInt(isFavourite);
121     }
122     if (values.GetObject(MEDIA_DATA_DB_IS_TRASH, valueObject)) {
123         valueObject.GetBool(isTrash);
124     }
125 
126     if (isFavourite != 0) {
127         resultSet = QueryFavFiles(cmd);
128     } else if (isTrash) {
129         resultSet = QueryTrashFiles(cmd);
130     }
131 
132     if (resultSet != nullptr) {
133         resultSet->GetRowCount(errorCode);
134         MEDIA_INFO_LOG("GetRowCount %{private}d", errorCode);
135     }
136 
137     return errorCode;
138 }
139 
ModifyFileOperation(MediaLibraryCommand & cmd)140 int32_t MediaLibraryFileOperations::ModifyFileOperation(MediaLibraryCommand &cmd)
141 {
142     string strFileId = cmd.GetOprnFileId();
143     if (strFileId.empty()) {
144         MEDIA_ERR_LOG("MediaLibraryFileOperations::ModifyFileOperation Get id from uri or valuesBucket failed!");
145         return E_INVALID_FILEID;
146     }
147 
148     string srcPath = MediaLibraryObjectUtils::GetPathByIdFromDb(strFileId);
149     if (srcPath.empty()) {
150         MEDIA_ERR_LOG("MediaLibraryFileOperations::ModifyFileOperation Get path of id %{private}s from database file!",
151             strFileId.c_str());
152         return E_INVALID_FILEID;
153     }
154 
155     string dstFileName;
156     string dstReFilePath;
157     auto values = cmd.GetValueBucket();
158     ValueObject valueObject;
159     if (values.GetObject(MEDIA_DATA_DB_NAME, valueObject)) {
160         valueObject.GetString(dstFileName);
161     }
162     if (values.GetObject(MEDIA_DATA_DB_RELATIVE_PATH, valueObject)) {
163         valueObject.GetString(dstReFilePath);
164     }
165     string dstFilePath = ROOT_MEDIA_DIR + dstReFilePath + dstFileName;
166 
167     if (srcPath.compare(dstFilePath) == 0) {
168         return E_SAME_PATH;
169     }
170     return MediaLibraryObjectUtils::RenameFileObj(cmd, srcPath, dstFilePath);
171 }
172 
173 constexpr bool START_PENDING = false;
SolvePendingInQuery(AbsRdbPredicates * predicates)174 static void SolvePendingInQuery(AbsRdbPredicates* predicates)
175 {
176     string whereClause = predicates->GetWhereClause();
177     size_t groupByPoint = whereClause.rfind("GROUP BY");
178     string groupBy;
179     if (groupByPoint != string::npos) {
180         groupBy = whereClause.substr(groupByPoint);
181         whereClause = whereClause.substr(0, groupByPoint);
182     }
183 
184     predicates->SetWhereClause(whereClause);
185     predicates->EqualTo(MEDIA_DATA_DB_TIME_PENDING, "0");
186     if (!groupBy.empty()) {
187         predicates->SetWhereClause(predicates->GetWhereClause() + groupBy);
188     }
189 }
190 
191 #ifdef MEDIALIBRARY_COMPATIBILITY
PhotosCompatColumns()192 static const vector<string> &PhotosCompatColumns()
193 {
194     /*
195      * Caution: Columns MUST KEEP SAME ORDER for sqlite UNION operation in:
196      *     o PHOTOS_COMPAT_COLUMNS
197      *     o AUDIOS_COMPAT_COLUMNS
198      *     o FILES_COMPAT_COLUMNS
199      */
200     static const vector<string> PHOTOS_COMPAT_COLUMNS = {
201         MEDIA_DATA_DB_ID,
202         MEDIA_DATA_DB_FILE_PATH,
203         COMPAT_COLUMN_URI,
204         MEDIA_DATA_DB_MIME_TYPE,
205         MEDIA_DATA_DB_MEDIA_TYPE,
206         MEDIA_DATA_DB_NAME,
207         MEDIA_DATA_DB_TITLE,
208         MEDIA_DATA_DB_RELATIVE_PATH,
209         MEDIA_DATA_DB_PARENT_ID,
210         MEDIA_DATA_DB_SIZE,
211         MEDIA_DATA_DB_DATE_ADDED,
212         MEDIA_DATA_DB_DATE_MODIFIED,
213         MEDIA_DATA_DB_DATE_TAKEN,
214         COMPAT_COLUMN_ARTIST,
215         COMPAT_COLUMN_AUDIO_ALBUM,
216         MEDIA_DATA_DB_WIDTH,
217         MEDIA_DATA_DB_HEIGHT,
218         MEDIA_DATA_DB_ORIENTATION,
219         MEDIA_DATA_DB_DURATION,
220         COMPAT_COLUMN_BUCKET_ID,
221         COMPAT_COLUMN_BUCKET_NAME,
222         COMPAT_COLUMN_IS_TRASH,
223         MEDIA_DATA_DB_IS_FAV,
224         MEDIA_DATA_DB_DATE_TRASHED,
225 
226         MediaColumn::MEDIA_HIDDEN,
227         PhotoColumn::PHOTO_SYNC_STATUS,
228         PhotoColumn::PHOTO_SUBTYPE,
229     };
230     return PHOTOS_COMPAT_COLUMNS;
231 }
232 
AudiosCompatColumns()233 static const vector<string> &AudiosCompatColumns()
234 {
235     /*
236      * Caution: Columns MUST KEEP SAME ORDER for sqlite UNION operation in:
237      *     o PHOTOS_COMPAT_COLUMNS
238      *     o AUDIOS_COMPAT_COLUMNS
239      *     o FILES_COMPAT_COLUMNS
240      */
241     static const vector<string> AUDIOS_COMPAT_COLUMNS = {
242         MEDIA_DATA_DB_ID,
243         MEDIA_DATA_DB_FILE_PATH,
244         COMPAT_COLUMN_URI,
245         MEDIA_DATA_DB_MIME_TYPE,
246         MEDIA_DATA_DB_MEDIA_TYPE,
247         MEDIA_DATA_DB_NAME,
248         MEDIA_DATA_DB_TITLE,
249         MEDIA_DATA_DB_RELATIVE_PATH,
250         MEDIA_DATA_DB_PARENT_ID,
251         MEDIA_DATA_DB_SIZE,
252         MEDIA_DATA_DB_DATE_ADDED,
253         MEDIA_DATA_DB_DATE_MODIFIED,
254         MEDIA_DATA_DB_DATE_TAKEN,
255         MEDIA_DATA_DB_ARTIST,
256         MEDIA_DATA_DB_AUDIO_ALBUM,
257         COMPAT_COLUMN_WIDTH,
258         COMPAT_COLUMN_HEIGHT,
259         COMPAT_COLUMN_ORIENTATION,
260         MEDIA_DATA_DB_DURATION,
261         COMPAT_COLUMN_BUCKET_ID,
262         COMPAT_COLUMN_BUCKET_NAME,
263         COMPAT_COLUMN_IS_TRASH,
264         MEDIA_DATA_DB_IS_FAV,
265         MEDIA_DATA_DB_DATE_TRASHED,
266 
267         DEFAULT_INT_COLUMN_AS + MediaColumn::MEDIA_HIDDEN,
268         DEFAULT_INT_COLUMN_AS + PhotoColumn::PHOTO_SYNC_STATUS,
269         DEFAULT_INT_COLUMN_AS + PhotoColumn::PHOTO_SUBTYPE,
270     };
271     return AUDIOS_COMPAT_COLUMNS;
272 }
273 
FilesCompatColumns()274 static const vector<string> &FilesCompatColumns()
275 {
276     /*
277      * Caution: KEEP SAME ORDER for sqlite UNION operation in columns below:
278      *     o PHOTOS_COMPAT_COLUMNS
279      *     o AUDIOS_COMPAT_COLUMNS
280      *     o FILES_COMPAT_COLUMNS
281      */
282     static const vector<string> FILES_COMPAT_COLUMNS = {
283         MEDIA_DATA_DB_ID,
284         MEDIA_DATA_DB_FILE_PATH,
285         MEDIA_DATA_DB_URI,
286         MEDIA_DATA_DB_MIME_TYPE,
287         MEDIA_DATA_DB_MEDIA_TYPE,
288         MEDIA_DATA_DB_NAME,
289         MEDIA_DATA_DB_TITLE,
290         MEDIA_DATA_DB_RELATIVE_PATH,
291         MEDIA_DATA_DB_PARENT_ID,
292         MEDIA_DATA_DB_SIZE,
293         MEDIA_DATA_DB_DATE_ADDED,
294         MEDIA_DATA_DB_DATE_MODIFIED,
295         MEDIA_DATA_DB_DATE_TAKEN,
296         MEDIA_DATA_DB_ARTIST,
297         COMPAT_COLUMN_AUDIO_ALBUM,
298         MEDIA_DATA_DB_WIDTH,
299         MEDIA_DATA_DB_HEIGHT,
300         MEDIA_DATA_DB_ORIENTATION,
301         MEDIA_DATA_DB_DURATION,
302         MEDIA_DATA_DB_BUCKET_ID,
303         MEDIA_DATA_DB_BUCKET_NAME,
304         MEDIA_DATA_DB_IS_TRASH,
305         MEDIA_DATA_DB_IS_FAV,
306         MEDIA_DATA_DB_DATE_TRASHED,
307 
308         DEFAULT_INT_COLUMN_AS + MediaColumn::MEDIA_HIDDEN,
309         PhotoColumn::PHOTO_SYNC_STATUS,
310         DEFAULT_INT_COLUMN_AS + PhotoColumn::PHOTO_SUBTYPE,
311     };
312 
313     return FILES_COMPAT_COLUMNS;
314 }
315 
BuildQueryColumns(const vector<string> & columns,string & sql)316 static void BuildQueryColumns(const vector<string> &columns, string &sql)
317 {
318     for (const auto &col : columns) {
319         sql += col + ',';
320     }
321     sql.pop_back();         // Remove last ','
322 }
323 
ReplaceAlbumName(const string & arg,string & argInstead)324 static void ReplaceAlbumName(const string &arg, string &argInstead)
325 {
326     if (arg == CAMERA_ALBUM_NAME) {
327         argInstead = to_string(static_cast<int32_t>(PhotoSubType::CAMERA));
328     } else if (arg == SCREEN_SHOT_ALBUM_NAME || arg == SCREEN_RECORD_ALBUM_NAME) {
329         argInstead = to_string(static_cast<int32_t>(PhotoSubType::SCREENSHOT));
330     } else {
331         argInstead = arg;
332     }
333 }
334 
ReplaceId(const string & fileId,string & idInstead,const string & tableName)335 static void ReplaceId(const string &fileId, string &idInstead, const string &tableName)
336 {
337     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
338         return;
339     }
340     int32_t id = stoi(fileId);
341     idInstead = to_string(MediaFileUtils::GetRealIdByTable(id, tableName));
342 }
343 
ReplaceSelectionAndArgsInQuery(string & selection,vector<string> & selectionArgs,const string & tableName,const string & key,const string & keyInstead="")344 static void ReplaceSelectionAndArgsInQuery(string &selection, vector<string> &selectionArgs,
345     const string &tableName, const string &key, const string &keyInstead = "")
346 {
347     if (selection.empty()) {
348         return;
349     }
350 
351     for (size_t pos = 0; pos != string::npos;) {
352         pos = selection.find(key, pos);
353         if (pos == string::npos) {
354             break;
355         }
356         if (!keyInstead.empty()) {
357             selection.replace(pos, key.length(), keyInstead);
358         }
359         size_t argPos = selection.find('?', pos);
360         if (argPos == string::npos) {
361             break;
362         }
363         size_t argIndex = 0;
364         for (size_t i = 0; i < argPos; i++) {
365             if (selection[i] == '?') {
366                 argIndex++;
367             }
368         }
369         if (argIndex > selectionArgs.size() - 1) {
370             MEDIA_INFO_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
371                 selection.c_str());
372             break;
373         }
374         const string &arg = selectionArgs[argIndex];
375         string argInstead = arg;
376         if (key == MEDIA_DATA_DB_BUCKET_NAME) {
377             ReplaceAlbumName(arg, argInstead);
378         } else if (key == MEDIA_DATA_DB_ID) {
379             ReplaceId(arg, argInstead, tableName);
380         }
381         selectionArgs[argIndex] = argInstead;
382         pos = argPos + 1;
383     }
384 }
385 
BuildCompatQuerySql(MediaLibraryCommand & cmd,const string table,const vector<string> & columns,vector<string> & selectionArgs,string & sql)386 static void BuildCompatQuerySql(MediaLibraryCommand &cmd, const string table, const vector<string> &columns,
387     vector<string> &selectionArgs, string &sql)
388 {
389     sql += "SELECT ";
390     BuildQueryColumns(columns, sql);
391     sql += " FROM " + table;
392 
393     string whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
394     vector<string> whereArgs = cmd.GetAbsRdbPredicates()->GetWhereArgs();
395     if (table == PhotoColumn::PHOTOS_TABLE) {
396         ReplaceSelectionAndArgsInQuery(whereClause, whereArgs, table, MEDIA_DATA_DB_BUCKET_NAME,
397             PhotoColumn::PHOTO_SUBTYPE);
398     }
399     ReplaceSelectionAndArgsInQuery(whereClause, whereArgs, table, MEDIA_DATA_DB_ID);
400 
401     if (!whereClause.empty()) {
402         sql += " WHERE " + whereClause;
403     }
404 
405     if (!whereArgs.empty()) {
406         selectionArgs.insert(selectionArgs.end(), whereArgs.begin(), whereArgs.end());
407     }
408 }
409 
RemoveWhereSuffix(MediaLibraryCommand & cmd,const string & key)410 static string RemoveWhereSuffix(MediaLibraryCommand &cmd, const string &key)
411 {
412     string suffix;
413     string whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
414     size_t keyPos = MediaFileUtils::FindIgnoreCase(whereClause, key);
415     if (keyPos != string::npos) {
416         suffix = whereClause.substr(keyPos);
417         whereClause = whereClause.substr(0, keyPos);
418     }
419     cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
420     return suffix;
421 }
422 
BuildQueryFileSql(MediaLibraryCommand & cmd,vector<string> & selectionArgs,string & sql)423 static void BuildQueryFileSql(MediaLibraryCommand &cmd, vector<string> &selectionArgs, string &sql)
424 {
425     string groupBy = RemoveWhereSuffix(cmd, " GROUP BY ");
426     string having = RemoveWhereSuffix(cmd, " HAVING ");
427     string orderBy = RemoveWhereSuffix(cmd, " ORDER BY ");
428     string limit = RemoveWhereSuffix(cmd, " LIMIT ");
429 
430     sql = "SELECT ";
431     if (!groupBy.empty()) {
432         sql += "count(*),";
433     }
434     BuildQueryColumns(FILE_ASSET_COLUMNS, sql);
435 
436     sql += " FROM (";
437     BuildCompatQuerySql(cmd, PhotoColumn::PHOTOS_TABLE, PhotosCompatColumns(), selectionArgs, sql);
438     sql += " UNION ";
439     BuildCompatQuerySql(cmd, AudioColumn::AUDIOS_TABLE, AudiosCompatColumns(), selectionArgs, sql);
440     sql += " UNION ";
441     BuildCompatQuerySql(cmd, MEDIALIBRARY_TABLE, FilesCompatColumns(), selectionArgs, sql);
442     sql += ") ";
443 
444     if (!groupBy.empty()) {
445         sql += groupBy;
446     }
447     if (!having.empty()) {
448         sql += having;
449     }
450 
451     const string &order = cmd.GetAbsRdbPredicates()->GetOrder();
452     if ((!order.empty()) && (!orderBy.empty())) {
453         MEDIA_WARN_LOG("ORDER BY found both in whereClause and predicates, use the predicates one");
454         sql += " ORDER BY " + order;
455     } else if (!order.empty()) {
456         sql += " ORDER BY " + order;
457     } else if (!orderBy.empty()) {
458         sql += orderBy;
459     }
460 
461     if (!limit.empty()) {
462         sql += limit;
463     }
464 }
465 
CampatQueryDebug(const string & sql,const vector<string> & selectionArgs,const shared_ptr<MediaLibraryUnistore> & store)466 static void CampatQueryDebug(const string &sql, const vector<string> &selectionArgs,
467     const shared_ptr<MediaLibraryUnistore> &store)
468 {
469     constexpr int32_t printMax = 512;
470     for (size_t pos = 0; pos < sql.size(); pos += printMax) {
471         MEDIA_DEBUG_LOG("Quering file sql: %{public}s", sql.substr(pos, printMax).c_str());
472     }
473     for (const auto &arg : selectionArgs) {
474         MEDIA_DEBUG_LOG("Quering file, arg: %{public}s", arg.c_str());
475     }
476     auto resultSet = store->QuerySql(sql, selectionArgs);
477     if (resultSet == nullptr) {
478         MEDIA_ERR_LOG("Failed to query file!");
479         return;
480     }
481     int32_t count = -1;
482     int32_t err = resultSet->GetRowCount(count);
483     if (err != E_OK) {
484         MEDIA_ERR_LOG("Failed to get count, err: %{public}d", err);
485         return;
486     }
487     MEDIA_DEBUG_LOG("Quering file, count: %{public}d", count);
488 }
489 #endif
490 
QueryFileOperation(MediaLibraryCommand & cmd,const vector<string> & columns)491 shared_ptr<NativeRdb::ResultSet> MediaLibraryFileOperations::QueryFileOperation(
492     MediaLibraryCommand &cmd, const vector<string> &columns)
493 {
494     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
495     if (uniStore == nullptr) {
496         MEDIA_ERR_LOG("uniStore is nullptr");
497         return nullptr;
498     }
499 
500     string fileId = cmd.GetOprnFileId();
501     if (cmd.GetAbsRdbPredicates()->GetWhereClause().empty() && !fileId.empty()) {
502         cmd.GetAbsRdbPredicates()->EqualTo(MEDIA_DATA_DB_ID, fileId);
503     }
504 
505     if (START_PENDING) {
506         SolvePendingInQuery(cmd.GetAbsRdbPredicates());
507     }
508     string networkId = cmd.GetOprnDevice();
509     if (!networkId.empty()) {
510         std::vector<string> devices;
511         devices.push_back(networkId);
512         cmd.GetAbsRdbPredicates()->InDevices(devices);
513     }
514     MediaLibraryTracer tracer;
515     tracer.Start("QueryFile RdbStore->Query");
516 
517 #ifdef MEDIALIBRARY_COMPATIBILITY
518     string sql;
519     vector<string> selectionArgs;
520     BuildQueryFileSql(cmd, selectionArgs, sql);
521     CampatQueryDebug(sql, selectionArgs, uniStore);
522     return uniStore->QuerySql(sql, selectionArgs);
523 #else
524     return uniStore->Query(cmd, columns);
525 #endif
526 }
527 
CopyFileOperation(MediaLibraryCommand & cmd)528 int32_t MediaLibraryFileOperations::CopyFileOperation(MediaLibraryCommand &cmd)
529 {
530     auto values = cmd.GetValueBucket();
531     auto assetId = cmd.GetOprnFileId();
532     ValueObject valueObject;
533     string relativePath;
534     if (values.GetObject(MEDIA_DATA_DB_RELATIVE_PATH, valueObject)) {
535         valueObject.GetString(relativePath);
536     }
537     Uri srcUri(MEDIALIBRARY_DATA_URI + "/" + assetId);
538     string srcUriString = srcUri.ToString();
539     shared_ptr<FileAsset> srcFileAsset = MediaLibraryObjectUtils::GetFileAssetFromUri(srcUriString);
540     if (srcFileAsset == nullptr) {
541         return E_INVALID_URI;
542     }
543     if (srcFileAsset->GetMediaType() == MEDIA_TYPE_ALBUM) {
544         return MediaLibraryObjectUtils::CopyDir(srcFileAsset, relativePath);
545     } else {
546         return MediaLibraryObjectUtils::CopyAsset(srcFileAsset, relativePath);
547     }
548 }
549 } // namespace Media
550 } // namespace OHOS
551