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 #define MLOG_TAG "UserFileClientEx"
16 #include "userfile_client_ex.h"
17
18 #include <map>
19 #include <string>
20 #include <unordered_map>
21 #include <unistd.h>
22
23 #include "datashare_abs_result_set.h"
24 #include "datashare_predicates.h"
25 #include "directory_ex.h"
26 #include "iservice_registry.h"
27 #include "media_column.h"
28 #include "media_file_uri.h"
29 #include "media_file_utils.h"
30 #include "media_log.h"
31 #include "medialibrary_db_const.h"
32 #include "medialibrary_errno.h"
33 #include "mimetype_utils.h"
34 #include "scanner_utils.h"
35 #include "string_ex.h"
36 #include "system_ability_definition.h"
37 #include "thumbnail_const.h"
38 #include "uri.h"
39 #include "userfile_client.h"
40 #include "userfile_manager_types.h"
41
42 using namespace OHOS::DataShare;
43 namespace OHOS {
44 namespace Media {
45 namespace MediaTool {
46 const std::string URI_DELIMITER = std::string(1, SLASH_CHAR);
47 const std::string URI_ARG_FIRST_DELIMITER = "?";
48 const std::string URI_API_VERSION_STR = std::to_string(static_cast<uint32_t>(MediaLibraryApi::API_10));
49 const std::string URI_API_VERSION = URI_PARAM_API_VERSION + "=" + URI_API_VERSION_STR;
50
51 enum class MediaToolOperation {
52 INSERT,
53 QUERY,
54 CLOSE,
55 DELETE,
56 UPDATE,
57 LIST
58 };
59
60 const std::map<MediaToolOperation, std::string> PHOTOOPRN_URI_MAP = {
61 { MediaToolOperation::INSERT, TOOL_CREATE_PHOTO },
62 { MediaToolOperation::QUERY, TOOL_QUERY_PHOTO },
63 { MediaToolOperation::LIST, TOOL_LIST_PHOTO },
64 { MediaToolOperation::CLOSE, TOOL_CLOSE_PHOTO },
65 { MediaToolOperation::DELETE, TOOL_DELETE_PHOTO },
66 { MediaToolOperation::UPDATE, TOOL_UPDATE_PHOTO }
67 };
68
69 const std::map<MediaToolOperation, std::string> AUDIOOPRN_URI_MAP = {
70 { MediaToolOperation::INSERT, TOOL_CREATE_AUDIO },
71 { MediaToolOperation::QUERY, TOOL_QUERY_AUDIO },
72 { MediaToolOperation::LIST, TOOL_LIST_AUDIO },
73 { MediaToolOperation::CLOSE, TOOL_CLOSE_AUDIO },
74 { MediaToolOperation::DELETE, TOOL_DELETE_AUDIO },
75 { MediaToolOperation::UPDATE, TOOL_UPDATE_AUDIO }
76 };
77
GetOperation(const std::string & tableName,MediaToolOperation oprn)78 static std::string GetOperation(const std::string &tableName, MediaToolOperation oprn)
79 {
80 if (tableName == PhotoColumn::PHOTOS_TABLE) {
81 auto item = PHOTOOPRN_URI_MAP.find(oprn);
82 if (item != PHOTOOPRN_URI_MAP.end()) {
83 return item->second;
84 }
85 } else if (tableName == AudioColumn::AUDIOS_TABLE) {
86 auto item = AUDIOOPRN_URI_MAP.find(oprn);
87 if (item != AUDIOOPRN_URI_MAP.end()) {
88 return item->second;
89 }
90 }
91 MEDIA_ERR_LOG("get operation failed. tableName:%{public}s", tableName.c_str());
92 return "";
93 }
94
CheckTableName(const std::string & tableName)95 static bool CheckTableName(const std::string &tableName)
96 {
97 static const std::set<std::string> VALID_TABLENAME_WHITELIST = {
98 PhotoColumn::PHOTOS_TABLE,
99 AudioColumn::AUDIOS_TABLE
100 };
101 if (tableName.empty()) {
102 return false;
103 }
104 if (VALID_TABLENAME_WHITELIST.find(tableName) == VALID_TABLENAME_WHITELIST.end()) {
105 return false;
106 }
107 return true;
108 }
109
GetUriInfo(const std::string & uri,std::string & uriId)110 static inline bool GetUriInfo(const std::string &uri, std::string &uriId)
111 {
112 MediaFileUri fileUri(uri);
113 if (!fileUri.IsValid()) {
114 MEDIA_ERR_LOG("uri %{public}s is invalid", uri.c_str());
115 return false;
116 }
117 uriId = fileUri.GetFileId();
118 return true;
119 }
120
GetInsertUri(const std::string & tableName)121 static inline std::string GetInsertUri(const std::string &tableName)
122 {
123 std::string uri = GetOperation(tableName, MediaToolOperation::INSERT);
124 if (uri.empty()) {
125 MEDIA_ERR_LOG("get insert uri failed. tableName:%{public}s", tableName.c_str());
126 return uri;
127 }
128 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
129 return uri;
130 }
131
GetQueryUri(const std::string & tableName)132 static inline std::string GetQueryUri(const std::string &tableName)
133 {
134 std::string uri = GetOperation(tableName, MediaToolOperation::QUERY);
135 if (uri.empty()) {
136 MEDIA_ERR_LOG("get query uri failed. tableName:%{public}s", tableName.c_str());
137 return uri;
138 }
139 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
140 return uri;
141 }
142
GetListUri(const std::string & tableName)143 static inline std::string GetListUri(const std::string &tableName)
144 {
145 std::string uri = GetOperation(tableName, MediaToolOperation::LIST);
146 if (uri.empty()) {
147 MEDIA_ERR_LOG("get list uri failed. tableName:%{public}s", tableName.c_str());
148 return uri;
149 }
150 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
151 return uri;
152 }
153
GetCloseUri(const std::string & tableName)154 static inline std::string GetCloseUri(const std::string &tableName)
155 {
156 std::string uri = GetOperation(tableName, MediaToolOperation::CLOSE);
157 if (uri.empty()) {
158 MEDIA_ERR_LOG("get close uri failed. tableName:%{public}s", tableName.c_str());
159 return uri;
160 }
161 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
162 return uri;
163 }
164
GetUpdateUri(const std::string & tableName)165 static inline std::string GetUpdateUri(const std::string &tableName)
166 {
167 std::string uri = GetOperation(tableName, MediaToolOperation::UPDATE);
168 if (uri.empty()) {
169 MEDIA_ERR_LOG("get update uri failed. tableName:%{public}s", tableName.c_str());
170 return uri;
171 }
172 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
173 return uri;
174 }
175
GetDeleteUri(const std::string & tableName)176 static inline std::string GetDeleteUri(const std::string &tableName)
177 {
178 std::string uri = GetOperation(tableName, MediaToolOperation::DELETE);
179 if (uri.empty()) {
180 MEDIA_ERR_LOG("get delete uri failed. tableName:%{public}s", tableName.c_str());
181 return uri;
182 }
183 uri.append(URI_ARG_FIRST_DELIMITER + URI_API_VERSION);
184 return uri;
185 }
186
InitToken(const sptr<IRemoteObject> & token)187 static bool InitToken(const sptr<IRemoteObject> &token)
188 {
189 UserFileClient::Init(token);
190 return UserFileClient::IsValid();
191 }
192
Init()193 int32_t UserFileClientEx::Init()
194 {
195 auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
196 if (saManager == nullptr) {
197 MEDIA_ERR_LOG("get system ability mgr failed.");
198 return Media::E_ERR;
199 }
200 auto remoteObj = saManager->GetSystemAbility(STORAGE_MANAGER_MANAGER_ID);
201 if (remoteObj == nullptr) {
202 MEDIA_ERR_LOG("GetSystemAbility Service failed.");
203 return Media::E_ERR;
204 }
205 if (!InitToken(remoteObj)) {
206 MEDIA_ERR_LOG("set DataShareHelper failed.");
207 return Media::E_ERR;
208 }
209 return Media::E_OK;
210 }
211
Clear()212 void UserFileClientEx::Clear()
213 {
214 UserFileClient::Clear();
215 }
216
InsertExt(const std::string & tableName,const std::string & name,std::string & outString,bool isRestart)217 int32_t UserFileClientEx::InsertExt(const std::string &tableName, const std::string &name,
218 std::string &outString, bool isRestart)
219 {
220 if (isRestart && Init() != Media::E_OK) {
221 MEDIA_ERR_LOG("Init failed");
222 return Media::E_ERR;
223 }
224 std::string insertUriStr = GetInsertUri(tableName);
225 if (insertUriStr.empty()) {
226 MEDIA_ERR_LOG("insert failed. tableName:%{public}s, name:%{public}s", tableName.c_str(),
227 name.c_str());
228 return Media::E_ERR;
229 }
230 Uri insertUri(insertUriStr);
231 DataShare::DataShareValuesBucket values;
232 values.Put(MediaColumn::MEDIA_NAME, name);
233 string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(ScannerUtils::GetFileExtension(name));
234 values.Put(MediaColumn::MEDIA_TYPE, MimeTypeUtils::GetMediaTypeFromMimeType(mimeType));
235 values.Put(MediaColumn::MEDIA_OWNER_PACKAGE, "com.mediatool.album");
236 values.Put(MediaColumn::MEDIA_OWNER_APPID, "mediatool.appid");
237 values.Put(MediaColumn::MEDIA_PACKAGE_NAME, "mediatool");
238 MEDIA_INFO_LOG("insertext. insertUri:%{public}s, name:%{public}s", insertUri.ToString().c_str(), name.c_str());
239 auto ret = UserFileClient::InsertExt(insertUri, values, outString);
240 if (ret <= 0) {
241 MEDIA_ERR_LOG("insertext failed. ret:%{public}d", ret);
242 }
243 return ret;
244 }
245
Query(const std::string & tableName,const std::string & uri,std::shared_ptr<DataShare::DataShareResultSet> & resultSet,bool isRestart)246 int32_t UserFileClientEx::Query(const std::string &tableName, const std::string &uri,
247 std::shared_ptr<DataShare::DataShareResultSet> &resultSet, bool isRestart)
248 {
249 if (isRestart && Init() != Media::E_OK) {
250 MEDIA_ERR_LOG("Init failed");
251 return Media::E_ERR;
252 }
253 if (!CheckTableName(tableName)) {
254 MEDIA_ERR_LOG("tableName %{public}s is Invalid", tableName.c_str());
255 return Media::E_ERR;
256 }
257 resultSet = nullptr;
258 std::string id;
259 if ((!uri.empty()) && (!GetUriInfo(uri, id))) {
260 MEDIA_ERR_LOG("query failed, uri:%{public}s", uri.c_str());
261 return Media::E_ERR;
262 }
263 std::string queryUriStr = GetListUri(tableName);
264 if (queryUriStr.empty()) {
265 MEDIA_ERR_LOG("query failed. queryUriStr:empty, tableName:%{public}s", tableName.c_str());
266 return Media::E_ERR;
267 }
268 Uri queryUri(queryUriStr);
269 DataShare::DataSharePredicates predicates;
270 // Id is empty, meaning get all object from table
271 if (!id.empty()) {
272 predicates.And()->EqualTo(MediaColumn::MEDIA_ID, id);
273 }
274 std::vector<std::string> columns;
275 int errCode = 0;
276 MEDIA_INFO_LOG("query. queryUri:%{public}s, tableName:%{public}s, uri:%{public}s, "
277 "id:%{public}s", queryUri.ToString().c_str(), tableName.c_str(), uri.c_str(), id.c_str());
278 resultSet = UserFileClient::Query(queryUri, predicates, columns, errCode);
279 if (resultSet == nullptr) {
280 MEDIA_ERR_LOG("query failed. resultSet:null, errCode:%{public}d.", errCode);
281 return ((errCode == Media::E_OK) ? Media::E_OK : Media::E_ERR);
282 }
283 if (errCode != Media::E_OK) {
284 MEDIA_ERR_LOG("query failed. errCode:%{public}d.", errCode);
285 resultSet->Close();
286 return Media::E_ERR;
287 }
288 return Media::E_OK;
289 }
290
Open(const std::string & uri,const std::string & mode,bool isRestart)291 int UserFileClientEx::Open(const std::string &uri, const std::string &mode, bool isRestart)
292 {
293 if (isRestart && Init() != Media::E_OK) {
294 MEDIA_ERR_LOG("Init failed");
295 return Media::E_ERR;
296 }
297 if (uri.empty()) {
298 return Media::E_FAIL;
299 }
300 std::string uriWithKey {uri};
301 MediaFileUtils::UriAppendKeyValue(uriWithKey, IS_TOOL_OPEN,
302 TOOL_OPEN_TRUE);
303 Uri openUri(uriWithKey);
304 MEDIA_INFO_LOG("open. uri:%{public}s, mode:%{public}s", uriWithKey.c_str(), mode.c_str());
305 return UserFileClient::OpenFile(openUri, mode);
306 }
307
Close(const std::string & uri,const int fileFd,const std::string & mode,bool isCreateThumbSync,bool isRestart)308 int UserFileClientEx::Close(const std::string &uri, const int fileFd, const std::string &mode,
309 bool isCreateThumbSync, bool isRestart)
310 {
311 if (isRestart && Init() != Media::E_OK) {
312 MEDIA_ERR_LOG("Init failed");
313 return Media::E_ERR;
314 }
315 if (!UserFileClient::IsValid()) {
316 MEDIA_ERR_LOG("close failed. helper:null. uri:%{public}s, fileFd:%{public}d, mode:%{public}s",
317 uri.c_str(), fileFd, mode.c_str());
318 return Media::E_FAIL;
319 }
320 if (mode == Media::MEDIA_FILEMODE_READONLY) {
321 if (close(fileFd) != E_SUCCESS) {
322 MEDIA_ERR_LOG("close failed. uri:%{public}s, fileFd:%{public}d, mode:%{public}s",
323 uri.c_str(), fileFd, mode.c_str());
324 return Media::E_FAIL;
325 }
326 return Media::E_OK;
327 }
328 DataShare::DataShareValuesBucket valuesBucket;
329 valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
330 if (isCreateThumbSync) {
331 valuesBucket.Put(CLOSE_CREATE_THUMB_STATUS, CREATE_THUMB_SYNC_STATUS);
332 }
333 std::string closeUriStr = GetCloseUri(GetTableNameByUri(uri));
334 if (closeUriStr.empty()) {
335 MEDIA_ERR_LOG("get close uri failed. uri:%{public}s", uri.c_str());
336 return Media::E_FAIL;
337 }
338 Uri closeUri(closeUriStr);
339 MEDIA_INFO_LOG("close. closeUri:%{public}s, uri:%{public}s", closeUri.ToString().c_str(), uri.c_str());
340 auto ret = UserFileClient::Insert(closeUri, valuesBucket);
341 if (ret != Media::E_OK) {
342 MEDIA_ERR_LOG("close the file failed. ret:%{public}d, closeUri:%{public}s, uri:%{public}s",
343 ret, closeUri.ToString().c_str(), uri.c_str());
344 }
345 if (close(fileFd) != E_SUCCESS) {
346 MEDIA_ERR_LOG("close failed. uri:%{public}s, fileFd:%{public}d, mode:%{public}s",
347 uri.c_str(), fileFd, mode.c_str());
348 return Media::E_FAIL;
349 }
350 return ret;
351 }
352
Trash(const std::string & uri,bool isRestart)353 int32_t UserFileClientEx::Trash(const std::string &uri, bool isRestart)
354 {
355 if (isRestart && Init() != Media::E_OK) {
356 MEDIA_ERR_LOG("Init failed");
357 return Media::E_ERR;
358 }
359 if (!UserFileClient::IsValid()) {
360 MEDIA_ERR_LOG("close failed. helper:null.");
361 return Media::E_FAIL;
362 }
363 MediaFileUri fileUri(uri);
364 if (!fileUri.IsValid()) {
365 MEDIA_ERR_LOG("FileUri %{public}s is not Valid", uri.c_str());
366 return Media::E_FAIL;
367 }
368 string tableName = GetTableNameByUri(uri);
369 std::string trashUriStr = GetUpdateUri(tableName);
370 if (trashUriStr.empty()) {
371 MEDIA_ERR_LOG("get trash uri failed. uri:%{public}s", uri.c_str());
372 return Media::E_FAIL;
373 }
374
375 DataShare::DataShareValuesBucket valuesBucket;
376 valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
377 DataShare::DataSharePredicates predicates;
378 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
379 predicates.SetWhereArgs({ fileUri.GetFileId() });
380 Uri trashUri(trashUriStr);
381 MEDIA_INFO_LOG("trash. trashUri:%{public}s, uri:%{public}s", trashUri.ToString().c_str(), uri.c_str());
382 auto ret = UserFileClient::Update(trashUri, predicates, valuesBucket);
383 if (ret < 0) {
384 MEDIA_ERR_LOG("trash the file failed. ret:%{public}d, trashUri:%{public}s, uri:%{public}s",
385 ret, trashUri.ToString().c_str(), uri.c_str());
386 }
387 return ret;
388 }
389
Delete(const std::string & uri,bool isRestart)390 int32_t UserFileClientEx::Delete(const std::string &uri, bool isRestart)
391 {
392 if (isRestart && Init() != Media::E_OK) {
393 MEDIA_ERR_LOG("Init failed");
394 return Media::E_ERR;
395 }
396 if (!UserFileClient::IsValid()) {
397 MEDIA_ERR_LOG("close failed. helper:null.");
398 return Media::E_FAIL;
399 }
400 MediaFileUri fileUri(uri);
401 if (!fileUri.IsValid()) {
402 MEDIA_ERR_LOG("FileUri %{public}s is not Valid", uri.c_str());
403 return Media::E_FAIL;
404 }
405 string tableName = GetTableNameByUri(uri);
406 std::string deleteUriStr = GetDeleteUri(tableName);
407 if (deleteUriStr.empty()) {
408 MEDIA_ERR_LOG("get delete uri failed. uri:%{public}s", uri.c_str());
409 return Media::E_FAIL;
410 }
411
412 DataShare::DataSharePredicates predicates;
413 predicates.EqualTo(MediaColumn::MEDIA_ID, fileUri.GetFileId());
414 DataShare::DataShareValuesBucket valuesBucket;
415 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, 0);
416 Uri deleteUri(deleteUriStr);
417 MEDIA_INFO_LOG("delete. deleteUri:%{public}s, uri:%{public}s", deleteUri.ToString().c_str(), uri.c_str());
418 int ret = 0;
419 if (tableName == PhotoColumn::PHOTOS_TABLE) {
420 ret = UserFileClient::Update(deleteUri, predicates, valuesBucket);
421 } else if (tableName == AudioColumn::AUDIOS_TABLE) {
422 ret = UserFileClient::Delete(deleteUri, predicates);
423 } else {
424 MEDIA_ERR_LOG("invalid table name: %{public}s", tableName.c_str());
425 }
426
427 if (ret < 0) {
428 MEDIA_ERR_LOG("delete the file failed. ret:%{public}d, deleteUri:%{public}s, uri:%{public}s",
429 ret, deleteUri.ToString().c_str(), uri.c_str());
430 }
431 return ret;
432 }
433
Delete(bool isOnlyDeleteDb,bool isRestart)434 int32_t UserFileClientEx::Delete(bool isOnlyDeleteDb, bool isRestart)
435 {
436 if (isRestart && Init() != Media::E_OK) {
437 MEDIA_ERR_LOG("Init failed");
438 return Media::E_ERR;
439 }
440 if (!UserFileClient::IsValid()) {
441 MEDIA_ERR_LOG("close failed. helper:null.");
442 return Media::E_FAIL;
443 }
444 DataShare::DataShareValuesBucket valuesBucket;
445 valuesBucket.Put(DELETE_TOOL_ONLY_DATABASE, isOnlyDeleteDb);
446 std::string uri = URI_DELETE_TOOL;
447 Uri deleteUri(uri);
448 auto ret = UserFileClient::Insert(deleteUri, valuesBucket);
449 if (ret != Media::E_OK) {
450 MEDIA_ERR_LOG("Delete all Files in MediaLibrary failed, ret=%{public}d", ret);
451 }
452 return ret;
453 }
454
GetResultsetByDisplayName(const std::string & tableName,const std::string & displayName)455 std::shared_ptr<DataShare::DataShareResultSet> UserFileClientEx::GetResultsetByDisplayName(
456 const std::string &tableName, const std::string &displayName)
457 {
458 DataShare::DataSharePredicates predicates;
459 predicates.And()->EqualTo(MediaColumn::MEDIA_NAME, displayName);
460 std::vector<std::string> columns = { MediaColumn::MEDIA_FILE_PATH };
461 int queryErrCode = 0;
462 std::string queryUriStr = GetQueryUri(tableName);
463 if (queryUriStr.empty()) {
464 MEDIA_ERR_LOG("query failed. queryUriStr:empty, tableName:%{public}s", tableName.c_str());
465 }
466 Uri filesQueryUri(queryUriStr);
467 auto resultSet = UserFileClient::Query(filesQueryUri, predicates, columns, queryErrCode);
468 return resultSet;
469 }
470
GetTableNameByMediaType(const MediaType mediaType)471 std::string UserFileClientEx::GetTableNameByMediaType(const MediaType mediaType)
472 {
473 static const std::map<MediaType, std::string> TYPE_TABLE_MAP = {
474 { MediaType::MEDIA_TYPE_AUDIO, AudioColumn::AUDIOS_TABLE },
475 { MediaType::MEDIA_TYPE_IMAGE, PhotoColumn::PHOTOS_TABLE },
476 { MediaType::MEDIA_TYPE_VIDEO, PhotoColumn::PHOTOS_TABLE },
477 { MediaType::MEDIA_TYPE_PHOTO, PhotoColumn::PHOTOS_TABLE }
478 };
479 std::string tableName;
480 auto item = TYPE_TABLE_MAP.find(mediaType);
481 if (item != TYPE_TABLE_MAP.end()) {
482 tableName = item->second;
483 } else {
484 MEDIA_ERR_LOG("get table name failed. mediaType:%{public}d", mediaType);
485 }
486 return tableName;
487 }
488
GetTableNameByUri(const std::string & uri)489 std::string UserFileClientEx::GetTableNameByUri(const std::string &uri)
490 {
491 MediaFileUri fileUri(uri);
492 if (!fileUri.IsValid()) {
493 MEDIA_ERR_LOG("uri %{public}s is invalid", uri.c_str());
494 return "";
495 }
496 return fileUri.GetTableName();
497 }
498
GetSupportTypes()499 const std::vector<MediaType> &UserFileClientEx::GetSupportTypes()
500 {
501 static const std::vector<MediaType> SUPPORT_TYPES = {
502 MediaType::MEDIA_TYPE_AUDIO,
503 MediaType::MEDIA_TYPE_IMAGE,
504 MediaType::MEDIA_TYPE_VIDEO
505 };
506 return SUPPORT_TYPES;
507 }
508
GetSupportTables()509 const std::vector<std::string> &UserFileClientEx::GetSupportTables()
510 {
511 static const std::vector<std::string> SUPPORT_TABLES = {
512 PhotoColumn::PHOTOS_TABLE,
513 AudioColumn::AUDIOS_TABLE
514 };
515 return SUPPORT_TABLES;
516 }
517 } // namespace MediaTool
518 } // namespace Media
519 } // namespace OHOS
520