1 /*
2  * Copyright (C) 2021-2022 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 "medialibrary_uripermission_operations.h"
17 
18 #include <iostream>
19 #include <sstream>
20 #include <string>
21 #include <cstdint>
22 
23 #include "common_func.h"
24 #include "ipc_skeleton.h"
25 #include "medialibrary_bundle_manager.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_object_utils.h"
28 #include "medialibrary_type_const.h"
29 #include "media_file_utils.h"
30 #include "media_log.h"
31 #include "media_app_uri_permission_column.h"
32 #include "medialibrary_appstate_observer.h"
33 #include "medialibrary_rdb_transaction.h"
34 #include "media_library_manager.h"
35 #include "permission_utils.h"
36 #include "result_set_utils.h"
37 #include "rdb_utils.h"
38 
39 namespace OHOS {
40 namespace Media {
41 using namespace std;
42 using namespace OHOS::NativeRdb;
43 using namespace OHOS::DataShare;
44 using namespace OHOS::RdbDataShareAdapter;
45 
46 constexpr int32_t NO_DB_OPERATION = -1;
47 constexpr int32_t UPDATE_DB_OPERATION = 0;
48 constexpr int32_t INSERT_DB_OPERATION = 1;
49 constexpr int32_t PHOTOSTYPE = 1;
50 constexpr int32_t AUDIOSTYPE = 2;
51 
52 constexpr int32_t FILE_ID_INDEX = 0;
53 constexpr int32_t URI_TYPE_INDEX = 1;
54 constexpr int32_t PERMISSION_TYPE_INDEX = 2;
55 constexpr int32_t APP_ID_INDEX = 3;
56 
57 const string DB_OPERATION = "uriPermission_operation";
58 
CheckMode(string & mode)59 static bool CheckMode(string& mode)
60 {
61     transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
62     if (MEDIA_OPEN_MODES.find(mode) == MEDIA_OPEN_MODES.end()) {
63         MEDIA_ERR_LOG("mode format is error: %{private}s", mode.c_str());
64         return false;
65     }
66     string tempMode;
67     if (mode.find(MEDIA_FILEMODE_READONLY) != string::npos) {
68         tempMode += MEDIA_FILEMODE_READONLY;
69     }
70     if (mode.find(MEDIA_FILEMODE_WRITEONLY) != string::npos) {
71         tempMode += MEDIA_FILEMODE_WRITEONLY;
72     }
73     mode = tempMode;
74     return true;
75 }
76 
UpdateOperation(MediaLibraryCommand & cmd,std::shared_ptr<TransactionOperations> trans)77 int32_t UriPermissionOperations::UpdateOperation(MediaLibraryCommand &cmd,
78     std::shared_ptr<TransactionOperations> trans)
79 {
80     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
81     int32_t updateRows = -1;
82     int errCode;
83     if (trans == nullptr) {
84         auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
85         if (rdbStore == nullptr) {
86             MEDIA_ERR_LOG("UriPermission update operation, rdbStore is null.");
87             return E_HAS_DB_ERROR;
88         }
89         errCode = rdbStore->Update(cmd, updateRows);
90     } else {
91         errCode = trans->Update(cmd, updateRows);
92     }
93     if (errCode != NativeRdb::E_OK || updateRows < 0) {
94         MEDIA_ERR_LOG("UriPermission Update db failed, errCode = %{public}d", errCode);
95         return E_HAS_DB_ERROR;
96     }
97     return updateRows;
98 }
99 
DeleteAllTemporaryOperation(AsyncTaskData * data)100 static void DeleteAllTemporaryOperation(AsyncTaskData *data)
101 {
102     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
103     if (rdbStore == nullptr) {
104         MEDIA_ERR_LOG("UriPermission update operation, rdbStore is null.");
105     }
106     NativeRdb::RdbPredicates rdbPredicate(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
107     vector<string> permissionTypes;
108     permissionTypes.emplace_back(to_string(static_cast<int32_t>(PhotoPermissionType::TEMPORARY_READ_IMAGEVIDEO)));
109     permissionTypes.emplace_back(to_string(static_cast<int32_t>(PhotoPermissionType::TEMPORARY_WRITE_IMAGEVIDEO)));
110     permissionTypes.emplace_back(to_string(static_cast<int32_t>(PhotoPermissionType::TEMPORARY_READWRITE_IMAGEVIDEO)));
111     rdbPredicate.And()->In(AppUriPermissionColumn::PERMISSION_TYPE, permissionTypes);
112     int32_t ret = rdbStore->Delete(rdbPredicate);
113     if (ret < 0) {
114         MEDIA_ERR_LOG("UriPermission table delete all temporary permission failed");
115         return;
116     }
117     MEDIA_INFO_LOG("UriPermission table delete all %{public}d rows temporary permission success", ret);
118 }
119 
DeleteAllTemporaryAsync()120 void UriPermissionOperations::DeleteAllTemporaryAsync()
121 {
122     shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
123     if (asyncWorker == nullptr) {
124         MEDIA_ERR_LOG("Can not get asyncWorker");
125         return;
126     }
127     shared_ptr<MediaLibraryAsyncTask> notifyAsyncTask =
128         make_shared<MediaLibraryAsyncTask>(DeleteAllTemporaryOperation, nullptr);
129     if (notifyAsyncTask != nullptr) {
130         asyncWorker->AddTask(notifyAsyncTask, false);
131     } else {
132         MEDIA_ERR_LOG("Failed to create async task for UriPermission");
133     }
134 }
135 
DeleteOperation(MediaLibraryCommand & cmd)136 int32_t UriPermissionOperations::DeleteOperation(MediaLibraryCommand &cmd)
137 {
138     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
139     if (rdbStore == nullptr) {
140         MEDIA_ERR_LOG("UriPermission update operation, rdbStore is null.");
141         return E_HAS_DB_ERROR;
142     }
143     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
144     int32_t deleteRows = -1;
145     int32_t errCode = rdbStore->Delete(cmd, deleteRows);
146     if (errCode != NativeRdb::E_OK || deleteRows < 0) {
147         MEDIA_ERR_LOG("UriPermission delete db failed, errCode = %{public}d", errCode);
148         return E_HAS_DB_ERROR;
149     }
150     return static_cast<int32_t>(deleteRows);
151 }
152 
InsertOperation(MediaLibraryCommand & cmd)153 int32_t UriPermissionOperations::InsertOperation(MediaLibraryCommand &cmd)
154 {
155     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
156     if (rdbStore == nullptr) {
157         MEDIA_ERR_LOG("UriPermission insert operation, rdbStore is null.");
158         return E_HAS_DB_ERROR;
159     }
160     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
161     int64_t rowId = -1;
162     int32_t errCode = rdbStore->Insert(cmd, rowId);
163     if (errCode != NativeRdb::E_OK || rowId < 0) {
164         MEDIA_ERR_LOG("UriPermission insert db failed, errCode = %{public}d", errCode);
165         return E_HAS_DB_ERROR;
166     }
167     return static_cast<int32_t>(rowId);
168 }
169 
BatchInsertOperation(MediaLibraryCommand & cmd,const std::vector<ValuesBucket> & values,std::shared_ptr<TransactionOperations> trans)170 int32_t UriPermissionOperations::BatchInsertOperation(MediaLibraryCommand &cmd,
171     const std::vector<ValuesBucket> &values, std::shared_ptr<TransactionOperations> trans)
172 {
173     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
174     if (rdbStore == nullptr) {
175         MEDIA_ERR_LOG("UriPermission insert operation, rdbStore is null.");
176         return E_HAS_DB_ERROR;
177     }
178     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
179     int64_t outInsertNum = -1;
180     int32_t errCode;
181     if (trans == nullptr) {
182         errCode = rdbStore->BatchInsert(cmd, outInsertNum, values);
183     } else {
184         errCode = trans->BatchInsert(cmd, outInsertNum, values);
185     }
186     if (errCode != NativeRdb::E_OK || outInsertNum < 0) {
187         MEDIA_ERR_LOG("UriPermission Insert into db failed, errCode = %{public}d", errCode);
188         return E_HAS_DB_ERROR;
189     }
190     return static_cast<int32_t>(outInsertNum);
191 }
192 
QueryUriPermission(MediaLibraryCommand & cmd,const std::vector<DataShareValuesBucket> & values,std::shared_ptr<OHOS::NativeRdb::ResultSet> & resultSet)193 static void QueryUriPermission(MediaLibraryCommand &cmd, const std::vector<DataShareValuesBucket> &values,
194     std::shared_ptr<OHOS::NativeRdb::ResultSet> &resultSet)
195 {
196     vector<string> columns;
197     vector<string> predicateInColumns;
198     DataSharePredicates predicates;
199     bool isValid;
200     string appid = values.at(0).Get(AppUriPermissionColumn::APP_ID, isValid);
201     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
202     if (rdbStore == nullptr) {
203         MEDIA_ERR_LOG("UriPermission query operation, rdbStore is null.");
204         return;
205     }
206     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
207     for (const auto &val : values) {
208         predicateInColumns.push_back(static_cast<string>(val.Get(AppUriPermissionColumn::FILE_ID, isValid)));
209     }
210     predicates.In(AppUriPermissionColumn::FILE_ID, predicateInColumns);
211     predicates.And()->EqualTo(AppUriPermissionColumn::APP_ID, appid);
212     cmd.SetDataSharePred(predicates);
213     NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
214     cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
215     cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
216     resultSet = rdbStore->Query(cmd, columns);
217     return;
218 }
219 
CanConvertToInt32(const std::string & str)220 static bool CanConvertToInt32(const std::string &str)
221 {
222     std::istringstream iss(str);
223     int32_t num = 0;
224     iss >> num;
225     return iss.eof() && !iss.fail();
226 }
227 
GetFileId(const DataShareValuesBucket & values,bool & isValid)228 static int32_t GetFileId(const DataShareValuesBucket &values, bool &isValid)
229 {
230     int32_t ret = E_ERR;
231     string fileIdStr = static_cast<string>(values.Get(AppUriPermissionColumn::FILE_ID, isValid));
232     if (CanConvertToInt32(fileIdStr)) {
233         ret = static_cast<int32_t>(std::stoi(fileIdStr));
234     }
235     return ret;
236 }
237 
GetSingleDbOperation(const vector<DataShareValuesBucket> & values,vector<int32_t> & dbOperation,vector<int32_t> & querySingleResultSet,int index)238 static void GetSingleDbOperation(const vector<DataShareValuesBucket> &values, vector<int32_t> &dbOperation,
239     vector<int32_t> &querySingleResultSet, int index)
240 {
241     bool isValid;
242     int32_t fileId = GetFileId(values.at(index), isValid);
243     if (fileId == E_ERR) {
244         MEDIA_ERR_LOG("Failed GetFileId.");
245         return;
246     }
247     int32_t uriType = values.at(index).Get(AppUriPermissionColumn::URI_TYPE, isValid);
248     int32_t permissionType = values.at(index).Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
249     if ((fileId == querySingleResultSet.at(FILE_ID_INDEX)) && (uriType == querySingleResultSet.at(URI_TYPE_INDEX))) {
250         if ((querySingleResultSet.at(PERMISSION_TYPE_INDEX) == AppUriPermissionColumn::PERMISSION_PERSIST_READ_WRITE) ||
251             (permissionType == querySingleResultSet.at(PERMISSION_TYPE_INDEX))) {
252             dbOperation[index] = NO_DB_OPERATION;
253         } else {
254             dbOperation[index] = UPDATE_DB_OPERATION;
255         }
256     }
257 }
258 
GetMediafileQueryResult(const vector<string> & predicateInColumns,OperationObject object,std::vector<int32_t> & fileIdList)259 static void GetMediafileQueryResult(const vector<string>& predicateInColumns, OperationObject object,
260     std::vector<int32_t>& fileIdList)
261 {
262     MediaLibraryCommand queryCmd(object, OperationType::QUERY);
263     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
264     if (rdbStore == nullptr) {
265         MEDIA_ERR_LOG("UriPermission query operation, rdbStore is null.");
266         return;
267     }
268     vector<string> columns;
269     queryCmd.GetAbsRdbPredicates()->In(AppUriPermissionColumn::FILE_ID, predicateInColumns);
270     auto queryResult = rdbStore->Query(queryCmd, columns);
271     if ((queryResult == nullptr) || (queryResult->GoToFirstRow() != NativeRdb::E_OK)) {
272         MEDIA_INFO_LOG("UriPermission query result is null.");
273         return;
274     }
275     do {
276         fileIdList.push_back(GetInt32Val(AppUriPermissionColumn::FILE_ID, queryResult));
277     } while (!queryResult->GoToNextRow());
278 }
279 
FilterSameElementFromColumns(vector<string> & columns)280 static void FilterSameElementFromColumns(vector<string>& columns)
281 {
282     if (!columns.empty()) {
283         set<string> sec(columns.begin(), columns.end());
284         columns.assign(sec.begin(), sec.end());
285     }
286 }
287 
FilterNotExistUri(const std::vector<DataShareValuesBucket> & values,vector<int32_t> & dbOperation)288 static void FilterNotExistUri(const std::vector<DataShareValuesBucket> &values, vector<int32_t>& dbOperation)
289 {
290     vector<int32_t> photoFileIdList;
291     vector<int32_t> audioFileIdList;
292     vector<string> photosColumns;
293     vector<string> audioColumns;
294     bool isValid;
295     for (const auto &val : values) {
296         if (static_cast<int32_t>(val.Get(AppUriPermissionColumn::URI_TYPE, isValid)) == PHOTOSTYPE) {
297             photosColumns.push_back(val.Get(AppUriPermissionColumn::FILE_ID, isValid));
298         } else if (static_cast<int32_t>(val.Get(AppUriPermissionColumn::URI_TYPE, isValid)) == AUDIOSTYPE) {
299             audioColumns.push_back(val.Get(AppUriPermissionColumn::FILE_ID, isValid));
300         }
301     }
302     FilterSameElementFromColumns(photosColumns);
303     FilterSameElementFromColumns(audioColumns);
304     if (!photosColumns.empty()) {
305         GetMediafileQueryResult(photosColumns, OperationObject::FILESYSTEM_PHOTO, photoFileIdList);
306     }
307     if (!audioColumns.empty()) {
308         GetMediafileQueryResult(audioColumns, OperationObject::FILESYSTEM_AUDIO, audioFileIdList);
309     }
310     for (size_t i = 0; i < values.size(); i++) {
311         int32_t fileId = GetFileId(values.at(i), isValid);
312         int32_t uriType = values[i].Get(AppUriPermissionColumn::URI_TYPE, isValid);
313         if (uriType == PHOTOSTYPE) {
314             auto notExistIt = std::find(photoFileIdList.begin(), photoFileIdList.end(), fileId);
315             auto sameIt = std::find(photosColumns.begin(), photosColumns.end(), to_string(fileId));
316             if (notExistIt == photoFileIdList.end() || sameIt == photosColumns.end()) {
317                 dbOperation[i] = NO_DB_OPERATION;
318             }
319             if (sameIt != photosColumns.end()) {
320                 photosColumns.erase(sameIt);
321             }
322         } else if (uriType == AUDIOSTYPE) {
323             auto it = std::find(audioFileIdList.begin(), audioFileIdList.end(), fileId);
324             auto sameIt = std::find(audioColumns.begin(), audioColumns.end(), to_string(fileId));
325             if (it == audioFileIdList.end() || sameIt == audioColumns.end()) {
326                 dbOperation[i] = NO_DB_OPERATION;
327             }
328             if (sameIt != audioColumns.end()) {
329                 audioColumns.erase(sameIt);
330             }
331         }
332     }
333 }
334 
GetAllUriDbOperation(const vector<DataShareValuesBucket> & values,vector<int32_t> & dbOperation,std::shared_ptr<OHOS::NativeRdb::ResultSet> & queryResult)335 static void GetAllUriDbOperation(const vector<DataShareValuesBucket> &values, vector<int32_t> &dbOperation,
336     std::shared_ptr<OHOS::NativeRdb::ResultSet> &queryResult)
337 {
338     for (const auto &val : values) {
339         dbOperation.push_back(INSERT_DB_OPERATION);
340     }
341     if ((queryResult == nullptr) || (queryResult->GoToFirstRow() != NativeRdb::E_OK)) {
342         MEDIA_INFO_LOG("UriPermission query result is null.");
343         return;
344     }
345     do {
346         vector<int32_t> querySingleResultSet;
347         querySingleResultSet.push_back(GetInt32Val(AppUriPermissionColumn::FILE_ID, queryResult));
348         querySingleResultSet.push_back(GetInt32Val(AppUriPermissionColumn::URI_TYPE, queryResult));
349         querySingleResultSet.push_back(GetInt32Val(AppUriPermissionColumn::PERMISSION_TYPE, queryResult));
350         for (size_t i = 0; i < values.size(); i++) {
351             GetSingleDbOperation(values, dbOperation, querySingleResultSet, i);
352         }
353     } while (!queryResult->GoToNextRow());
354 }
355 
BatchUpdate(MediaLibraryCommand & cmd,std::vector<string> inColumn,int32_t tableType,const std::vector<DataShareValuesBucket> & values,std::shared_ptr<TransactionOperations> trans)356 static void BatchUpdate(MediaLibraryCommand &cmd, std::vector<string> inColumn, int32_t tableType,
357     const std::vector<DataShareValuesBucket> &values, std::shared_ptr<TransactionOperations> trans)
358 {
359     bool isValid;
360     DataShareValuesBucket valuesBucket;
361     int32_t permissionType = values.at(0).Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
362     valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
363     ValuesBucket valueBucket = RdbUtils::ToValuesBucket(valuesBucket);
364     if (valueBucket.IsEmpty()) {
365         MEDIA_ERR_LOG("MediaLibraryDataManager Insert: Input parameter is invalid");
366         return;
367     }
368 
369     DataSharePredicates predicates;
370     string appid = values.at(0).Get(AppUriPermissionColumn::APP_ID, isValid);
371     predicates.EqualTo(AppUriPermissionColumn::APP_ID, appid);
372     predicates.And()->EqualTo(AppUriPermissionColumn::URI_TYPE, to_string(tableType));
373     predicates.In(AppUriPermissionColumn::FILE_ID, inColumn);
374     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
375     cmd.SetValueBucket(valueBucket);
376     cmd.SetDataSharePred(predicates);
377 
378     NativeRdb::RdbPredicates rdbPredicate =
379         RdbUtils::ToPredicates(predicates, AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
380     cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
381     cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
382     UriPermissionOperations::UpdateOperation(cmd, trans);
383 }
384 
AppstateOberserverBuild(int32_t permissionType)385 static void AppstateOberserverBuild(int32_t permissionType)
386 {
387     if (permissionType != static_cast<int32_t>(PhotoPermissionType::PERSIST_READ_IMAGEVIDEO)) {
388         MedialibraryAppStateObserverManager::GetInstance().SubscribeAppState();
389     }
390 }
391 
ValueBucketCheck(const std::vector<DataShareValuesBucket> & values)392 static int32_t ValueBucketCheck(const std::vector<DataShareValuesBucket> &values)
393 {
394     bool isValidArr[] = {false, false, false, false};
395     if (values.empty()) {
396         return E_ERR;
397     }
398     for (const auto &val : values) {
399         val.Get(AppUriPermissionColumn::FILE_ID, isValidArr[FILE_ID_INDEX]);
400         val.Get(AppUriPermissionColumn::URI_TYPE, isValidArr[URI_TYPE_INDEX]);
401         val.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValidArr[PERMISSION_TYPE_INDEX]);
402         val.Get(AppUriPermissionColumn::APP_ID, isValidArr[APP_ID_INDEX]);
403         for (size_t i = 0; i < sizeof(isValidArr); i++) {
404             if ((isValidArr[i]) == false) {
405                 return E_ERR;
406             }
407         }
408     }
409     return E_OK;
410 }
411 
InsertValueBucketPrepare(const std::vector<DataShareValuesBucket> & values,int32_t fileId,int32_t uriType,std::vector<ValuesBucket> & batchInsertBucket)412 static void InsertValueBucketPrepare(const std::vector<DataShareValuesBucket> &values, int32_t fileId,
413     int32_t uriType, std::vector<ValuesBucket> &batchInsertBucket)
414 {
415     bool isValid;
416     ValuesBucket insertValues;
417     string appid = values.at(0).Get(AppUriPermissionColumn::APP_ID, isValid);
418     int32_t permissionType = values.at(0).Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
419     insertValues.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
420     insertValues.Put(AppUriPermissionColumn::FILE_ID, fileId);
421     insertValues.Put(AppUriPermissionColumn::APP_ID, appid);
422     insertValues.Put(AppUriPermissionColumn::URI_TYPE, uriType);
423     insertValues.Put(AppUriPermissionColumn::DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
424     batchInsertBucket.push_back(insertValues);
425 }
426 
GrantUriPermission(MediaLibraryCommand & cmd,const std::vector<DataShareValuesBucket> & values)427 int32_t UriPermissionOperations::GrantUriPermission(MediaLibraryCommand &cmd,
428     const std::vector<DataShareValuesBucket> &values)
429 {
430     std::vector<string> photosValues;
431     std::vector<string> audiosValues;
432     std::vector<int32_t> dbOperation;
433     std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet;
434     std::vector<ValuesBucket>  batchInsertBucket;
435     bool photoNeedToUpdate = false;
436     bool audioNeedToUpdate = false;
437     bool needToInsert = false;
438     bool isValid = false;
439     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
440     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
441     int32_t errCode = E_OK;
442     std::function<int(void)> func = [&]()->int {
443         if (photoNeedToUpdate) {
444             BatchUpdate(cmd, photosValues, PHOTOSTYPE, values, trans);
445         }
446         if (audioNeedToUpdate) {
447             BatchUpdate(cmd, audiosValues, AUDIOSTYPE, values, trans);
448         }
449         if (needToInsert) {
450             UriPermissionOperations::BatchInsertOperation(cmd, batchInsertBucket, trans);
451         }
452         return errCode;
453     };
454     errCode = trans->RetryTrans(func);
455     if (errCode != E_OK) {
456         MEDIA_ERR_LOG("GrantUriPermission: trans retry fail!, ret:%{public}d", errCode);
457     }
458     return E_OK;
459 }
460 
HandleUriPermOperations(MediaLibraryCommand & cmd)461 int32_t UriPermissionOperations::HandleUriPermOperations(MediaLibraryCommand &cmd)
462 {
463     if (!PermissionUtils::CheckIsSystemAppByUid()) {
464         MEDIA_ERR_LOG("the caller is not system app");
465         return E_PERMISSION_DENIED;
466     }
467     string bundleName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
468 
469     int32_t errCode = E_FAIL;
470     switch (cmd.GetOprnType()) {
471         case OperationType::INSERT_PERMISSION:
472             errCode = HandleUriPermInsert(cmd);
473             break;
474         default:
475             MEDIA_ERR_LOG("unknown operation type %{public}d", cmd.GetOprnType());
476             break;
477     }
478     return errCode;
479 }
480 
GetUriPermissionMode(const string & fileId,const string & bundleName,int32_t tableType,string & mode)481 int32_t UriPermissionOperations::GetUriPermissionMode(const string &fileId, const string &bundleName,
482     int32_t tableType, string &mode)
483 {
484     MediaLibraryCommand cmd(Uri(MEDIALIBRARY_BUNDLEPERM_URI), OperationType::QUERY);
485     cmd.GetAbsRdbPredicates()->EqualTo(PERMISSION_FILE_ID, fileId);
486     cmd.GetAbsRdbPredicates()->And()->EqualTo(PERMISSION_BUNDLE_NAME, bundleName);
487     cmd.GetAbsRdbPredicates()->And()->EqualTo(PERMISSION_TABLE_TYPE, to_string(tableType));
488     auto queryResult = MediaLibraryObjectUtils::QueryWithCondition(cmd, {}, "");
489     CHECK_AND_RETURN_RET_LOG(queryResult != nullptr, E_HAS_DB_ERROR, "Failed to obtain value from database");
490     int count = -1;
491     CHECK_AND_RETURN_RET_LOG(queryResult->GetRowCount(count) == NativeRdb::E_OK, E_HAS_DB_ERROR,
492         "Failed to get query result row count");
493     if (count <= 0) {
494         return E_PERMISSION_DENIED;
495     }
496     CHECK_AND_RETURN_RET_LOG(queryResult->GoToFirstRow() == NativeRdb::E_OK, E_HAS_DB_ERROR,
497         "Failed to go to first row");
498     mode = GetStringVal(PERMISSION_MODE, queryResult);
499     return E_SUCCESS;
500 }
501 
CheckUriPermValues(ValuesBucket & valuesBucket,int32_t & fileId,string & bundleName,int32_t & tableType,string & inputMode)502 static int32_t CheckUriPermValues(ValuesBucket &valuesBucket, int32_t &fileId, string &bundleName, int32_t &tableType,
503     string &inputMode)
504 {
505     ValueObject valueObject;
506     if (valuesBucket.GetObject(PERMISSION_FILE_ID, valueObject)) {
507         valueObject.GetInt(fileId);
508     } else {
509         MEDIA_ERR_LOG("ValueBucket does not have PERMISSION_FILE_ID");
510         return E_INVALID_VALUES;
511     }
512 
513     if (valuesBucket.GetObject(PERMISSION_BUNDLE_NAME, valueObject)) {
514         valueObject.GetString(bundleName);
515     } else {
516         MEDIA_ERR_LOG("ValueBucket does not have PERMISSION_BUNDLE_NAME");
517         return E_INVALID_VALUES;
518     }
519 
520     if (valuesBucket.GetObject(PERMISSION_MODE, valueObject)) {
521         valueObject.GetString(inputMode);
522     } else {
523         MEDIA_ERR_LOG("ValueBucket does not have PERMISSION_MODE");
524         return E_INVALID_VALUES;
525     }
526 
527     if (valuesBucket.GetObject(PERMISSION_TABLE_TYPE, valueObject)) {
528         valueObject.GetInt(tableType);
529     } else {
530         MEDIA_ERR_LOG("ValueBucket does not have PERMISSION_TABLE_TYPE");
531         return E_INVALID_VALUES;
532     }
533     if (!CheckMode(inputMode)) {
534         return E_INVALID_MODE;
535     }
536     valuesBucket.Delete(PERMISSION_MODE);
537     valuesBucket.PutString(PERMISSION_MODE, inputMode);
538     return E_SUCCESS;
539 }
540 
541 #ifdef MEDIALIBRARY_COMPATIBILITY
ConvertVirtualIdToRealId(ValuesBucket & valuesBucket,int32_t & fileId,int32_t tableType)542 static void ConvertVirtualIdToRealId(ValuesBucket &valuesBucket, int32_t &fileId, int32_t tableType)
543 {
544     if (tableType == static_cast<int32_t>(TableType::TYPE_PHOTOS)) {
545         fileId = MediaFileUtils::GetRealIdByTable(fileId, PhotoColumn::PHOTOS_TABLE);
546     } else if (tableType == static_cast<int32_t>(TableType::TYPE_AUDIOS)) {
547         fileId = MediaFileUtils::GetRealIdByTable(fileId, AudioColumn::AUDIOS_TABLE);
548     } else {
549         fileId = MediaFileUtils::GetRealIdByTable(fileId, MEDIALIBRARY_TABLE);
550     }
551 
552     valuesBucket.Delete(PERMISSION_FILE_ID);
553     valuesBucket.PutInt(PERMISSION_FILE_ID, fileId);
554 }
555 #endif
556 
557 
HandleUriPermInsert(MediaLibraryCommand & cmd)558 int32_t UriPermissionOperations::HandleUriPermInsert(MediaLibraryCommand &cmd)
559 {
560     int32_t fileId;
561     string bundleName;
562     string inputMode;
563     int32_t tableType;
564     ValuesBucket &valuesBucket = cmd.GetValueBucket();
565     auto ret = CheckUriPermValues(valuesBucket, fileId, bundleName, tableType, inputMode);
566     CHECK_AND_RETURN_RET(ret == E_SUCCESS, ret);
567 
568 #ifdef MEDIALIBRARY_COMPATIBILITY
569     if (cmd.GetApi() != MediaLibraryApi::API_10) {
570         ConvertVirtualIdToRealId(valuesBucket, fileId, tableType);
571     }
572 #endif
573 
574     string permissionMode;
575     ret = GetUriPermissionMode(to_string(fileId), bundleName, tableType, permissionMode);
576     if ((ret != E_SUCCESS) && (ret != E_PERMISSION_DENIED)) {
577         return ret;
578     }
579 
580     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
581     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "uniStore is nullptr!");
582 
583     if (ret == E_PERMISSION_DENIED) {
584         int64_t outRowId = -1;
585         return uniStore->Insert(cmd, outRowId);
586     }
587     if (permissionMode.find(inputMode) != string::npos) {
588         return E_SUCCESS;
589     }
590     ValuesBucket updateValues;
591     updateValues.PutString(PERMISSION_MODE, MEDIA_FILEMODE_READWRITE);
592     MediaLibraryCommand updateCmd(Uri(MEDIALIBRARY_BUNDLEPERM_URI), updateValues);
593     updateCmd.GetAbsRdbPredicates()->EqualTo(PERMISSION_FILE_ID, to_string(fileId))->And()->
594         EqualTo(PERMISSION_BUNDLE_NAME, bundleName);
595     int32_t updatedRows = -1;
596     return uniStore->Update(updateCmd, updatedRows);
597 }
598 
GetTableTypeFromTableName(const std::string & tableName)599 static inline int32_t GetTableTypeFromTableName(const std::string &tableName)
600 {
601     if (tableName == PhotoColumn::PHOTOS_TABLE) {
602         return static_cast<int32_t>(TableType::TYPE_PHOTOS);
603     } else if (tableName == AudioColumn::AUDIOS_TABLE) {
604         return static_cast<int32_t>(TableType::TYPE_AUDIOS);
605     } else {
606         return static_cast<int32_t>(TableType::TYPE_FILES);
607     }
608 }
609 
InsertBundlePermission(const int32_t & fileId,const std::string & bundleName,const std::string & mode,const std::string & tableName)610 int32_t UriPermissionOperations::InsertBundlePermission(const int32_t &fileId, const std::string &bundleName,
611     const std::string &mode, const std::string &tableName)
612 {
613     string curMode;
614     int32_t tableType = GetTableTypeFromTableName(tableName);
615     auto ret = GetUriPermissionMode(to_string(fileId), bundleName, tableType, curMode);
616     if ((ret != E_SUCCESS) && (ret != E_PERMISSION_DENIED)) {
617         return ret;
618     }
619     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
620     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "uniStore is nullptr!");
621     if (ret == E_PERMISSION_DENIED) {
622         ValuesBucket addValues;
623         addValues.PutInt(PERMISSION_FILE_ID, fileId);
624         addValues.PutString(PERMISSION_BUNDLE_NAME, bundleName);
625         addValues.PutString(PERMISSION_MODE, mode);
626         addValues.PutInt(PERMISSION_TABLE_TYPE, tableType);
627         MediaLibraryCommand cmd(Uri(MEDIALIBRARY_BUNDLEPERM_URI), addValues);
628         int64_t outRowId = -1;
629         return uniStore->Insert(cmd, outRowId);
630     }
631     if (curMode.find(mode) != string::npos) {
632         return E_SUCCESS;
633     }
634     ValuesBucket updateValues;
635     updateValues.PutString(PERMISSION_MODE, mode);
636     MediaLibraryCommand updateCmd(Uri(MEDIALIBRARY_BUNDLEPERM_URI), updateValues);
637     updateCmd.GetAbsRdbPredicates()->EqualTo(PERMISSION_FILE_ID, to_string(fileId))->And()->
638         EqualTo(PERMISSION_BUNDLE_NAME, bundleName)->And()->
639         EqualTo(PERMISSION_TABLE_TYPE, to_string(tableType));
640     int32_t updatedRows = -1;
641     return uniStore->Update(updateCmd, updatedRows);
642 }
643 
DeleteBundlePermission(const std::string & fileId,const std::string & bundleName,const std::string & tableName)644 int32_t UriPermissionOperations::DeleteBundlePermission(const std::string &fileId, const std::string &bundleName,
645     const std::string &tableName)
646 {
647     int32_t tableType = GetTableTypeFromTableName(tableName);
648 
649     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
650     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "uniStore is nullptr!");
651     Uri uri(MEDIALIBRARY_BUNDLEPERM_URI);
652     MediaLibraryCommand deleteCmd(uri);
653     deleteCmd.GetAbsRdbPredicates()->EqualTo(PERMISSION_FILE_ID, fileId)->And()->
654         EqualTo(PERMISSION_BUNDLE_NAME, bundleName)->And()->
655         EqualTo(PERMISSION_TABLE_TYPE, to_string(tableType));
656     int32_t deleteRows = -1;
657     int32_t ret = uniStore->Delete(deleteCmd, deleteRows);
658     if (deleteRows > 0 && ret == NativeRdb::E_OK) {
659         MEDIA_DEBUG_LOG("DeleteBundlePermission success:fileId:%{private}s, bundleName:%{private}s, table:%{private}s",
660             fileId.c_str(), bundleName.c_str(), tableName.c_str());
661         return E_OK;
662     }
663     return E_HAS_DB_ERROR;
664 }
665 
CheckUriPermission(const std::string & fileUri,std::string mode)666 int32_t UriPermissionOperations::CheckUriPermission(const std::string &fileUri, std::string mode)
667 {
668     if (!CheckMode(mode)) {
669         return E_INVALID_MODE;
670     }
671     string bundleName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
672     string fileId = MediaFileUtils::GetIdFromUri(fileUri);
673     TableType tableType = TableType::TYPE_FILES;
674     static map<string, TableType> tableMap = {
675         { MEDIALIBRARY_TYPE_IMAGE_URI, TableType::TYPE_PHOTOS },
676         { MEDIALIBRARY_TYPE_VIDEO_URI, TableType::TYPE_PHOTOS },
677         { MEDIALIBRARY_TYPE_AUDIO_URI, TableType::TYPE_AUDIOS },
678         { MEDIALIBRARY_TYPE_FILE_URI, TableType::TYPE_FILES },
679         { PhotoColumn::PHOTO_TYPE_URI, TableType::TYPE_PHOTOS },
680         { AudioColumn::AUDIO_TYPE_URI, TableType::TYPE_AUDIOS }
681     };
682     for (const auto &iter : tableMap) {
683         if (fileUri.find(iter.first) != string::npos) {
684             tableType = iter.second;
685         }
686     }
687     string permissionMode;
688     int32_t ret = GetUriPermissionMode(fileId, bundleName, static_cast<int32_t>(tableType), permissionMode);
689     CHECK_AND_RETURN_RET(ret == E_SUCCESS, ret);
690     return (permissionMode.find(mode) != string::npos) ? E_SUCCESS : E_PERMISSION_DENIED;
691 }
692 }   // Media
693 }   // OHOS