From f86741a0efb486a1d5b2ce127d8d8400b09887bf Mon Sep 17 00:00:00 2001 From: caochuan Date: Mon, 27 Mar 2023 17:39:04 +0800 Subject: [PATCH] feat: add copy interface for faf Signed-off-by: caochuan --- .../napi_fileaccess_helper.cpp | 93 +++++++- .../napi_fileaccess_helper.h | 3 +- .../include/file_access_extension_info.h | 50 ++++- .../file_access/include/file_access_helper.h | 7 + .../file_access/src/file_access_helper.cpp | 210 +++++++++++++++++- utils/file_access_framework_errno.h | 50 ++++- 6 files changed, 407 insertions(+), 6 deletions(-) diff --git a/frameworks/js/napi/file_access_module/napi_fileaccess_helper.cpp b/frameworks/js/napi/file_access_module/napi_fileaccess_helper.cpp index 772e8cdb..2b970f0b 100644 --- a/frameworks/js/napi/file_access_module/napi_fileaccess_helper.cpp +++ b/frameworks/js/napi/file_access_module/napi_fileaccess_helper.cpp @@ -230,6 +230,7 @@ napi_value FileAccessHelperInit(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("createFile", NAPI_CreateFile), DECLARE_NAPI_FUNCTION("delete", NAPI_Delete), DECLARE_NAPI_FUNCTION("move", NAPI_Move), + DECLARE_NAPI_FUNCTION("copy", NAPI_Copy), DECLARE_NAPI_FUNCTION("rename", NAPI_Rename), DECLARE_NAPI_FUNCTION("getRoots", NAPI_GetRoots), DECLARE_NAPI_FUNCTION("access", NAPI_Access), @@ -605,6 +606,96 @@ napi_value NAPI_Move(napi_env env, napi_callback_info info) return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_; } +napi_value CreateObjectArray(napi_env env, std::vector result) +{ + uint32_t status = napi_ok; + napi_value copyResultArray = nullptr; + status = napi_create_array_with_length(env, result.size(), ©ResultArray); + if (status != napi_ok) { + return nullptr; + } + + for (size_t i = 0; i < result.size(); i++) { + CopyResult &cr = result.at(i); + + napi_value crVal; + status |= napi_create_object(env, &crVal); + napi_value tmpVal; + status |= napi_create_string_utf8(env, cr.uri.c_str(), cr.uri.length(), &tmpVal); + status |= napi_set_named_property(env, crVal, "uri", tmpVal); + status |= napi_create_int32(env, cr.errCode, &tmpVal); + status |= napi_set_named_property(env, crVal, "errCode", tmpVal); + status |= napi_create_string_utf8(env, cr.errMsg.c_str(), cr.errMsg.length(), &tmpVal); + status |= napi_set_named_property(env, crVal, "errMsg", tmpVal); + status |= napi_set_element(env, copyResultArray, i, crVal); + if (status != napi_ok) { + return nullptr; + } + } + return copyResultArray; +} + +napi_value NAPI_Copy(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) { + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + bool retStatus = false; + std::unique_ptr srcChar; + std::tie(retStatus, srcChar, std::ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!retStatus) { + NError(EINVAL).ThrowErr(env); + } + std::string srcStr (srcChar.get()); + + std::unique_ptr destChar; + std::tie(retStatus, destChar, std::ignore) = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); + if (!retStatus) { + NError(EINVAL).ThrowErr(env); + } + std::string destStr (destChar.get()); + + FileAccessHelper *fileAccessHelper = GetFileAccessHelper(env, funcArg.GetThisVar()); + if (fileAccessHelper == nullptr) { + return nullptr; + } + + auto result = std::make_shared>(); + if (result == nullptr) { + NError(E_GETRESULT).ThrowErr(env); + return nullptr; + } + + auto cbExec = [srcStr, destStr, result, fileAccessHelper]() -> NError { + OHOS::Uri srcUri(srcStr); + OHOS::Uri destUri(destStr); + int retVal = fileAccessHelper->Copy(srcUri, destUri, *result); + return NError(retVal); + }; + auto cbComplete = [result](napi_env env, NError err) -> NVal { + if (err) { + NError(ERR_FAF_FAIL).ThrowErr(env, FAFErrCodeTable.at(ERR_FAF_FAIL)); + } + return { env, CreateObjectArray(env, *result) }; + }; + + const std::string procedureName = "copy"; + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::TWO) { + return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbComplete).val_; + } + + NVal cb(env, funcArg[NARG_POS::THIRD]); + if (!cb.TypeIs(napi_function)) { + NError(EINVAL).ThrowErr(env); + return nullptr; + } + return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_; +} + napi_value NAPI_Rename(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); @@ -1073,4 +1164,4 @@ napi_value NAPI_Off(napi_env env, napi_callback_info info) return NVal::CreateUndefined(env).val_; } } // namespace FileAccessFwk -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/frameworks/js/napi/file_access_module/napi_fileaccess_helper.h b/frameworks/js/napi/file_access_module/napi_fileaccess_helper.h index 2c650b60..85107dce 100644 --- a/frameworks/js/napi/file_access_module/napi_fileaccess_helper.h +++ b/frameworks/js/napi/file_access_module/napi_fileaccess_helper.h @@ -29,6 +29,7 @@ namespace FileAccessFwk { napi_value NAPI_Mkdir(napi_env env, napi_callback_info info); napi_value NAPI_Delete(napi_env env, napi_callback_info info); napi_value NAPI_Move(napi_env env, napi_callback_info info); + napi_value NAPI_Copy(napi_env env, napi_callback_info info); napi_value NAPI_Rename(napi_env env, napi_callback_info info); napi_value NAPI_GetRoots(napi_env env, napi_callback_info info); napi_value NAPI_Access(napi_env env, napi_callback_info info); @@ -40,4 +41,4 @@ namespace FileAccessFwk { void InitOpenFlags(napi_env env, napi_value exports); } // namespace FileAccessFwk } // namespace OHOS -#endif // NAPI_FILEACCESS_HELPER_H \ No newline at end of file +#endif // NAPI_FILEACCESS_HELPER_H diff --git a/interfaces/inner_api/file_access/include/file_access_extension_info.h b/interfaces/inner_api/file_access/include/file_access_extension_info.h index 0f51b3b8..f7b63ce7 100644 --- a/interfaces/inner_api/file_access/include/file_access_extension_info.h +++ b/interfaces/inner_api/file_access/include/file_access_extension_info.h @@ -207,6 +207,54 @@ public: return size; } }; + +struct CopyResult : public virtual OHOS::Parcelable { +public: + std::string uri { "" }; + int32_t errCode { 0 }; + std::string errMsg { "" }; + + CopyResult() = default; + CopyResult(std::string uri, int32_t errCode, std::string errMsg) + : uri(uri), errCode(errCode), errMsg(errMsg) + {} + + bool ReadFromParcel(Parcel &parcel) + { + uri = parcel.ReadString(); + errCode = parcel.ReadInt32(); + errMsg = parcel.ReadString(); + return true; + } + + virtual bool Marshalling(Parcel &parcel) const override + { + if (!parcel.WriteString(uri)) { + return false; + } + if (!parcel.WriteInt32(errCode)) { + return false; + } + if (!parcel.WriteString(errMsg)) { + return false; + } + return true; + } + + static CopyResult *Unmarshalling(Parcel &parcel) + { + CopyResult *result = new (std::nothrow)CopyResult(); + if (result == nullptr) { + return nullptr; + } + + if (!result->ReadFromParcel(parcel)) { + delete result; + result = nullptr; + } + return result; + } +}; } // namespace FileAccessFwk } // namespace OHOS -#endif // FILE_ACCESS_EXTENSION_INFO_H \ No newline at end of file +#endif // FILE_ACCESS_EXTENSION_INFO_H diff --git a/interfaces/inner_api/file_access/include/file_access_helper.h b/interfaces/inner_api/file_access/include/file_access_helper.h index 385a0ca4..f8b54535 100644 --- a/interfaces/inner_api/file_access/include/file_access_helper.h +++ b/interfaces/inner_api/file_access/include/file_access_helper.h @@ -46,6 +46,7 @@ namespace { static const std::string SCHEME_NAME = "datashare"; static const std::string MEDIA_BNUDLE_NAME_ALIAS = "media"; static const std::string MEDIA_BNUDLE_NAME = "com.ohos.medialibrary.medialibrarydata"; + static const std::string EXTERNAL_BNUDLE_NAME = "com.ohos.UserFile.ExternalFileManager"; static const int32_t READ = 0; static const int32_t WRITE = 1; static const int32_t WRITE_READ = 2; @@ -77,6 +78,7 @@ public: int Mkdir(Uri &parent, const std::string &displayName, Uri &newDir); int Delete(Uri &selectFile); int Move(Uri &sourceFile, Uri &targetParent, Uri &newFile); + int Copy(Uri &sourceUri, Uri &destUri, std::vector ©Result); int Rename(Uri &sourceFile, const std::string &displayName, Uri &newFile); int ListFile(const FileInfo &fileInfo, const int64_t offset, const int64_t maxCount, const FileFilter &filter, std::vector &fileInfoVec); @@ -103,6 +105,11 @@ private: std::shared_ptr GetConnectInfo(const std::string &bundleName); + int CopyInMediaOrExternal(Uri &sourceUri, Uri &destUri, std::vector ©Result); + int CopyToMediaOrExternal(Uri& sourceUri, Uri& destUri, std::vector& copyResult); + int CopyDirectory(FileInfo &fileInfo, Uri &destUri, std::vector ©Result); + int CopyFile(FileInfo &fileInfo, Uri &destUri, CopyResult ©Result); + sptr token_ = nullptr; std::unordered_map> cMap_; diff --git a/interfaces/inner_api/file_access/src/file_access_helper.cpp b/interfaces/inner_api/file_access/src/file_access_helper.cpp index a2b4bf2f..79f8d2a7 100644 --- a/interfaces/inner_api/file_access/src/file_access_helper.cpp +++ b/interfaces/inner_api/file_access/src/file_access_helper.cpp @@ -14,9 +14,20 @@ */ #include "file_access_helper.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "bundle_constants.h" #include "bundle_mgr_proxy.h" +#include "fcntl.h" #include "file_access_framework_errno.h" #include "hilog_wrapper.h" #include "hitrace_meter.h" @@ -27,11 +38,20 @@ #include "image_source.h" #include "system_ability_definition.h" #include "tokenid_kit.h" +#include "uri.h" namespace OHOS { namespace FileAccessFwk { using namespace Media; +namespace { + const std::string ROOT_MEDIA_DIR = "/storage/media/local/files"; + const std::string ROOT_EXTERNAL_DIR = "/data/storage/el1/bundle/storage_daemon"; + const std::string EXTERNAL_BUNDLE_NAME = "com.ohos.UserFile.NotExistBundleName"; + constexpr int64_t MAX_COUNT = 1000; +} std::vector FileAccessHelper::wants_; +sptr g_sourceExtProxy; +sptr g_destExtProxy; static int GetUserId() { @@ -63,8 +83,11 @@ static bool GetBundleNameFromPath(const std::string &path, std::string &bundleNa static bool CheckUri(Uri &uri) { - HILOG_DEBUG("Uri : %{public}s.", uri.ToString().c_str()); + //HILOG_DEBUG("Uri : %{public}s.", uri.ToString().c_str()); + //std::string schemeStr = std::string(uri.GetScheme()); + HILOG_INFO("Uri : %{public}s.", uri.ToString().c_str()); // TODO: delete 3 lines std::string schemeStr = std::string(uri.GetScheme()); + HILOG_INFO("schemeStr : %{public}s.", schemeStr.c_str()); if (schemeStr.compare(SCHEME_NAME) != 0) { HILOG_ERROR("Uri scheme error."); return false; @@ -631,6 +654,189 @@ int FileAccessHelper::Move(Uri &sourceFile, Uri &targetParent, Uri &newFile) return ERR_OK; } +bool IsMediaUri(Uri &uri) +{ + string path = uri.GetPath(); + std::size_t len = MEDIA_BNUDLE_NAME_ALIAS.length(); + if (path.length() > len) { + string media = path.substr(1, len); + return (media == MEDIA_BNUDLE_NAME_ALIAS); + } + return false; +} + +bool IsExternalUri(Uri &uri) +{ + string path = uri.GetPath(); + std::size_t len = EXTERNAL_BNUDLE_NAME.length(); + if (path.length() > len) { + string external = path.substr(1, len); + return (external == EXTERNAL_BNUDLE_NAME); + } + return false; +} + +int FileAccessHelper::CopyFile(FileInfo &fileInfo, Uri &destUri, CopyResult ©Result) +{ + int ret; + do { + Uri srcUri {fileInfo.uri}; + int rFd; + ret = g_sourceExtProxy->OpenFile(srcUri, O_RDONLY, rFd); + if (ret != ERR_FAF_SUCCESS) { + HILOG_ERROR("OpenFile get result error, code:%{public}d", ret); + break; + } + + std::string sourceFileName = fileInfo.fileName; + int64_t sourceFileSize = fileInfo.size; + Uri newUri {""}; + ret = g_destExtProxy->CreateFile(destUri, sourceFileName, newUri); + if (ret != ERR_FAF_SUCCESS) { + HILOG_ERROR("OpenFile get result error, code:%{public}d", ret); + break; + } + + int wFd; + ret = g_destExtProxy->OpenFile(newUri, WRITE, wFd); + if (ret != ERR_FAF_SUCCESS) { + HILOG_ERROR("OpenFile get result error, code:%{public}d", ret); + break; + } + + if ((ret = sendfile(wFd, rFd, 0, sourceFileSize) < 0)) { + ret = errno; + break; + } + copyResult.uri = newUri.ToString(); + copyResult.errCode = ERR_FAF_SUCCESS; + copyResult.errMsg = ""; + } while (0); + + copyResult.uri = fileInfo.uri; + copyResult.errCode = ret; + copyResult.errMsg = "Copy Error"; + return ERR_FAF_SUCCESS; +} + +int FileAccessHelper::CopyDirectory(FileInfo &fileInfo, Uri &destUri, std::vector ©Result) +{ + std::vector fileInfoVec; + FileFilter filter { {}, {}, {}, 0, 0, false, false }; + int64_t offset { 0 }; + int ret = ERR_FAF_FAIL; + do { + ret = g_sourceExtProxy->ListFile(fileInfo, offset, MAX_COUNT, filter, fileInfoVec); + if (ret != ERR_OK) { + HILOG_ERROR("ListFile get result error, code:%{public}d", ret); + return ret; + } + + for (auto info : fileInfoVec) { + if (info.mode & DOCUMENT_FLAG_REPRESENTS_DIR) { + Uri dUri {""}; + ret = g_destExtProxy->Mkdir(destUri, info.fileName, dUri); + if (ret != ERR_OK) { + HILOG_ERROR("Mkdir get result error, code:%{public}d", ret); + copyResult.push_back(CopyResult { info.uri, ret, "" }); + continue; + } + ret = CopyDirectory(info, dUri, copyResult); + } else if (info.mode & DOCUMENT_FLAG_REPRESENTS_FILE) { + Uri newUri {""}; + CopyResult cr; + ret = CopyFile(info, destUri, cr); + copyResult.push_back(cr); + } + } + fileInfoVec.clear(); + offset += MAX_COUNT; + } while (fileInfoVec.size() == MAX_COUNT); + + return ret; +} + +int FileAccessHelper::CopyToMediaOrExternal(Uri &sourceUri, Uri &destUri, std::vector ©Result) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "CopyToMediaOrExternal"); + g_sourceExtProxy = GetProxyByUri(sourceUri); + if (g_sourceExtProxy == nullptr) { + HILOG_ERROR("failed with invalid fileAccessExtProxy"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return E_IPCS; + } + + g_destExtProxy = GetProxyByUri(destUri); + if (g_destExtProxy == nullptr) { + HILOG_ERROR("failed with invalid fileAccessExtProxy"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return E_IPCS; + } + + int ret = ERR_FAF_FAIL; + Uri newUri {""}; + FileAccessFwk::FileInfo fileInfo; + ret = g_sourceExtProxy->GetFileInfoFromUri(sourceUri, fileInfo); + if (ret != ERR_FAF_SUCCESS) { + HILOG_ERROR("get FileInfo from uri error, code:%{public}d", ret); + return ret; + } + if (fileInfo.mode & DOCUMENT_FLAG_REPRESENTS_DIR) { + g_destExtProxy->Mkdir(destUri, fileInfo.fileName, newUri); + ret = CopyDirectory(fileInfo, newUri, copyResult); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + } else if (fileInfo.mode & DOCUMENT_FLAG_REPRESENTS_FILE) { + CopyResult cr; + ret = CopyFile(fileInfo, destUri, cr); + copyResult.push_back(cr); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + } + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return ret ; +} + +int FileAccessHelper::CopyInMediaOrExternal(Uri &sourceUri, Uri &destUri, std::vector ©Result) +{ + sptr proxy = GetProxyByUri(sourceUri); + if (proxy == nullptr) { + HILOG_ERROR("failed with invalid fileAccessExtProxy"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return E_IPCS; + } + return ERR_FAF_SUCCESS; +} + +int FileAccessHelper::Copy(Uri &sourceUri, Uri &destUri, std::vector ©Result) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "Copy"); + if (!IsSystemApp()) { + HILOG_ERROR("FileAccessHelper::Copy check IsSystemAppByFullTokenID failed"); + return E_PERMISSION_SYS; + } + + if (!CheckUri(sourceUri)) { + HILOG_ERROR("sourceUri(%{public}s) format check error.", sourceUri.ToString().c_str()); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return E_URIS; + } + if (!CheckUri(destUri)) { + HILOG_ERROR("destUri(%{public}s) format check error.", destUri.ToString().c_str()); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return E_URIS; + } + + int ret = ERR_FAF_FAIL; + if ((IsMediaUri(sourceUri) && IsMediaUri(destUri)) + || (IsExternalUri(sourceUri) && IsExternalUri(destUri))) { + ret = CopyInMediaOrExternal(sourceUri, destUri, copyResult); + } else if ((IsMediaUri(sourceUri) && IsExternalUri(destUri)) + || (IsExternalUri(sourceUri) && IsMediaUri(destUri))) { + ret = CopyToMediaOrExternal(sourceUri, destUri, copyResult); + } + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return ret; +} + int FileAccessHelper::Rename(Uri &sourceFile, const std::string &displayName, Uri &newFile) { StartTrace(HITRACE_TAG_FILEMANAGEMENT, "Rename"); @@ -1040,4 +1246,4 @@ FileAccessDeathRecipient::~FileAccessDeathRecipient() { } } // namespace FileAccessFwk -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/utils/file_access_framework_errno.h b/utils/file_access_framework_errno.h index e3d79285..6c02a8d8 100644 --- a/utils/file_access_framework_errno.h +++ b/utils/file_access_framework_errno.h @@ -16,6 +16,8 @@ #ifndef FILE_ACCESS_FRAMEWORK_ERRNO_H #define FILE_ACCESS_FRAMEWORK_ERRNO_H +#include +#include #include "errors.h" namespace OHOS { @@ -36,6 +38,52 @@ enum { E_PERMISSION = 201, // Permission verification failed E_PERMISSION_SYS // is not system app }; + +// General error code for FAF +enum { + ERR_FAF_SUCCESS = 0, + ERR_FAF_FAIL, + ERR_FAF_PERM, + ERR_FAF_NOENT, + ERR_FAF_INTR, + ERR_FAF_IO, + ERR_FAF_NXIO, + ERR_FAF_2BIG, + ERR_FAF_NOMEM, + ERR_FAF_ACCES, + ERR_FAF_FAULT, + ERR_FAF_BUSY, + ERR_FAF_EXIST, + ERR_FAF_NOTDIR, + ERR_FAF_INVAL, + ERR_FAF_FBIG, + ERR_FAF_NOSPC, + ERR_FAF_ROFS, + ERR_FAF_NAMETOOLONG, +}; + +// {FAF error code, error message} +const std::unordered_map FAFErrCodeTable = { + { ERR_FAF_SUCCESS, "Execute succeed" }, + { ERR_FAF_FAIL, "Execute failed" }, + { ERR_FAF_PERM, "Operation not permitted" }, + { ERR_FAF_NOENT, "No such file or directory" }, + { ERR_FAF_INTR, "Interrupted system call" }, + { ERR_FAF_IO, "I/O error" }, + { ERR_FAF_NXIO, "No such device or address" }, + { ERR_FAF_2BIG, "Arg list too long" }, + { ERR_FAF_NOMEM, "Out of memory" }, + { ERR_FAF_ACCES, "Permission denied" }, + { ERR_FAF_FAULT, "Bad address" }, + { ERR_FAF_BUSY, "Device or resource busy" }, + { ERR_FAF_EXIST, "File exists" }, + { ERR_FAF_NOTDIR, "Not a directory" }, + { ERR_FAF_INVAL, "Invalid argument" }, + { ERR_FAF_FBIG, "File too large" }, + { ERR_FAF_NOSPC, "No space left on device" }, + { ERR_FAF_ROFS, "Read-only file system" }, + { ERR_FAF_NAMETOOLONG, "File name too long" } +}; } // namespace FileAccessFwk } // namespace OHOS -#endif // FILE_ACCESS_FRAMEWORK_ERRNO_H \ No newline at end of file +#endif // FILE_ACCESS_FRAMEWORK_ERRNO_H -- Gitee