• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "moving_photo_impl.h"
17 
18 #include <fcntl.h>
19 #include <unistd.h>
20 
21 #include "directory_ex.h"
22 #include "file_uri.h"
23 #include "media_file_utils.h"
24 #include "medialibrary_errno.h"
25 #include "userfile_client.h"
26 #include "userfile_manager_types.h"
27 
28 using namespace std;
29 
30 namespace OHOS {
31 namespace Media {
FfiMovingPhotoImpl(const string & photoUri,SourceMode sourceMode)32 FfiMovingPhotoImpl::FfiMovingPhotoImpl(const string& photoUri, SourceMode sourceMode)
33 {
34     this->photoUri_ = photoUri;
35     this->sourceMode_ = sourceMode;
36 }
37 
GetUri()38 string FfiMovingPhotoImpl::GetUri()
39 {
40     return photoUri_;
41 }
42 
GetSourceMode()43 SourceMode FfiMovingPhotoImpl::GetSourceMode()
44 {
45     return sourceMode_;
46 }
47 
SetSourceMode(SourceMode sourceMode)48 void FfiMovingPhotoImpl::SetSourceMode(SourceMode sourceMode)
49 {
50     this->sourceMode_ = sourceMode;
51 }
52 
OpenReadOnlyImage(const std::string & imageUri,bool isMediaLibUri)53 static int32_t OpenReadOnlyImage(const std::string& imageUri, bool isMediaLibUri)
54 {
55     if (isMediaLibUri) {
56         Uri uri(imageUri);
57         return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
58     }
59     AppFileService::ModuleFileUri::FileUri fileUri(imageUri);
60     std::string realPath = fileUri.GetRealPath();
61     int32_t fd = open(realPath.c_str(), O_RDONLY);
62     if (fd < 0) {
63         LOGE("Failed to open read only image file");
64         return E_ERR;
65     }
66     return fd;
67 }
68 
OpenReadOnlyVideo(const std::string & videoUri,bool isMediaLibUri)69 static int32_t OpenReadOnlyVideo(const std::string& videoUri, bool isMediaLibUri)
70 {
71     if (isMediaLibUri) {
72         std::string openVideoUri = videoUri;
73         MediaFileUtils::UriAppendKeyValue(openVideoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
74             OPEN_MOVING_PHOTO_VIDEO);
75         Uri uri(openVideoUri);
76         return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
77     }
78     AppFileService::ModuleFileUri::FileUri fileUri(videoUri);
79     std::string realPath = fileUri.GetRealPath();
80     int32_t fd = open(realPath.c_str(), O_RDONLY);
81     if (fd < 0) {
82         LOGE("Failed to open read only video file");
83         return E_ERR;
84     }
85     return fd;
86 }
87 
HandleFd(int32_t & fd)88 static bool HandleFd(int32_t& fd)
89 {
90     if (fd == E_ERR) {
91         fd = E_HAS_FS_ERROR;
92         return false;
93     } else if (fd < 0) {
94         LOGE("Open failed due to OpenFile failure, error: %{public}d", fd);
95         return false;
96     }
97     return true;
98 }
99 
OpenReadOnlyFile(const string & uri,bool isReadImage)100 int32_t FfiMovingPhotoImpl::OpenReadOnlyFile(const string& uri, bool isReadImage)
101 {
102     if (uri.empty()) {
103         LOGE("Failed to open read only file, uri is empty");
104         return E_ERR;
105     }
106     std::string curUri = uri;
107     bool isMediaLibUri = MediaFileUtils::IsMediaLibraryUri(uri);
108     if (!isMediaLibUri) {
109         std::vector<std::string> uris;
110         if (!MediaFileUtils::SplitMovingPhotoUri(uri, uris)) {
111             LOGE("Failed to open read only file, split moving photo failed");
112             return E_ERR;
113         }
114         curUri = uris[isReadImage ? MOVING_PHOTO_IMAGE_POS : MOVING_PHOTO_VIDEO_POS];
115     }
116     return isReadImage ? OpenReadOnlyImage(curUri, isMediaLibUri) : OpenReadOnlyVideo(curUri, isMediaLibUri);
117 }
118 
OpenReadOnlyLivePhoto(const string & destLivePhotoUri)119 int32_t FfiMovingPhotoImpl::OpenReadOnlyLivePhoto(const string& destLivePhotoUri)
120 {
121     if (destLivePhotoUri.empty()) {
122         LOGE("Failed to open read only file, uri is empty");
123         return E_ERR;
124     }
125     if (MediaFileUtils::IsMediaLibraryUri(destLivePhotoUri)) {
126         string livePhotoUri = destLivePhotoUri;
127         MediaFileUtils::UriAppendKeyValue(livePhotoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
128             OPEN_PRIVATE_LIVE_PHOTO);
129         Uri uri(livePhotoUri);
130         return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
131     }
132     return E_ERR;
133 }
134 
CopyFileFromMediaLibrary(int32_t srcFd,int32_t destFd)135 static int32_t CopyFileFromMediaLibrary(int32_t srcFd, int32_t destFd)
136 {
137     size_t bufferSize = 4096;
138     char buffer[bufferSize];
139     ssize_t bytesRead;
140     ssize_t bytesWritten;
141     while ((bytesRead = read(srcFd, buffer, bufferSize)) > 0) {
142         bytesWritten = write(destFd, buffer, bytesRead);
143         if (bytesWritten != bytesRead) {
144             LOGE("Failed to copy file from srcFd=%{public}d to destFd=%{public}d, errno=%{public}d",
145                 srcFd, destFd, errno);
146             return E_HAS_FS_ERROR;
147         }
148     }
149 
150     if (bytesRead < 0) {
151         LOGE("Failed to read from srcFd=%{public}d, errno=%{public}d", srcFd, errno);
152         return E_HAS_FS_ERROR;
153     }
154     return E_OK;
155 }
156 
WriteToSandboxUri(int32_t srcFd,const string & sandboxUri)157 static int32_t WriteToSandboxUri(int32_t srcFd, const string& sandboxUri)
158 {
159     UniqueFd srcUniqueFd(srcFd);
160     AppFileService::ModuleFileUri::FileUri fileUri(sandboxUri);
161     string destPath = fileUri.GetRealPath();
162     if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
163         LOGE("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
164         return E_HAS_FS_ERROR;
165     }
166     int32_t destFd = MediaFileUtils::OpenFile(destPath, MEDIA_FILEMODE_READWRITE);
167     if (destFd < 0) {
168         LOGE("Open dest file failed, error: %{public}d", errno);
169         return E_HAS_FS_ERROR;
170     }
171     UniqueFd destUniqueFd(destFd);
172     if (ftruncate(destUniqueFd.Get(), 0) == -1) {
173         LOGE("Truncate old file in sandbox failed, error:%{public}d", errno);
174         return E_HAS_FS_ERROR;
175     }
176     return CopyFileFromMediaLibrary(srcUniqueFd.Get(), destUniqueFd.Get());
177 }
178 
RequestContentToSandbox(const string & destImageUri,const string & destVideoUri,string movingPhotoUri,SourceMode sourceMode)179 static int32_t RequestContentToSandbox(const string &destImageUri, const string &destVideoUri,
180     string movingPhotoUri, SourceMode sourceMode)
181 {
182     if (sourceMode == SourceMode::ORIGINAL_MODE) {
183         MediaFileUtils::UriAppendKeyValue(movingPhotoUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
184     }
185     if (!destImageUri.empty()) {
186         int32_t imageFd = FfiMovingPhotoImpl::OpenReadOnlyFile(movingPhotoUri, true);
187         if (!HandleFd(imageFd)) {
188             LOGE("Open source image file failed");
189             return imageFd;
190         }
191         int32_t ret = WriteToSandboxUri(imageFd, destImageUri);
192         if (ret != E_OK) {
193             LOGE("Write image to sandbox failed");
194             return ret;
195         }
196     }
197     if (!destVideoUri.empty()) {
198         int32_t videoFd = FfiMovingPhotoImpl::OpenReadOnlyFile(movingPhotoUri, false);
199         if (!HandleFd(videoFd)) {
200             LOGE("Open source video file failed");
201             return videoFd;
202         }
203         int32_t ret = WriteToSandboxUri(videoFd, destVideoUri);
204         if (ret != E_OK) {
205             LOGE("Write video to sandbox failed");
206             return ret;
207         }
208     }
209     return E_OK;
210 }
211 
IsValidResourceType(int32_t resourceType)212 static bool IsValidResourceType(int32_t resourceType)
213 {
214     // public API only support IMAGE_RESOURCE/VIDEO_RESOURCE
215     return (resourceType == static_cast<int>(ResourceType::IMAGE_RESOURCE) ||
216         resourceType == static_cast<int>(ResourceType::VIDEO_RESOURCE));
217 }
218 
RequestContent(char * imageFileUri,char * videoFileUri,int32_t & errCode)219 void FfiMovingPhotoImpl::RequestContent(char* imageFileUri, char* videoFileUri, int32_t &errCode)
220 {
221     // write both image and video to sandbox
222     string destImageUri(imageFileUri);
223     string destVideoUri(videoFileUri);
224     int32_t ret = RequestContentToSandbox(destImageUri, destVideoUri, photoUri_, sourceMode_);
225     if (ret != E_OK) {
226         errCode = static_cast<int32_t>(MediaLibraryNapiUtils::TransErrorCode("RequestContent", ret));
227     }
228 }
229 
RequestContent(int32_t resourceType,char * fileUri,int32_t & errCode)230 void FfiMovingPhotoImpl::RequestContent(int32_t resourceType, char* fileUri, int32_t &errCode)
231 {
232     string destImageUri = "";
233     string destVideoUri = "";
234     if (!IsValidResourceType(resourceType)) {
235         LOGE("Invalid resource type");
236         errCode = OHOS_INVALID_PARAM_CODE;
237         return;
238     }
239     if (resourceType == static_cast<int>(ResourceType::IMAGE_RESOURCE)) {
240         destImageUri = string(fileUri);
241     } else {
242         destVideoUri = string(fileUri);
243     }
244     int32_t ret = RequestContentToSandbox(destImageUri, destVideoUri, photoUri_, sourceMode_);
245     if (ret != E_OK) {
246         errCode = static_cast<int32_t>(MediaLibraryNapiUtils::TransErrorCode("RequestContent", ret));
247     }
248 }
249 
AcquireFdForArrayBuffer(string movingPhotoUri,SourceMode sourceMode,ResourceType resourceType)250 static int32_t AcquireFdForArrayBuffer(string movingPhotoUri, SourceMode sourceMode, ResourceType resourceType)
251 {
252     int32_t fd = 0;
253     if (sourceMode == SourceMode::ORIGINAL_MODE) {
254         MediaFileUtils::UriAppendKeyValue(movingPhotoUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
255     }
256     switch (resourceType) {
257         case ResourceType::IMAGE_RESOURCE:
258             fd = FfiMovingPhotoImpl::OpenReadOnlyFile(movingPhotoUri, true);
259             if (!HandleFd(fd)) {
260                 LOGE("Open source image file failed");
261             }
262             return fd;
263         case ResourceType::VIDEO_RESOURCE:
264             fd = FfiMovingPhotoImpl::OpenReadOnlyFile(movingPhotoUri, false);
265             if (!HandleFd(fd)) {
266                 LOGE("Open source video file failed");
267             }
268             return fd;
269         default:
270             LOGE("Invalid resource type: %{public}d", static_cast<int32_t>(resourceType));
271             return -EINVAL;
272     }
273 }
274 
RequestContentToArrayBuffer(int32_t resourceType,string movingPhotoUri,SourceMode sourceMode,CArrUI8 & result)275 static int32_t RequestContentToArrayBuffer(int32_t resourceType, string movingPhotoUri,
276     SourceMode sourceMode, CArrUI8 &result)
277 {
278     int32_t fd = AcquireFdForArrayBuffer(movingPhotoUri, sourceMode, static_cast<ResourceType>(resourceType));
279     if (fd < 0) {
280         return fd;
281     }
282     UniqueFd uniqueFd(fd);
283     off_t fileLen = lseek(uniqueFd.Get(), 0, SEEK_END);
284     if (fileLen < 0) {
285         LOGE("Failed to get file length, error: %{public}d", errno);
286         return E_HAS_FS_ERROR;
287     }
288     off_t ret = lseek(uniqueFd.Get(), 0, SEEK_SET);
289     if (ret < 0) {
290         LOGE("Failed to reset file offset, error: %{public}d", errno);
291         return E_HAS_FS_ERROR;
292     }
293     size_t fileSize = static_cast<size_t>(fileLen);
294     void* arrayBufferData = malloc(fileSize);
295     if (!arrayBufferData) {
296         LOGE("Failed to malloc array buffer data, moving photo uri is %{public}s, resource type is %{public}d",
297             movingPhotoUri.c_str(), resourceType);
298         return E_HAS_FS_ERROR;
299     }
300     size_t readBytes = static_cast<size_t>(read(uniqueFd.Get(), arrayBufferData, fileSize));
301     if (readBytes != fileSize) {
302         LOGE("read file failed, read bytes is %{public}zu, actual length is %{public}zu, "
303             "error: %{public}d", readBytes, fileSize, errno);
304         free(arrayBufferData);
305         return E_HAS_FS_ERROR;
306     }
307     if (fileSize > 0) {
308         if (arrayBufferData == nullptr) {
309             LOGE("get arrayBuffer failed.");
310             return E_HAS_FS_ERROR;
311         }
312         result.head = static_cast<uint8_t*>(arrayBufferData);
313         result.size = static_cast<int64_t>(fileSize);
314     }
315     return E_OK;
316 }
317 
RequestContent(int32_t resourceType,int32_t & errCode)318 CArrUI8 FfiMovingPhotoImpl::RequestContent(int32_t resourceType, int32_t &errCode)
319 {
320     CArrUI8 result = {
321         .head = nullptr,
322         .size  = 0
323     };
324     if (!IsValidResourceType(resourceType)) {
325         LOGE("Invalid resource type");
326         errCode = OHOS_INVALID_PARAM_CODE;
327         return result;
328     }
329     int32_t ret = RequestContentToArrayBuffer(resourceType, photoUri_, sourceMode_, result);
330     if (ret != E_OK) {
331         errCode = static_cast<int32_t>(MediaLibraryNapiUtils::TransErrorCode("RequestContent", ret));
332     }
333     return result;
334 }
335 }
336 }