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