1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "file.h" 21#include "internal.h" 22#include "log.h" 23#include "mem.h" 24#include <fcntl.h> 25#include <sys/stat.h> 26#if HAVE_UNISTD_H 27#include <unistd.h> 28#endif 29#if HAVE_IO_H 30#include <io.h> 31#endif 32#if HAVE_MMAP 33#include <sys/mman.h> 34#elif HAVE_MAPVIEWOFFILE 35#include <windows.h> 36#endif 37 38typedef struct FileLogContext { 39 const AVClass *class; 40 int log_offset; 41 void *log_ctx; 42} FileLogContext; 43 44static const AVClass file_log_ctx_class = { 45 .class_name = "FILE", 46 .item_name = av_default_item_name, 47 .option = NULL, 48 .version = LIBAVUTIL_VERSION_INT, 49 .log_level_offset_offset = offsetof(FileLogContext, log_offset), 50 .parent_log_context_offset = offsetof(FileLogContext, log_ctx), 51}; 52 53int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, 54 int log_offset, void *log_ctx) 55{ 56 FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; 57 int err, fd = avpriv_open(filename, O_RDONLY); 58 struct stat st; 59 av_unused void *ptr; 60 off_t off_size; 61 char errbuf[128]; 62 *bufptr = NULL; 63 *size = 0; 64 65 if (fd < 0) { 66 err = AVERROR(errno); 67 av_strerror(err, errbuf, sizeof(errbuf)); 68 av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, errbuf); 69 return err; 70 } 71 72 if (fstat(fd, &st) < 0) { 73 err = AVERROR(errno); 74 av_strerror(err, errbuf, sizeof(errbuf)); 75 av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", errbuf); 76 close(fd); 77 return err; 78 } 79 80 off_size = st.st_size; 81 if (off_size > SIZE_MAX) { 82 av_log(&file_log_ctx, AV_LOG_ERROR, 83 "File size for file '%s' is too big\n", filename); 84 close(fd); 85 return AVERROR(EINVAL); 86 } 87 *size = off_size; 88 89 if (!*size) { 90 *bufptr = NULL; 91 goto out; 92 } 93 94#if HAVE_MMAP 95 ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 96 if (ptr == MAP_FAILED) { 97 err = AVERROR(errno); 98 av_strerror(err, errbuf, sizeof(errbuf)); 99 av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf); 100 close(fd); 101 *size = 0; 102 return err; 103 } 104 *bufptr = ptr; 105#elif HAVE_MAPVIEWOFFILE 106 { 107 HANDLE mh, fh = (HANDLE)_get_osfhandle(fd); 108 109 mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL); 110 if (!mh) { 111 av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n"); 112 close(fd); 113 *size = 0; 114 return -1; 115 } 116 117 ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, *size); 118 CloseHandle(mh); 119 if (!ptr) { 120 av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n"); 121 close(fd); 122 *size = 0; 123 return -1; 124 } 125 126 *bufptr = ptr; 127 } 128#else 129 *bufptr = av_malloc(*size); 130 if (!*bufptr) { 131 av_log(&file_log_ctx, AV_LOG_ERROR, "Memory allocation error occurred\n"); 132 close(fd); 133 *size = 0; 134 return AVERROR(ENOMEM); 135 } 136 read(fd, *bufptr, *size); 137#endif 138 139out: 140 close(fd); 141 return 0; 142} 143 144void av_file_unmap(uint8_t *bufptr, size_t size) 145{ 146 if (!size || !bufptr) 147 return; 148#if HAVE_MMAP 149 munmap(bufptr, size); 150#elif HAVE_MAPVIEWOFFILE 151 UnmapViewOfFile(bufptr); 152#else 153 av_free(bufptr); 154#endif 155} 156 157int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) { 158 return avpriv_tempfile(prefix, filename, log_offset, log_ctx); 159} 160