1 /*
2 * Copyright (C) 2021 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 "file_source_stream.h"
17
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/ioctl.h>
22
23 #include "directory_ex.h"
24 #include "file_packer_stream.h"
25 #include "image_log.h"
26 #include "image_utils.h"
27 #include "media_errors.h"
28
29 #if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
30 #include <sys/mman.h>
31 #define SUPPORT_MMAP
32 #endif
33
34 const unsigned HMDFS_IOC = 0xf2;
35 #define HMDFS_IOC_GET_LOCATION _IOR(HMDFS_IOC, 7, unsigned int)
36
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
39
40 #undef LOG_TAG
41 #define LOG_TAG "FileSourceStream"
42
43 namespace OHOS {
44 namespace Media {
45 using namespace std;
46 using namespace ImagePlugin;
47
48 constexpr int INVALID_POSITION = -1;
49 constexpr int IOCTL_SUCCESS = 0;
50 constexpr int LOCAL_FILE_POSITION = 1;
51
FileSourceStream(std::FILE * file,size_t size,size_t offset,size_t original,bool useMmap,int originalFd)52 FileSourceStream::FileSourceStream(std::FILE *file, size_t size, size_t offset, size_t original,
53 bool useMmap, int originalFd)
54 : filePtr_(file), fileSize_(size), fileOffset_(offset), fileOriginalOffset_(original),
55 useMmap_(useMmap)
56 {
57 originalFd_ = originalFd;
58 }
59
FileSourceStream(std::FILE * file,size_t size,size_t offset,size_t original,bool useMmap,const std::string & originalPath)60 FileSourceStream::FileSourceStream(std::FILE *file, size_t size, size_t offset, size_t original,
61 bool useMmap, const std::string &originalPath)
62 : filePtr_(file), fileSize_(size), fileOffset_(offset), fileOriginalOffset_(original),
63 useMmap_(useMmap)
64 {
65 originalPath_ = originalPath;
66 }
67
~FileSourceStream()68 FileSourceStream::~FileSourceStream()
69 {
70 IMAGE_LOGD("[FileSourceStream]destructor enter.");
71 if (filePtr_ != nullptr) {
72 fclose(filePtr_);
73 filePtr_ = nullptr;
74 }
75 ResetReadBuffer();
76 }
77
CreateSourceStream(const string & pathName)78 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(const string &pathName)
79 {
80 string realPath;
81 if (!PathToRealPath(pathName, realPath)) {
82 IMAGE_LOGE("[FileSourceStream]input the file path exception, errno:%{public}d.", errno);
83 return nullptr;
84 }
85 FILE *filePtr = fopen(realPath.c_str(), "rb");
86 if (filePtr == nullptr) {
87 IMAGE_LOGE("[FileSourceStream]open file fail.");
88 return nullptr;
89 }
90 int fd = fileno(filePtr);
91 bool useMmap = ShouldUseMmap(fd);
92 size_t size = 0;
93 if (!ImageUtils::GetFileSize(realPath, size)) {
94 IMAGE_LOGE("[FileSourceStream]get the file size fail");
95 fclose(filePtr);
96 return nullptr;
97 }
98 int64_t offset = ftell(filePtr);
99 if (offset < 0) {
100 IMAGE_LOGE("[FileSourceStream]get the position fail.");
101 fclose(filePtr);
102 return nullptr;
103 }
104 return make_unique<FileSourceStream>(filePtr, size, offset, offset, useMmap, realPath);
105 }
106
CreateSourceStream(const int fd)107 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(const int fd)
108 {
109 int dupFd = dup(fd);
110 if (dupFd < 0) {
111 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
112 return nullptr;
113 }
114
115 FILE *filePtr = fdopen(dupFd, "rb");
116 if (filePtr == nullptr) {
117 IMAGE_LOGE("[FileSourceStream]open file fail.");
118 close(dupFd);
119 return nullptr;
120 }
121 bool useMmap = ShouldUseMmap(fd);
122 size_t size = 0;
123 if (!ImageUtils::GetFileSize(dupFd, size)) {
124 IMAGE_LOGE("[FileSourceStream]get the file size fail. dupFd=%{public}d", dupFd);
125 fclose(filePtr);
126 return nullptr;
127 }
128
129 int ret = fseek(filePtr, 0, SEEK_SET);
130 if (ret != 0) {
131 IMAGE_LOGE("[FileSourceStream]Go to 0 position fail, ret:%{public}d.", ret);
132 }
133
134 int64_t offset = ftell(filePtr);
135 if (offset < 0) {
136 IMAGE_LOGE("[FileSourceStream]get the position fail.");
137 fclose(filePtr);
138 return nullptr;
139 }
140 return make_unique<FileSourceStream>(filePtr, size, offset, offset, useMmap, dupFd);
141 }
142
CreateSourceStream(const int fd,int32_t offset,int32_t length)143 unique_ptr<FileSourceStream> FileSourceStream::CreateSourceStream(
144 const int fd, int32_t offset, int32_t length)
145 {
146 int dupFd = dup(fd);
147 if (dupFd < 0) {
148 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
149 return nullptr;
150 }
151
152 FILE *filePtr = fdopen(dupFd, "rb");
153 if (filePtr == nullptr) {
154 IMAGE_LOGE("[FileSourceStream]open file fail.");
155 close(dupFd);
156 return nullptr;
157 }
158 bool useMmap = ShouldUseMmap(fd);
159 int ret = fseek(filePtr, offset, SEEK_SET);
160 if (ret != 0) {
161 IMAGE_LOGE("[FileSourceStream]Go to %{public}d position fail, ret:%{public}d.", offset, ret);
162 fclose(filePtr);
163 return nullptr;
164 }
165 return make_unique<FileSourceStream>(filePtr, length, offset, offset, useMmap, dupFd);
166 }
167
Read(uint32_t desiredSize,DataStreamBuffer & outData)168 bool FileSourceStream::Read(uint32_t desiredSize, DataStreamBuffer &outData)
169 {
170 if (desiredSize == 0 || filePtr_ == nullptr) {
171 IMAGE_LOGE("[FileSourceStream]read stream input parameter exception.");
172 return false;
173 }
174 if (!GetData(desiredSize, outData)) {
175 IMAGE_LOGI("[FileSourceStream]read dataStreamBuffer fail.");
176 return false;
177 }
178 fileOffset_ += outData.dataSize;
179 return true;
180 }
181
Peek(uint32_t desiredSize,DataStreamBuffer & outData)182 bool FileSourceStream::Peek(uint32_t desiredSize, DataStreamBuffer &outData)
183 {
184 if (desiredSize == 0 || filePtr_ == nullptr) {
185 IMAGE_LOGE("[FileSourceStream]peek stream input parameter exception.");
186 return false;
187 }
188 if (!GetData(desiredSize, outData)) {
189 IMAGE_LOGD("[FileSourceStream]peek dataStreamBuffer fail, desiredSize:%{public}u", desiredSize);
190 return false;
191 }
192 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
193 if (ret != 0) {
194 IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret);
195 return false;
196 }
197 return true;
198 }
199
Read(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)200 bool FileSourceStream::Read(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
201 {
202 if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) {
203 IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u,"
204 "bufferSize:%{public}u,fileSize_:%{public}zu.", desiredSize, bufferSize, fileSize_);
205 return false;
206 }
207 if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) {
208 IMAGE_LOGD("[FileSourceStream]read outBuffer fail.");
209 return false;
210 }
211 fileOffset_ += readSize;
212 return true;
213 }
214
Peek(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)215 bool FileSourceStream::Peek(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
216 {
217 if (desiredSize == 0 || outBuffer == nullptr || desiredSize > bufferSize || desiredSize > fileSize_) {
218 IMAGE_LOGE("[FileSourceStream]input parameter exception, desiredSize:%{public}u,"
219 "bufferSize:%{public}u, fileSize_:%{public}zu.", desiredSize, bufferSize, fileSize_);
220 return false;
221 }
222 if (!GetData(desiredSize, outBuffer, bufferSize, readSize)) {
223 IMAGE_LOGI("[FileSourceStream]peek outBuffer fail.");
224 return false;
225 }
226 if (filePtr_ == nullptr) {
227 return false;
228 }
229 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
230 if (ret != 0) {
231 IMAGE_LOGE("[FileSourceStream]go to original position fail, ret:%{public}d.", ret);
232 return false;
233 }
234 return true;
235 }
236
Seek(uint32_t position)237 bool FileSourceStream::Seek(uint32_t position)
238 {
239 if (position > fileSize_) {
240 IMAGE_LOGE("[FileSourceStream]Seek the position greater than the file size, position:%{public}u.",
241 position);
242 return false;
243 }
244 if (filePtr_ == nullptr) {
245 return false;
246 }
247 size_t targetPosition = position + fileOriginalOffset_;
248 fileOffset_ = ((targetPosition < fileSize_) ? targetPosition : fileSize_);
249 int ret = fseek(filePtr_, fileOffset_, SEEK_SET);
250 if (ret != 0) {
251 IMAGE_LOGE("[FileSourceStream]go to offset position fail, ret:%{public}d.", ret);
252 return false;
253 }
254 return true;
255 }
256
Tell()257 uint32_t FileSourceStream::Tell()
258 {
259 return fileOffset_ - fileOriginalOffset_;
260 }
261
GetData(uint32_t desiredSize,uint8_t * outBuffer,uint32_t bufferSize,uint32_t & readSize)262 bool FileSourceStream::GetData(uint32_t desiredSize, uint8_t *outBuffer, uint32_t bufferSize, uint32_t &readSize)
263 {
264 if (fileSize_ == fileOffset_) {
265 IMAGE_LOGE("[FileSourceStream]read data finish, offset:%{public}zu ,dataSize%{public}zu.",
266 fileOffset_, fileSize_);
267 return false;
268 }
269 if (filePtr_ == nullptr) {
270 return false;
271 }
272 if (desiredSize > (fileSize_ - fileOffset_)) {
273 desiredSize = fileSize_ - fileOffset_;
274 }
275 size_t bytesRead = fread(outBuffer, sizeof(outBuffer[0]), desiredSize, filePtr_);
276 if (bytesRead < desiredSize) {
277 IMAGE_LOGD("read outBuffer end, bytesRead:%{public}zu, desiredSize:%{public}u, fileSize_:%{public}zu,"
278 "fileOffset_:%{public}zu", bytesRead, desiredSize, fileSize_, fileOffset_);
279 int fRes = ferror(filePtr_);
280 if (fRes) {
281 IMAGE_LOGD("fread failed, ferror:%{public}d", fRes);
282 return false;
283 }
284 }
285 readSize = bytesRead;
286 return true;
287 }
288
GetData(uint32_t desiredSize,DataStreamBuffer & outData)289 bool FileSourceStream::GetData(uint32_t desiredSize, DataStreamBuffer &outData)
290 {
291 if (fileSize_ == fileOffset_) {
292 IMAGE_LOGE("[FileSourceStream]read finish, offset:%{public}zu ,dataSize%{public}zu.",
293 fileOffset_, fileSize_);
294 return false;
295 }
296
297 if (desiredSize == 0 || desiredSize > MALLOC_MAX_LENTH) {
298 IMAGE_LOGE("[FileSourceStream]Invalid value, desiredSize out of size.");
299 return false;
300 }
301 if (filePtr_ == nullptr) {
302 return false;
303 }
304
305 ResetReadBuffer();
306 readBuffer_ = static_cast<uint8_t *>(malloc(desiredSize));
307 if (readBuffer_ == nullptr) {
308 IMAGE_LOGE("[FileSourceStream]malloc the desiredSize fail.");
309 return false;
310 }
311 outData.bufferSize = desiredSize;
312 if (desiredSize > (fileSize_ - fileOffset_)) {
313 desiredSize = fileSize_ - fileOffset_;
314 }
315 size_t bytesRead = fread(readBuffer_, sizeof(uint8_t), desiredSize, filePtr_);
316 if (bytesRead < desiredSize) {
317 IMAGE_LOGD("read outData end, bytesRead:%{public}zu, desiredSize:%{public}u, fileSize_:%{public}zu,"
318 "fileOffset_:%{public}zu", bytesRead, desiredSize, fileSize_, fileOffset_);
319 int fRes = ferror(filePtr_);
320 if (fRes) {
321 IMAGE_LOGD("fread failed, ferror:%{public}d", fRes);
322 free(readBuffer_);
323 readBuffer_ = nullptr;
324 return false;
325 }
326 }
327 outData.inputStreamBuffer = static_cast<uint8_t *>(readBuffer_);
328 outData.dataSize = bytesRead;
329 return true;
330 }
331
GetStreamSize()332 size_t FileSourceStream::GetStreamSize()
333 {
334 return fileSize_ - fileOriginalOffset_;
335 }
336
DupFd(FILE * f,int & res)337 static bool DupFd(FILE *f, int &res)
338 {
339 res = fileno(f);
340 if (res < 0) {
341 IMAGE_LOGE("[FileSourceStream]Fail to fileno fd.");
342 return false;
343 }
344 res = dup(res);
345 if (res < 0) {
346 IMAGE_LOGE("[FileSourceStream]Fail to dup fd.");
347 return false;
348 }
349 return true;
350 }
351
GetDataPtr()352 uint8_t *FileSourceStream::GetDataPtr()
353 {
354 return GetDataPtr(false);
355 }
356
GetDataPtr(bool populate)357 uint8_t *FileSourceStream::GetDataPtr(bool populate)
358 {
359 if (fileData_ != nullptr) {
360 return fileData_;
361 }
362
363 if (!useMmap_) {
364 uint32_t size = static_cast<uint32_t>(GetStreamSize());
365 uint8_t* buffer = new (std::nothrow) uint8_t [size];
366 if (buffer == nullptr) {
367 IMAGE_LOGE("[FileSourceStream] Failed to new stream buffer.");
368 return nullptr;
369 }
370 uint32_t savedPosition = Tell();
371 if (!Seek(0)) {
372 IMAGE_LOGE("[FileSourceStream] GetDataPtr seek start failed.");
373 delete[] buffer;
374 return nullptr;
375 }
376 uint32_t readSize = 0;
377 bool retRead = Read(size, buffer, size, readSize);
378 if (!Seek(savedPosition) || !retRead) {
379 IMAGE_LOGE("[FileSourceStream] GetDataPtr read failed.");
380 delete[] buffer;
381 return nullptr;
382 }
383 IMAGE_LOGD("[FileSourceStream] UseMmap is false, read buffer success.");
384 fileData_ = buffer;
385 return fileData_;
386 }
387
388 #ifdef SUPPORT_MMAP
389 if (filePtr_ == nullptr) {
390 return nullptr;
391 }
392 if (!DupFd(filePtr_, mmapFd_)) {
393 return nullptr;
394 }
395 auto mmptr = ::mmap(nullptr, fileSize_ - fileOriginalOffset_, PROT_READ,
396 populate ? MAP_SHARED | MAP_POPULATE : MAP_SHARED, mmapFd_, fileOriginalOffset_);
397 if (mmptr == MAP_FAILED) {
398 IMAGE_LOGE("[FileSourceStream] mmap failed, errno:%{public}d", errno);
399 close(mmapFd_);
400 return nullptr;
401 }
402 fileData_ = static_cast<uint8_t*>(mmptr);
403 #endif
404 return fileData_;
405 }
406
GetStreamType()407 uint32_t FileSourceStream::GetStreamType()
408 {
409 return ImagePlugin::FILE_STREAM_TYPE;
410 }
411
ResetReadBuffer()412 void FileSourceStream::ResetReadBuffer()
413 {
414 if (readBuffer_ != nullptr) {
415 free(readBuffer_);
416 readBuffer_ = nullptr;
417 }
418 if (fileData_ != nullptr && !mmapFdPassedOn_ && useMmap_) {
419 #ifdef SUPPORT_MMAP
420 ::munmap(fileData_, fileSize_ - fileOriginalOffset_);
421 close(mmapFd_);
422 #endif
423 }
424 if (!useMmap_) {
425 delete [] fileData_;
426 }
427 fileData_ = nullptr;
428 }
429
GetMMapFd()430 int FileSourceStream::GetMMapFd()
431 {
432 mmapFdPassedOn_ = true;
433 return mmapFd_;
434 }
435
ShouldUseMmap(int fd)436 bool FileSourceStream::ShouldUseMmap(int fd)
437 {
438 int location = INVALID_POSITION;
439 bool useMmap = false;
440 int err = ioctl(fd, HMDFS_IOC_GET_LOCATION, &location);
441 if (err != IOCTL_SUCCESS) {
442 IMAGE_LOGD("[FileSourceStream] ioctl failed, error: %{public}d, errno: %{public}d.", err, errno);
443 return useMmap;
444 }
445
446 if (location == LOCAL_FILE_POSITION) {
447 useMmap = true;
448 }
449 IMAGE_LOGD("[FileSourceStream] File position: %{public}d.", location);
450 return useMmap;
451 }
452
453 } // namespace Media
454 } // namespace OHOS
455