• 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 <fcntl.h>
17 #include <unistd.h>
18 #include <cstring>
19 #include <securec.h>
20 
21 #include "moving_photo_impl.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "unique_fd.h"
25 #include "userfilemgr_uri.h"
26 #include "file_uri.h"
27 #include "medialibrary_db_const.h"
28 #include "medialibrary_errno.h"
29 #include "media_userfile_client.h"
30 
31 using namespace OHOS::Media;
32 using UniqueFd = OHOS::UniqueFd;
33 using Uri = OHOS::Uri;
34 
CreateMovingPhoto(const std::string & uri)35 std::shared_ptr<MovingPhoto> MovingPhotoFactory::CreateMovingPhoto(const std::string& uri)
36 {
37     std::shared_ptr<MovingPhotoImpl> impl = std::make_shared<MovingPhotoImpl>(uri);
38     CHECK_AND_PRINT_LOG(impl != nullptr, "Failed to create MovingPhotoImpl instance.");
39 
40     return impl;
41 }
42 
MovingPhotoImpl(const std::string & imageUri)43 MovingPhotoImpl::MovingPhotoImpl(const std::string& imageUri) : imageUri_(imageUri)
44 {
45 }
46 
~MovingPhotoImpl()47 MovingPhotoImpl::~MovingPhotoImpl()
48 {
49     if (arrayBufferData_ != nullptr) {
50         free(arrayBufferData_);
51         arrayBufferData_ = nullptr;
52     }
53 }
54 
GetUri(const char ** uri)55 MediaLibrary_ErrorCode MovingPhotoImpl::GetUri(const char** uri)
56 {
57     *uri = imageUri_.c_str();
58     MEDIA_INFO_LOG("Moving photo uri = %{public}s", imageUri_.c_str());
59     return MEDIA_LIBRARY_OK;
60 }
61 
RequestContentWithUris(char * imageUri,char * videoUri)62 MediaLibrary_ErrorCode MovingPhotoImpl::RequestContentWithUris(char* imageUri, char* videoUri)
63 {
64     destImageUri_ = imageUri;
65     destVideoUri_ = videoUri;
66     MEDIA_DEBUG_LOG("Request content imageUri = %{public}s, video = %{public}s", imageUri, videoUri);
67     int32_t ret = RequestContentToSandbox();
68     CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "RequestContentToSandbox failed");
69 
70     return MEDIA_LIBRARY_OK;
71 }
72 
RequestContentWithUri(MediaLibrary_ResourceType resourceType,char * uri)73 MediaLibrary_ErrorCode MovingPhotoImpl::RequestContentWithUri(MediaLibrary_ResourceType resourceType, char* uri)
74 {
75     resourceType_ = resourceType;
76     if (resourceType == MEDIA_LIBRARY_IMAGE_RESOURCE) {
77         destImageUri_ = uri;
78         destVideoUri_ = nullptr;
79         MEDIA_DEBUG_LOG("Request content with uri destImageUri_ = %{public}s", destImageUri_);
80     } else if (resourceType == MEDIA_LIBRARY_VIDEO_RESOURCE) {
81         destImageUri_ = nullptr;
82         destVideoUri_ = uri;
83         MEDIA_DEBUG_LOG("Request content with uri destVideoUri_ = %{public}s", destVideoUri_);
84     } else {
85         MEDIA_ERR_LOG("Request content with uri, invalid resourceType");
86         destImageUri_ = nullptr;
87         destVideoUri_ = nullptr;
88         return MEDIA_LIBRARY_PARAMETER_ERROR;
89     }
90     int32_t ret = RequestContentToSandbox();
91     CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "RequestContentToSandbox failed");
92 
93     return MEDIA_LIBRARY_OK;
94 }
95 
RequestContentWithBuffer(MediaLibrary_ResourceType resourceType,const uint8_t ** buffer,uint32_t * size)96 MediaLibrary_ErrorCode MovingPhotoImpl::RequestContentWithBuffer(MediaLibrary_ResourceType resourceType,
97     const uint8_t** buffer, uint32_t* size)
98 {
99     resourceType_ = resourceType;
100     int32_t ret = RequestContentToArrayBuffer();
101     CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "RequestContentToArrayBuffer failed");
102 
103     if (arrayBufferLength_ <= 0) {
104         MEDIA_ERR_LOG("arrayBufferLength equals 0,ivalid buffer length");
105         return MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED;
106     }
107 
108     *buffer = reinterpret_cast<const uint8_t*>(arrayBufferData_);
109     *size = arrayBufferLength_;
110     MEDIA_INFO_LOG("Request content buffer size = %{public}zu", arrayBufferLength_);
111     return MEDIA_LIBRARY_OK;
112 }
113 
RequestContentToSandbox()114 int32_t MovingPhotoImpl::RequestContentToSandbox()
115 {
116     std::string movingPhotoUri = imageUri_;
117     if (sourceMode_ == SourceMode::ORIGINAL_MODE) {
118         MediaFileUtils::UriAppendKeyValue(movingPhotoUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
119     }
120 
121     if (destImageUri_ && strlen(destImageUri_) > 0) {
122         MEDIA_DEBUG_LOG("Sandbox image movingPhotoUri = %{public}s, destImageUri_ = %{public}s",
123             movingPhotoUri.c_str(), destImageUri_);
124         int32_t imageFd = OpenReadOnlyFile(movingPhotoUri, true);
125         CHECK_AND_RETURN_RET_LOG(HandleFd(imageFd), imageFd, "Open source image file failed");
126         std::string imageUri(destImageUri_);
127         int32_t ret = WriteToSandboxUri(imageFd, imageUri);
128         CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Write image to sandbox failed");
129     }
130     if (destVideoUri_ && strlen(destVideoUri_) > 0) {
131         MEDIA_DEBUG_LOG("Sandbox video movingPhotoUri = %{public}s, destVideoUri_ = %{public}s",
132             movingPhotoUri.c_str(), destVideoUri_);
133         int32_t videoFd = OpenReadOnlyFile(movingPhotoUri, false);
134         CHECK_AND_RETURN_RET_LOG(HandleFd(videoFd), videoFd, "Open source video file failed");
135         std::string videoUri(destVideoUri_);
136         int32_t ret = WriteToSandboxUri(videoFd, videoUri);
137         CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Write video to sandbox failed");
138     }
139     MEDIA_INFO_LOG("Request content to sandbox done");
140     return E_OK;
141 }
142 
WriteToSandboxUri(int32_t srcFd,std::string & sandboxUri)143 int32_t MovingPhotoImpl::WriteToSandboxUri(int32_t srcFd, std::string& sandboxUri)
144 {
145     UniqueFd srcUniqueFd(srcFd);
146     OHOS::AppFileService::ModuleFileUri::FileUri fileUri(sandboxUri);
147     std::string destPath = fileUri.GetRealPath();
148     MEDIA_INFO_LOG("Dest real path = %{public}s", destPath.c_str());
149     if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
150         MEDIA_ERR_LOG("Create empty dest file in sandbox failed, path:%{public}s", destPath.c_str());
151         return E_HAS_FS_ERROR;
152     }
153 
154     int32_t destFd = MediaFileUtils::OpenFile(destPath, MEDIA_FILEMODE_READWRITE);
155     if (destFd < 0) {
156         MEDIA_ERR_LOG("Open dest file failed, error: %{public}d", errno);
157         return E_HAS_FS_ERROR;
158     }
159     UniqueFd destUniqueFd(destFd);
160 
161     if (ftruncate(destUniqueFd.Get(), 0) == -1) {
162         MEDIA_ERR_LOG("Truncate old file in sandbox failed, error:%{public}d", errno);
163         return E_HAS_FS_ERROR;
164     }
165     return CopyFileFromMediaLibrary(srcUniqueFd.Get(), destUniqueFd.Get());
166 }
167 
CopyFileFromMediaLibrary(int32_t srcFd,int32_t destFd)168 int32_t MovingPhotoImpl::CopyFileFromMediaLibrary(int32_t srcFd, int32_t destFd)
169 {
170     constexpr size_t bufferSize = 4096;
171     char buffer[bufferSize];
172     ssize_t bytesRead;
173     ssize_t bytesWritten;
174     while ((bytesRead = read(srcFd, buffer, bufferSize)) > 0) {
175         bytesWritten = write(destFd, buffer, bytesRead);
176         if (bytesWritten != bytesRead) {
177             MEDIA_ERR_LOG("Failed to copy file from srcFd=%{public}d to destFd=%{public}d, errno=%{public}d",
178                 srcFd, destFd, errno);
179             return E_HAS_FS_ERROR;
180         }
181     }
182 
183     if (bytesRead < 0) {
184         MEDIA_ERR_LOG("Failed to read from srcFd=%{public}d, errno=%{public}d", srcFd, errno);
185         return E_HAS_FS_ERROR;
186     }
187     MEDIA_INFO_LOG("Copy file from media library done");
188     return E_OK;
189 }
190 
OpenReadOnlyFile(const std::string & uri,bool isReadImage)191 int32_t MovingPhotoImpl::OpenReadOnlyFile(const std::string& uri, bool isReadImage)
192 {
193     CHECK_AND_RETURN_RET_LOG(!uri.empty(), E_ERR, "Failed to open read only file, uri is empty");
194 
195     std::string curUri = uri;
196     bool isMediaLibUri = MediaFileUtils::IsMediaLibraryUri(uri);
197     MEDIA_DEBUG_LOG("isMediaLibUri = %{public}d, isReadImage = %{public}d", isMediaLibUri, isReadImage);
198     if (!isMediaLibUri) {
199         std::vector<std::string> uris;
200         if (!MediaFileUtils::SplitMovingPhotoUri(uri, uris)) {
201             MEDIA_ERR_LOG("Failed to open read only file, split moving photo failed");
202             return -1;
203         }
204         curUri = uris[isReadImage ? MOVING_PHOTO_IMAGE_POS : MOVING_PHOTO_VIDEO_POS];
205     }
206     return isReadImage ? OpenReadOnlyImage(curUri, isMediaLibUri) : OpenReadOnlyVideo(curUri, isMediaLibUri);
207 }
208 
OpenReadOnlyImage(const std::string & imageUri,bool isMediaLibUri)209 int32_t MovingPhotoImpl::OpenReadOnlyImage(const std::string& imageUri, bool isMediaLibUri)
210 {
211     if (isMediaLibUri) {
212         Uri uri(imageUri);
213         return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
214     }
215     OHOS::AppFileService::ModuleFileUri::FileUri fileUri(imageUri);
216     std::string realPath = fileUri.GetRealPath();
217     int32_t fd = open(realPath.c_str(), O_RDONLY);
218     CHECK_AND_RETURN_RET_LOG(fd >= 0, E_ERR, "Failed to open read only image file");
219 
220     return fd;
221 }
222 
HandleFd(int32_t & fd)223 bool MovingPhotoImpl::HandleFd(int32_t& fd)
224 {
225     if (fd == E_ERR) {
226         fd = E_HAS_FS_ERROR;
227         return false;
228     } else if (fd < 0) {
229         MEDIA_ERR_LOG("Open failed due to OpenFile failure, error: %{public}d", fd);
230         return false;
231     }
232     return true;
233 }
234 
OpenReadOnlyVideo(const std::string & videoUri,bool isMediaLibUri)235 int32_t MovingPhotoImpl::OpenReadOnlyVideo(const std::string& videoUri, bool isMediaLibUri)
236 {
237     if (isMediaLibUri) {
238         std::string openVideoUri = videoUri;
239         MediaFileUtils::UriAppendKeyValue(openVideoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
240             OPEN_MOVING_PHOTO_VIDEO);
241         Uri uri(openVideoUri);
242         return UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
243     }
244     OHOS::AppFileService::ModuleFileUri::FileUri fileUri(videoUri);
245     std::string realPath = fileUri.GetRealPath();
246     int32_t fd = open(realPath.c_str(), O_RDONLY);
247     if (fd < 0) {
248         MEDIA_ERR_LOG("Failed to open read only video file, errno: %{public}d", errno);
249         return -1;
250     }
251     return fd;
252 }
253 
AcquireFdForArrayBuffer()254 int32_t MovingPhotoImpl::AcquireFdForArrayBuffer()
255 {
256     int32_t fd = 0;
257     std::string movingPhotoUri = imageUri_;
258     switch (resourceType_) {
259         case MediaLibrary_ResourceType::MEDIA_LIBRARY_IMAGE_RESOURCE: {
260             fd = OpenReadOnlyFile(movingPhotoUri, true);
261             CHECK_AND_RETURN_RET_LOG(HandleFd(fd), fd, "Open source image file failed");
262             return fd;
263         }
264         case MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE: {
265             fd = OpenReadOnlyFile(movingPhotoUri, false);
266             CHECK_AND_RETURN_RET_LOG(HandleFd(fd), fd, "Open source video file failed");
267             return fd;
268         }
269         default:
270             MEDIA_ERR_LOG("Invalid resource type: %{public}d", static_cast<int32_t>(resourceType_));
271             return -EINVAL;
272     }
273 }
274 
RequestContentToArrayBuffer()275 int32_t MovingPhotoImpl::RequestContentToArrayBuffer()
276 {
277     int32_t fd = AcquireFdForArrayBuffer();
278     CHECK_AND_RETURN_RET_LOG(fd >= 0, fd, "Acquire fd for arraybuffer failed");
279 
280     UniqueFd uniqueFd(fd);
281     off_t fileLen = lseek(uniqueFd.Get(), 0, SEEK_END);
282     if (fileLen < 0) {
283         MEDIA_ERR_LOG("Failed to get file length, error: %{public}d", errno);
284         return E_HAS_FS_ERROR;
285     }
286 
287     off_t ret = lseek(uniqueFd.Get(), 0, SEEK_SET);
288     if (ret < 0) {
289         MEDIA_ERR_LOG("Failed to reset file offset, error: %{public}d", errno);
290         return E_HAS_FS_ERROR;
291     }
292 
293     if (static_cast<uint64_t>(fileLen) > static_cast<uint64_t>(SIZE_MAX)) {
294         MEDIA_ERR_LOG("File length is too large to fit in a size_t, length: %{public}zu",
295             static_cast<size_t>(fileLen));
296         return E_HAS_FS_ERROR;
297     }
298 
299     size_t fileSize = static_cast<size_t>(fileLen);
300     arrayBufferData_ = malloc(fileSize);
301     if (!arrayBufferData_) {
302         MEDIA_ERR_LOG("Failed to malloc array buffer, moving photo uri is %{public}s, resource type is %{public}d",
303             imageUri_.c_str(), static_cast<int32_t>(resourceType_));
304         return E_HAS_FS_ERROR;
305     }
306     memset_s(arrayBufferData_, fileSize, 0, fileSize);
307 
308     ssize_t readBytes = read(uniqueFd.Get(), arrayBufferData_, fileSize);
309     if (readBytes != fileSize) {
310         MEDIA_ERR_LOG("read file failed, read bytes is %{public}zu, actual length is %{public}zu, error: %{public}d",
311             readBytes, fileSize, errno);
312         free(arrayBufferData_);
313         arrayBufferData_ = nullptr;
314         return E_HAS_FS_ERROR;
315     }
316     arrayBufferLength_ = fileSize;
317     return E_OK;
318 }
319