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