• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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