diff --git a/bundle.json b/bundle.json index 7fd57bc55d3c48845b356b3c5ec877735f1c9d21..8c64a721fb2002efd21b2b495c852c1a5ce71878 100644 --- a/bundle.json +++ b/bundle.json @@ -60,7 +60,8 @@ "//foundation/filemanagement/app_file_service/interfaces/kits/js:fileshare", "//foundation/filemanagement/app_file_service/interfaces/kits/js:fileuri", "//foundation/filemanagement/app_file_service/interfaces/kits/js:backup", - "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileuri/src:ohfileuri" + "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileuri/src:ohfileuri", + "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileshare/src:ohfileshare" ], "service_group": [ "//foundation/filemanagement/app_file_service:tgt_backup_extension", @@ -70,6 +71,15 @@ ] }, "inner_kits": [ + { + "name": "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileshare/src:ohfileshare", + "header": { + "header_files": [ + "oh_file_share.h" + ], + "header_base": "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileshare/include" + } + }, { "name": "//foundation/filemanagement/app_file_service/interfaces/innerkits/native:fileshare_native", "header": { diff --git a/interfaces/innerkits/native/file_share/include/file_permission.h b/interfaces/innerkits/native/file_share/include/file_permission.h index d563e234a3fc1770b1017917e372fa0e8998fafa..cb56798ab9777ebd029a5aba8a41e28f5dd5015a 100644 --- a/interfaces/innerkits/native/file_share/include/file_permission.h +++ b/interfaces/innerkits/native/file_share/include/file_permission.h @@ -29,6 +29,7 @@ using namespace std; #ifdef SANDBOX_MANAGER using namespace AccessControl::SandboxManager; #endif +constexpr const int32_t MAX_ARRAY_SIZE = 500; typedef enum OperationMode { READ_MODE = 1 << 0, WRITE_MODE = 1 << 1, @@ -43,6 +44,7 @@ enum PolicyErrorCode { PERSISTENCE_FORBIDDEN = 1, INVALID_MODE = 2, INVALID_PATH = 3, + PERMISSION_NOT_PERSISTED = 4, }; struct UriPolicyInfo { @@ -71,13 +73,17 @@ public: deque &errorResults); static int32_t DeactivatePermission(const vector &uriPolicies, deque &errorResults); + static int32_t CheckPersistentPermission(const vector &uriPolicies, vector &errorResults); #ifdef SANDBOX_MANAGER private: static void ParseErrorResults(const vector &resultCodes, - const vector &pathPolicies, - deque &errorResults); + const vector &pathPolicies, + deque &errorResults); + static void ParseErrorResults(const vector &resultCodes, vector &errorResults); static vector GetPathPolicyInfoFromUriPolicyInfo(const vector &uriPolicies, - deque &errorResults); + deque &errorResults); + static vector GetPathPolicyInfoFromUriPolicyInfo(const vector &uriPolicies, + vector &errorResults); #endif }; } // namespace AppFileService diff --git a/interfaces/innerkits/native/file_share/src/file_permission.cpp b/interfaces/innerkits/native/file_share/src/file_permission.cpp index dbcd11f9f8d5c497639b23330c897428dca0e753..25dd7932134cc36421ed1aff4ad834d7383f2c31 100644 --- a/interfaces/innerkits/native/file_share/src/file_permission.cpp +++ b/interfaces/innerkits/native/file_share/src/file_permission.cpp @@ -34,6 +34,7 @@ const std::string NETWORK_PARA = "?networkid="; const std::string PERSISTENCE_FORBIDDEN_MESSAGE = "URI forbid to be persisted!"; const std::string INVALID_MODE_MESSAGE = "Invalid operation mode!"; const std::string INVALID_PATH_MESSAGE = "Invalid path!"; +const std::string PERMISSION_NOT_PERSISTED_MESSAGE = "The policy is no persistent capability!"; const std::string FILE_SCHEME_PREFIX = "file://"; #ifdef SANDBOX_MANAGER @@ -88,6 +89,18 @@ int32_t ErrorCodeConversion(int32_t sandboxManagerErrorCode, } return FileManagement::LibN::E_UNKNOWN_ERROR; } + +int32_t ErrorCodeConversion(int32_t sandboxManagerErrorCode) +{ + if (sandboxManagerErrorCode == SANDBOX_MANAGER_OK) { + return 0; + } + if (sandboxManagerErrorCode == PERMISSION_DENIED) { + LOGE("The app does not have the authorization URI permission"); + return FileManagement::LibN::E_PERMISSION; + } + return FileManagement::LibN::E_UNKNOWN_ERROR; +} } // namespace void FilePermission::ParseErrorResults(const vector &resultCodes, const vector &pathPolicies, @@ -109,19 +122,37 @@ void FilePermission::ParseErrorResults(const vector &resultCodes, result = {uri.ToString(), PolicyErrorCode::INVALID_PATH, INVALID_PATH_MESSAGE}; errorResults.emplace_back(result); break; + case static_cast(PolicyErrorCode::PERMISSION_NOT_PERSISTED): + result = {uri.ToString(), PolicyErrorCode::PERMISSION_NOT_PERSISTED, PERMISSION_NOT_PERSISTED_MESSAGE}; + errorResults.emplace_back(result); + break; default: break; } } } +void FilePermission::ParseErrorResults(const vector &resultCodes, vector &errorResults) +{ + auto resultCodeSize = resultCodes.size(); + if (resultCodeSize == 0) { + return; + } + auto errorResultSize = errorResults.size(); + for (size_t i = 0, j = 0; i < errorResultSize && j < resultCodeSize; i++) { + if (errorResults[i]) { + errorResults[i] = resultCodes[j++]; + } + } +} + vector FilePermission::GetPathPolicyInfoFromUriPolicyInfo(const vector &uriPolicies, deque &errorResults) { vector pathPolicies; for (auto uriPolicy : uriPolicies) { Uri uri(uriPolicy.uri); - string path = uri.GetPath(); + string path = SandboxHelper::Decode(uri.GetPath()); if (!CheckValidUri(uriPolicy.uri) || access(path.c_str(), F_OK) != 0) { LOGE("Not correct uri!"); PolicyErrorResult result = {uriPolicy.uri, PolicyErrorCode::INVALID_PATH, INVALID_PATH_MESSAGE}; @@ -130,10 +161,39 @@ vector FilePermission::GetPathPolicyInfoFromUriPolicyInfo(const vect string currentUserId = to_string(IPCSkeleton::GetCallingTokenID() / AppExecFwk::Constants::BASE_USER_RANGE); int32_t ret = SandboxHelper::GetPhysicalPath(uri.ToString(), currentUserId, path); if (ret != 0) { + PolicyErrorResult result = {uriPolicy.uri, PolicyErrorCode::INVALID_PATH, INVALID_PATH_MESSAGE}; + errorResults.emplace_back(result); + LOGE("Failed to get physical path, errorcode: %{public}d", ret); + continue; + } + PolicyInfo policyInfo = {path, uriPolicy.mode}; + pathPolicies.emplace_back(policyInfo); + } + } + return pathPolicies; +} + +vector FilePermission::GetPathPolicyInfoFromUriPolicyInfo(const vector &uriPolicies, + vector &errorResults) +{ + vector pathPolicies; + for (const auto &uriPolicy : uriPolicies) { + Uri uri(uriPolicy.uri); + string path = SandboxHelper::Decode(uri.GetPath()); + if (!CheckValidUri(uriPolicy.uri) || access(path.c_str(), F_OK) != 0) { + LOGE("Not correct uri!"); + errorResults.emplace_back(false); + } else { + string currentUserId = to_string(IPCSkeleton::GetCallingTokenID() / AppExecFwk::Constants::BASE_USER_RANGE); + int32_t ret = SandboxHelper::GetPhysicalPath(uri.ToString(), currentUserId, path); + if (ret != 0) { + errorResults.emplace_back(false); LOGE("Failed to get physical path, errorcode: %{public}d", ret); + continue; } PolicyInfo policyInfo = {path, uriPolicy.mode}; pathPolicies.emplace_back(policyInfo); + errorResults.emplace_back(true); } } return pathPolicies; @@ -202,5 +262,22 @@ int32_t FilePermission::DeactivatePermission(const vector &uriPol #endif return errorCode; } + +int32_t FilePermission::CheckPersistentPermission(const vector &uriPolicies, vector &errorResults) +{ + int errorCode = 0; +#ifdef SANDBOX_MANAGER + vector pathPolicies = GetPathPolicyInfoFromUriPolicyInfo(uriPolicies, errorResults); + if (pathPolicies.size() == 0) { + return errorCode; + } + vector resultCodes; + auto tokenId = IPCSkeleton::GetCallingTokenID(); + int32_t sandboxManagerErrorCode = SandboxManagerKit::CheckPersistPolicy(tokenId, pathPolicies, resultCodes); + errorCode = ErrorCodeConversion(sandboxManagerErrorCode); + ParseErrorResults(resultCodes, errorResults); +#endif + return errorCode; +} } // namespace AppFileService } // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/file_share/fileshare_n_exporter.cpp b/interfaces/kits/js/file_share/fileshare_n_exporter.cpp index ad07413aeb2552420befbb4e970b5f0c7b4b19b7..8502be925409d6e3d79a1e1565394695b763c9cf 100644 --- a/interfaces/kits/js/file_share/fileshare_n_exporter.cpp +++ b/interfaces/kits/js/file_share/fileshare_n_exporter.cpp @@ -39,6 +39,7 @@ napi_value FileShareExport(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("revokePermission", RevokePermission), DECLARE_NAPI_FUNCTION("activatePermission", ActivatePermission), DECLARE_NAPI_FUNCTION("deactivatePermission", DeactivatePermission), + DECLARE_NAPI_FUNCTION("checkPersistentPermission", CheckPersistentPermission), }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; diff --git a/interfaces/kits/js/file_share/grant_permissions.cpp b/interfaces/kits/js/file_share/grant_permissions.cpp index 411e0c46077b3c236e9c648d291aa1a6c2a97019..3bc1a3f4a633e42195193552ffcf3b4f7267a30f 100644 --- a/interfaces/kits/js/file_share/grant_permissions.cpp +++ b/interfaces/kits/js/file_share/grant_permissions.cpp @@ -20,6 +20,7 @@ #include "access_token.h" #include "accesstoken_kit.h" #include "ipc_skeleton.h" +#include "js_native_api.h" #include "log.h" #include "n_napi.h" #include "parameter.h" @@ -78,6 +79,27 @@ static napi_value GetErrData(napi_env env, deque &erro return res; } +static napi_value GetResultData(napi_env env, vector &results) +{ + napi_value res = nullptr; + napi_status status = napi_create_array(env, &res); + if (status != napi_ok) { + LOGE("Failed to create array"); + return nullptr; + } + size_t index = 0; + for (const auto &iter : results) { + napi_value value; + napi_get_boolean(env, iter, &value); + status = napi_set_element(env, res, index++, value); + if (status != napi_ok) { + LOGE("Failed to set element on data"); + return nullptr; + } + } + return res; +} + static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector &uriPolicies) { uint32_t count; @@ -86,6 +108,10 @@ static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector< LOGE("get array length failed"); return status; } + if (count > MAX_ARRAY_SIZE) { + LOGE("The length of the array is extra-long"); + return napi_invalid_arg; + } for (uint32_t i = 0; i < count; i++) { napi_handle_scope scope; status = napi_open_handle_scope(env, &scope); @@ -98,7 +124,6 @@ static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector< LOGE("get element failed"); return status; } - UriPolicyInfo uriPolicy; napi_value uriValue; napi_value modeValue; status = napi_get_named_property(env, object, "uri", &uriValue); @@ -117,8 +142,7 @@ static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector< LOGE("the argument error"); return napi_invalid_arg; } - uriPolicy.uri = str.get(); - uriPolicy.mode = mode; + UriPolicyInfo uriPolicy {.uri = str.get(), .mode = mode}; uriPolicies.emplace_back(uriPolicy); status = napi_close_handle_scope(env, scope); if (status != napi_ok) { @@ -319,6 +343,50 @@ napi_value DeactivatePermission(napi_env env, napi_callback_info info) NVal thisVar(env, funcArg.GetThisVar()); return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_; } + +napi_value CheckPersistentPermission(napi_env env, napi_callback_info info) +{ + if (!CheckFileManagerFullMountEnable()) { + LOGE("The device doesn't support this api"); + NError(E_DEVICENOTSUPPORT).ThrowErr(env); + return nullptr; + } + if (!CheckPermission(FILE_ACCESS_PERMISSION)) { + LOGE("PersistPermission has not ohos permission!"); + NError(E_PERMISSION).ThrowErr(env); + return nullptr; + } + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + LOGE("ActivatePermission Number of arguments unmatched"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + std::vector uriPolicies; + if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) { + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + shared_ptr arg = make_shared(); + if (arg == nullptr) { + NError(EILSEQ).ThrowErr(env); + return nullptr; + } + auto cbExec = [uriPolicies, arg]() -> NError { + arg->errNo = FilePermission::CheckPersistentPermission(uriPolicies, arg->resultData); + return NError(arg->errNo); + }; + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (arg->errNo != 0) { + return {env, err.GetNapiErr(env)}; + } + return {env, GetResultData(env, arg->resultData)}; + }; + const string procedureName = "check_persist_permission"; + NVal thisVar(env, funcArg.GetThisVar()); + return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_; +} + } // namespace ModuleFileShare } // namespace AppFileService } // namespace OHOS diff --git a/interfaces/kits/js/file_share/grant_permissions.h b/interfaces/kits/js/file_share/grant_permissions.h index c025a4b77bbba7c1c6322ce03604cbf3da855bbf..285033667496d37b4e8883c309edf06bb82d72aa 100644 --- a/interfaces/kits/js/file_share/grant_permissions.h +++ b/interfaces/kits/js/file_share/grant_permissions.h @@ -28,12 +28,19 @@ napi_value PersistPermission(napi_env env, napi_callback_info info); napi_value RevokePermission(napi_env env, napi_callback_info info); napi_value ActivatePermission(napi_env env, napi_callback_info info); napi_value DeactivatePermission(napi_env env, napi_callback_info info); +napi_value CheckPersistentPermission(napi_env env, napi_callback_info info); struct PolicyErrorArgs { deque errorResults; int32_t errNo = 0; ~PolicyErrorArgs() = default; }; + +struct PolicyInfoResultArgs { + vector resultData; + int32_t errNo = 0; + ~PolicyInfoResultArgs() = default; +}; } // namespace ModuleFileShare } // namespace AppFileService } // namespace OHOS diff --git a/interfaces/kits/ndk/fileshare/BUILD.gn b/interfaces/kits/ndk/fileshare/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..eb0851c778bf357f29c668022a18f1368489a4e6 --- /dev/null +++ b/interfaces/kits/ndk/fileshare/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("//build/ohos/ndk/ndk.gni") + +ohos_ndk_library("libohfileshare") { + ndk_description_file = "./libfile_share.ndk.json" + min_compact_version = "12" + output_name = "ohfileshare" + output_extension = "so" + system_capability = + "SystemCapability.FileManagement.AppFileService.FolderAuthorization" + system_capability_headers = + [ "$ndk_headers_out_dir/filemanagement/fileshare/oh_file_share.h" ] +} + +ohos_ndk_headers("oh_file_share_header") { + dest_dir = "$ndk_headers_out_dir/filemanagement/fileshare/" + sources = [ + "../fileio/include/error_code.h", + "./include/oh_file_share.h", + ] +} diff --git a/interfaces/kits/ndk/fileshare/include/error_code.h b/interfaces/kits/ndk/fileshare/include/error_code.h new file mode 100644 index 0000000000000000000000000000000000000000..7f28cd7a565321b703ec8b63c3323c232e9908d1 --- /dev/null +++ b/interfaces/kits/ndk/fileshare/include/error_code.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILEMANAGEMENT_APP_FILE_SERVICE_INTERFACES_FILE_SHARE_ERROR_CODE_H +#define FILEMANAGEMENT_APP_FILE_SERVICE_INTERFACES_FILE_SHARE_ERROR_CODE_H + +enum FileManagement_ErrCode { + E_NO_ERROR = 0, + E_PERMISSION = 201, + E_PARAMS = 401, + E_DEVICE_NOT_SUPPORT = 801, + E_EPERM = 13900001, + E_ENOMEM = 13900011, + E_UNKNOWN_ERROR = 13900042 +}; + +#endif // FILEMANAGEMENT_APP_FILE_SERVICE_INTERFACES_FILE_SHARE_ERROR_CODE_H \ No newline at end of file diff --git a/interfaces/kits/ndk/fileshare/include/oh_file_share.h b/interfaces/kits/ndk/fileshare/include/oh_file_share.h new file mode 100644 index 0000000000000000000000000000000000000000..821336be5772181da11a7ccdd7ce22271f47104b --- /dev/null +++ b/interfaces/kits/ndk/fileshare/include/oh_file_share.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILE_MANAGEMENT_OH_FILE_SHARE_H +#define FILE_MANAGEMENT_OH_FILE_SHARE_H + +#include "error_code.h" + +/** + * @addtogroup fileShare + * @{ + * + * @brief This module provides file sharing capabilities to authorize Uniform Resource Identifiers (URIs) + * for public directory files that have read and write access to other applications. + * @since 12 + */ + +/** + * @file oh_file_share.h + * + * @brief Provides URI-based file and directory authorization and persistence, permission activation, permission query, + * and other methods. + * @library libohfileshare.so + * @syscap SystemCapability.FileManagement.AppFileService.FolderAuthorization + * @since 12 + */ +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Enumerates the uri operate mode types. + * + * @since 12 + */ +typedef enum FileShare_OperationMode { + /** + * @brief Indicates read permissions. + */ + READ_MODE = 1 << 0, + + /** + * @brief Indicates write permissions. + */ + WRITE_MODE = 1 << 1 +} FileShare_OperationMode; + +/** + * @brief Enumerates the error code of the permission policy for the URI operation. + * + * @since 12 + */ +typedef enum FileShare_PolicyErrorCode { + /** + * @brief Indicates that the policy is not allowed to be persisted. + */ + PERSISTENCE_FORBIDDEN = 1, + + /** + * @brief Indicates that the mode of this policy is invalid. + */ + INVALID_MODE = 2, + + /** + * @brief Indicates that the path of this policy is invalid. + */ + INVALID_PATH = 3, + + /** + * @brief Indicates that the policy is no persistent capability. + */ + PERMISSION_NOT_PERSISTED = 4 +} FileShare_PolicyErrorCode; + +/** + * @brief Define the FileShare_PolicyErrorResult structure type. + * + * Failed policy result on URI. + * + * @since 12 + */ +typedef struct FileShare_PolicyErrorResult { + /** + * Indicates the failed uri of the policy information. + */ + char *uri; + + /** + * Indicates the error code of the failure in the policy information. + */ + FileShare_PolicyErrorCode code; + + /** + * Indicates the reason of the failure in the policy information. + */ + char *message; +} FileShare_PolicyErrorResult; + +/** + * @brief Define the FileShare_PolicyInfo structure type. + * + * Policy information to manager permissions on a URI. + * + * @since 12 + */ +typedef struct FileShare_PolicyInfo { + /** + * Indicates the uri of the policy information. + */ + char *uri; + + /** + * Indicates The length of the uri. + */ + unsigned int length; + + /** + * Indicates the mode of operation for the URI. + * example { FileShare_OperationMode.READ_MODE } or { FileShare_OperationMode.READ_MODE | + * FileShare_OperationMode.WRITE_MODE }. + */ + unsigned int operationMode; +} FileShare_PolicyInfo; + +/** + * @brief Set persistent permissions for the URI. + * + * @permission ohos.permission.FILE_ACCESS_PERSIST + * @param policies Input a pointer to an {@link FileShare_PolicyInfo} instance. + * @param policyNum Indicates the size of the policies array. + * @param result Output a pointer to an {@link FileShare_PolicyErrorResult} instance. Please use + * OH_FileShare_ReleasePolicyErrorResult() to clear Resource. + * @param resultNum Output the size of the result array. + * @return Returns the status code of the execution. + * @since 12 + */ +FileManagement_ErrCode OH_FileShare_PersistPermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum); + +/** + * @brief Revoke persistent permissions for the URI. + * + * @permission ohos.permission.FILE_ACCESS_PERSIST + * @param policies Input a pointer to an {@link FileShare_PolicyInfo} instance. + * @param policyNum Indicates the size of the policies array. + * @param result Output a pointer to an {@link FileShare_PolicyErrorResult} instance. Please use + * OH_FileShare_ReleasePolicyErrorResult() to clear Resource. + * @param resultNum Output the size of the result array. + * @return Returns the status code of the execution. + * @since 12 + */ +FileManagement_ErrCode OH_FileShare_RevokePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum); + +/** + * @brief Enable the URI that have been permanently authorized. + * + * @permission ohos.permission.FILE_ACCESS_PERSIST + * @param policies Input a pointer to an {@link FileShare_PolicyInfo} instance. + * @param policyNum Indicates the size of the policies array. + * @param result Output a pointer to an {@link FileShare_PolicyErrorResult} instance. Please use + * OH_FileShare_ReleasePolicyErrorResult() to clear Resource. + * @param resultNum Output the size of the result array. + * @return Returns the status code of the execution. + * @since 12 + */ +FileManagement_ErrCode OH_FileShare_ActivatePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum); + +/** + * @brief Stop the authorized URI that has been enabled. + * + * @permission ohos.permission.FILE_ACCESS_PERSIST + * @param policies Input a pointer to an {@link FileShare_PolicyInfo} instance. + * @param policyNum Indicates the size of the policies array. + * @param result Output a pointer to an {@link FileShare_PolicyErrorResult} instance. Please use + * OH_FileShare_ReleasePolicyErrorResult() to clear Resource. + * @param resultNum Output the size of the result array. + * @return Returns the status code of the execution. + * @since 12 + */ +FileManagement_ErrCode OH_FileShare_DeactivatePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum); + +/** + * @brief Check persistent permissions for the URI. + * + * @permission ohos.permission.FILE_ACCESS_PERSIST + * @param policies Input a pointer to an {@link FileShare_PolicyInfo} instance. + * @param policyNum Indicates the size of the policies array. + * @param result Output a pointer to an bool instance. Please use free() to clear Resource. + * @param resultNum Output the size of the result array. + * @return Returns the status code of the execution. + * @since 12 + */ +FileManagement_ErrCode OH_FileShare_CheckPersistentPermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + bool **result, + unsigned int *resultNum); + +/** + * @brief Free FileShare_PolicyErrorResult pointer points to address memory. + * + * @param errorResult Input a pointer to an {@link FileShare_PolicyErrorResult} instance. + * @param resultNum Indicates the size of the errorResult array. + * @since 12 + */ +void OH_FileShare_ReleasePolicyErrorResult(FileShare_PolicyErrorResult *errorResult, unsigned int resultNum); +#ifdef __cplusplus +}; +#endif +/** @} */ +#endif // FILE_MANAGEMENT_OH_FILE_SHARE_H diff --git a/interfaces/kits/ndk/fileshare/libfile_share.ndk.json b/interfaces/kits/ndk/fileshare/libfile_share.ndk.json new file mode 100644 index 0000000000000000000000000000000000000000..fb133d6bd6e0f1c1e3cda248c50f2fdff631cf8c --- /dev/null +++ b/interfaces/kits/ndk/fileshare/libfile_share.ndk.json @@ -0,0 +1,26 @@ +[ + { + "first_introduced": "12", + "name": "OH_FileShare_PersistPermission" + }, + { + "first_introduced": "12", + "name": "OH_FileShare_RevokePermission" + }, + { + "first_introduced": "12", + "name": "OH_FileShare_ActivatePermission" + }, + { + "first_introduced": "12", + "name": "OH_FileShare_DeactivatePermission" + }, + { + "first_introduced": "12", + "name": "OH_FileShare_CheckPersistPermission" + }, + { + "first_introduced": "12", + "name": "OH_FileShare_ReleasePolicyErrorResult" + } +] \ No newline at end of file diff --git a/interfaces/kits/ndk/fileshare/src/BUILD.gn b/interfaces/kits/ndk/fileshare/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5b3755cd5fd2cda4b345487b5c06fb037080f41c --- /dev/null +++ b/interfaces/kits/ndk/fileshare/src/BUILD.gn @@ -0,0 +1,49 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/app_file_service.gni") + +ohos_shared_library("ohfileshare") { + stack_protector_ret = true + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "../include", + "${app_file_service_path}/interfaces/innerkits/native/file_share/include/", + "${app_file_service_path}/interfaces/common/include/", + ] + + sources = [ "oh_file_share.cpp" ] + deps = [ + "${app_file_service_path}/interfaces/innerkits/native:fileshare_native", + ] + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "hilog:libhilog", + "init:libbegetutil", + "ipc:ipc_core", + ] + output_extension = "so" + relative_install_dir = "ndk" + part_name = "app_file_service" + subsystem_name = "filemanagement" +} diff --git a/interfaces/kits/ndk/fileshare/src/oh_file_share.cpp b/interfaces/kits/ndk/fileshare/src/oh_file_share.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64da424b59fb0e6594b6cbc57cd1c01d14b5c4d9 --- /dev/null +++ b/interfaces/kits/ndk/fileshare/src/oh_file_share.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "oh_file_share.h" + +#include +#include +#include + +#include "access_token.h" +#include "accesstoken_kit.h" +#include "file_permission.h" +#include "ipc_skeleton.h" +#include "log.h" +#include "parameter.h" +#include "securec.h" +#include "tokenid_kit.h" + +const int32_t FOO_MAX_LEN = sizeof(FileShare_PolicyErrorResult) * OHOS::AppFileService::MAX_ARRAY_SIZE; +const std::string FILE_ACCESS_PERSIST_PERMISSION = "ohos.permission.FILE_ACCESS_PERSIST"; +const std::string FULL_MOUNT_ENABLE_PARAMETER = "const.filemanager.full_mount.enable"; + +using Exec = std::function &uriPolicies, + std::deque &errorResults)>; +static bool CheckPermission(const std::string &permission) +{ + OHOS::Security::AccessToken::AccessTokenID tokenCaller = OHOS::IPCSkeleton::GetCallingTokenID(); + return OHOS::Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenCaller, permission) == + OHOS::Security::AccessToken::PermissionState::PERMISSION_GRANTED; +} + +static bool CheckFileManagerFullMountEnable() +{ + char value[] = "false"; + int retSystem = GetParameter(FULL_MOUNT_ENABLE_PARAMETER.c_str(), "false", value, sizeof(value)); + if (retSystem > 0 && !strcmp(value, "true")) { + LOGI("The full mount enable parameter is true"); + return true; + } + LOGI("The full mount enable parameter is false"); + return false; +} + +static bool ConvertPolicyInfo(const FileShare_PolicyInfo *policies, + int policyNum, + std::vector &uriPolicies) +{ + for (int32_t i = 0; i < policyNum; i++) { + OHOS::AppFileService::UriPolicyInfo policyInfo; + if (policies[i].uri == nullptr || policies[i].length == 0) { + LOGE("The uri pointer is nullptr or length is 0"); + return false; + } + auto uriLength = strnlen(policies[i].uri, policies[i].length); + if (uriLength != policies[i].length) { + LOGE("The uri length abnormal"); + return false; + } + policyInfo.uri = std::string(policies[i].uri, policies[i].length); + policyInfo.mode = policies[i].operationMode; + uriPolicies.push_back(policyInfo); + } + return true; +} + +static bool ConvertPolicyErrorResult(const std::deque &errorResults, + FileShare_PolicyErrorResult **result, + unsigned int &resultNum) +{ + resultNum = 0; + auto count = errorResults.size(); + auto memorySize = count * sizeof(FileShare_PolicyErrorResult); + if (memorySize == 0 || memorySize > FOO_MAX_LEN) { + LOGE("The size of the return value array is abnormal"); + return false; + } + *result = (FileShare_PolicyErrorResult *)malloc(memorySize); + if (*result == nullptr) { + LOGE("Failed to apply for FileShare_PolicyErrorResult array memory"); + return false; + } + for (uint32_t i = 0; i < count; i++) { + int size = errorResults[i].uri.size() + 1; + (*result)[i].uri = (char *)malloc(size); + if ((*result)[i].uri == nullptr) { + LOGE("Failed to apply for URI memory"); + return false; + } + auto ret = strcpy_s((*result)[i].uri, size, errorResults[i].uri.c_str()); + if (ret != 0) { + LOGE("Copy uri failed uri:%{public}s, errno:%{public}d", errorResults[i].uri.c_str(), ret); + free((*result)[i].uri); + return false; + } + (*result)[i].code = static_cast(errorResults[i].code); + size = errorResults[i].message.size() + 1; + (*result)[i].message = (char *)malloc(size); + if ((*result)[i].message == nullptr) { + LOGE("Failed to apply for message memory"); + free((*result)[i].uri); + return false; + } + ret = strcpy_s((*result)[i].message, size, errorResults[i].message.c_str()); + if (ret != 0) { + LOGE("Copy message failed message:%{public}s, errno:%{public}d", errorResults[i].uri.c_str(), ret); + free((*result)[i].uri); + free((*result)[i].message); + return false; + } + resultNum++; + } + return true; +} + +static bool ConvertPolicyErrorResultBool(const std::vector &errorResults, bool **result) +{ + auto count = errorResults.size(); + auto memorySize = count * sizeof(bool); + if (memorySize == 0 || memorySize > FOO_MAX_LEN) { + LOGE("The size of the return value array is abnormal"); + return false; + } + *result = (bool *)malloc(memorySize); + if (*result == nullptr) { + LOGE("Failed to apply for bool array memory"); + return false; + } + for (uint32_t i = 0; i < count; i++) { + (*result)[i] = errorResults[i]; + } + return true; +} + +static FileManagement_ErrCode ErrorCodeConversion(int32_t errorCode) +{ + FileManagement_ErrCode errCode = E_UNKNOWN_ERROR; + switch (errorCode) { + case static_cast(E_NO_ERROR): + errCode = E_NO_ERROR; + break; + case static_cast(E_PERMISSION): + errCode = E_PERMISSION; + break; + case static_cast(E_PARAMS): + errCode = E_PARAMS; + break; + case EPERM: + errCode = E_EPERM; + break; + default: + break; + } + return errCode; +} + +void OH_FileShare_ReleasePolicyErrorResult(FileShare_PolicyErrorResult *result, unsigned int num); +static FileManagement_ErrCode ExecAction(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum, + Exec exec) +{ + (*resultNum) = 0; + if (!CheckFileManagerFullMountEnable()) { + return E_DEVICE_NOT_SUPPORT; + } + if (!CheckPermission(FILE_ACCESS_PERSIST_PERMISSION)) { + return E_PERMISSION; + } + std::vector uriPolicies; + if (!ConvertPolicyInfo(policies, policyNum, uriPolicies)) { + return E_PARAMS; + } + std::deque errorResults; + auto ret = ErrorCodeConversion(exec(uriPolicies, errorResults)); + if (ret == E_NO_ERROR) { + return E_NO_ERROR; + } + if (!ConvertPolicyErrorResult(errorResults, result, *resultNum)) { + OH_FileShare_ReleasePolicyErrorResult(*result, *resultNum); + return E_ENOMEM; + } + return ret; +} + +FileManagement_ErrCode OH_FileShare_PersistPermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum) +{ + if (policies == nullptr || result == nullptr || resultNum == nullptr) { + LOGE("The external input pointer is abnormal"); + return E_PARAMS; + } + if (policyNum <= 0 || policyNum > OHOS::AppFileService::MAX_ARRAY_SIZE) { + LOGE("The policyNum is abnormal"); + return E_PARAMS; + } + return ExecAction(policies, policyNum, result, resultNum, OHOS::AppFileService::FilePermission::PersistPermission); +} + +FileManagement_ErrCode OH_FileShare_RevokePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum) +{ + if (policies == nullptr || result == nullptr || resultNum == nullptr) { + LOGE("The external input pointer is abnormal"); + return E_PARAMS; + } + if (policyNum <= 0 || policyNum > OHOS::AppFileService::MAX_ARRAY_SIZE) { + LOGE("The policyNum is abnormal"); + return E_PARAMS; + } + return ExecAction(policies, policyNum, result, resultNum, OHOS::AppFileService::FilePermission::RevokePermission); +} + +FileManagement_ErrCode OH_FileShare_ActivatePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum) +{ + if (policies == nullptr || result == nullptr || resultNum == nullptr) { + LOGE("The external input pointer is abnormal"); + return E_PARAMS; + } + if (policyNum <= 0 || policyNum > OHOS::AppFileService::MAX_ARRAY_SIZE) { + LOGE("The policyNum is abnormal"); + return E_PARAMS; + } + return ExecAction(policies, policyNum, result, resultNum, OHOS::AppFileService::FilePermission::ActivatePermission); +} + +FileManagement_ErrCode OH_FileShare_DeactivatePermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + FileShare_PolicyErrorResult **result, + unsigned int *resultNum) +{ + if (policies == nullptr || result == nullptr || resultNum == nullptr) { + LOGE("The external input pointer is abnormal"); + return E_PARAMS; + } + if (policyNum <= 0 || policyNum > OHOS::AppFileService::MAX_ARRAY_SIZE) { + LOGE("The policyNum is abnormal"); + return E_PARAMS; + } + return ExecAction(policies, policyNum, result, resultNum, + OHOS::AppFileService::FilePermission::DeactivatePermission); +} + +FileManagement_ErrCode OH_FileShare_CheckPersistentPermission(const FileShare_PolicyInfo *policies, + unsigned int policyNum, + bool **result, + unsigned int *resultNum) +{ + if (policies == nullptr || result == nullptr || resultNum == nullptr) { + LOGE("The external input pointer is abnormal"); + return E_PARAMS; + } + if (policyNum <= 0 || policyNum > OHOS::AppFileService::MAX_ARRAY_SIZE) { + LOGE("The policyNum is abnormal"); + return E_PARAMS; + } + *resultNum = 0; + if (!CheckFileManagerFullMountEnable()) { + return E_DEVICE_NOT_SUPPORT; + } + if (!CheckPermission(FILE_ACCESS_PERSIST_PERMISSION)) { + return E_PERMISSION; + } + std::vector uriPolicies; + if (!ConvertPolicyInfo(policies, policyNum, uriPolicies)) { + return E_PARAMS; + } + std::vector errorResults; + auto ret = OHOS::AppFileService::FilePermission::CheckPersistentPermission(uriPolicies, errorResults); + if (ret != 0) { + return ErrorCodeConversion(ret); + } + if (!ConvertPolicyErrorResultBool(errorResults, result)) { + return E_ENOMEM; + } + *resultNum = errorResults.size(); + return E_NO_ERROR; +} + +void OH_FileShare_ReleasePolicyErrorResult(FileShare_PolicyErrorResult *result, unsigned int num) +{ + if (result == nullptr) { + return; + } + for (unsigned i = 0; i < num; i++) { + if (result[i].uri != nullptr) { + free(result[i].uri); + } + if (result[i].message != nullptr) { + free(result[i].message); + } + } + free(result); +} \ No newline at end of file