Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 | ||
38 | typedef struct { | |
39 | const AVClass *class; | |
40 | int log_offset; | |
41 | void *log_ctx; | |
42 | } FileLogContext; | |
43 | ||
44 | static const AVClass file_log_ctx_class = { | |
45 | "FILE", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, | |
46 | offsetof(FileLogContext, log_offset), offsetof(FileLogContext, log_ctx) | |
47 | }; | |
48 | ||
49 | int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, | |
50 | int log_offset, void *log_ctx) | |
51 | { | |
52 | FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; | |
53 | int err, fd = avpriv_open(filename, O_RDONLY); | |
54 | struct stat st; | |
55 | av_unused void *ptr; | |
56 | off_t off_size; | |
57 | char errbuf[128]; | |
58 | *bufptr = NULL; | |
59 | ||
60 | if (fd < 0) { | |
61 | err = AVERROR(errno); | |
62 | av_strerror(err, errbuf, sizeof(errbuf)); | |
63 | av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, errbuf); | |
64 | return err; | |
65 | } | |
66 | ||
67 | if (fstat(fd, &st) < 0) { | |
68 | err = AVERROR(errno); | |
69 | av_strerror(err, errbuf, sizeof(errbuf)); | |
70 | av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", errbuf); | |
71 | close(fd); | |
72 | return err; | |
73 | } | |
74 | ||
75 | off_size = st.st_size; | |
76 | if (off_size > SIZE_MAX) { | |
77 | av_log(&file_log_ctx, AV_LOG_ERROR, | |
78 | "File size for file '%s' is too big\n", filename); | |
79 | close(fd); | |
80 | return AVERROR(EINVAL); | |
81 | } | |
82 | *size = off_size; | |
83 | ||
84 | #if HAVE_MMAP | |
85 | ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); | |
86 | if (ptr == MAP_FAILED) { | |
87 | err = AVERROR(errno); | |
88 | av_strerror(err, errbuf, sizeof(errbuf)); | |
89 | av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf); | |
90 | close(fd); | |
91 | return err; | |
92 | } | |
93 | *bufptr = ptr; | |
94 | #elif HAVE_MAPVIEWOFFILE | |
95 | { | |
96 | HANDLE mh, fh = (HANDLE)_get_osfhandle(fd); | |
97 | ||
98 | mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL); | |
99 | if (!mh) { | |
100 | av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n"); | |
101 | close(fd); | |
102 | return -1; | |
103 | } | |
104 | ||
105 | ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, *size); | |
106 | CloseHandle(mh); | |
107 | if (!ptr) { | |
108 | av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n"); | |
109 | close(fd); | |
110 | return -1; | |
111 | } | |
112 | ||
113 | *bufptr = ptr; | |
114 | } | |
115 | #else | |
116 | *bufptr = av_malloc(*size); | |
117 | if (!*bufptr) { | |
118 | av_log(&file_log_ctx, AV_LOG_ERROR, "Memory allocation error occurred\n"); | |
119 | close(fd); | |
120 | return AVERROR(ENOMEM); | |
121 | } | |
122 | read(fd, *bufptr, *size); | |
123 | #endif | |
124 | ||
125 | close(fd); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | void av_file_unmap(uint8_t *bufptr, size_t size) | |
130 | { | |
131 | #if HAVE_MMAP | |
132 | munmap(bufptr, size); | |
133 | #elif HAVE_MAPVIEWOFFILE | |
134 | UnmapViewOfFile(bufptr); | |
135 | #else | |
136 | av_free(bufptr); | |
137 | #endif | |
138 | } | |
139 | ||
140 | int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) | |
141 | { | |
142 | FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; | |
143 | int fd = -1; | |
144 | #if !HAVE_MKSTEMP | |
145 | void *ptr= tempnam(NULL, prefix); | |
146 | if(!ptr) | |
147 | ptr= tempnam(".", prefix); | |
148 | *filename = av_strdup(ptr); | |
149 | #undef free | |
150 | free(ptr); | |
151 | #else | |
152 | size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */ | |
153 | *filename = av_malloc(len); | |
154 | #endif | |
155 | /* -----common section-----*/ | |
156 | if (!*filename) { | |
157 | av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot allocate file name\n"); | |
158 | return AVERROR(ENOMEM); | |
159 | } | |
160 | #if !HAVE_MKSTEMP | |
161 | # ifndef O_BINARY | |
162 | # define O_BINARY 0 | |
163 | # endif | |
164 | # ifndef O_EXCL | |
165 | # define O_EXCL 0 | |
166 | # endif | |
167 | fd = open(*filename, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600); | |
168 | #else | |
169 | snprintf(*filename, len, "/tmp/%sXXXXXX", prefix); | |
170 | fd = mkstemp(*filename); | |
171 | #ifdef _WIN32 | |
172 | if (fd < 0) { | |
173 | snprintf(*filename, len, "./%sXXXXXX", prefix); | |
174 | fd = mkstemp(*filename); | |
175 | } | |
176 | #endif | |
177 | #endif | |
178 | /* -----common section-----*/ | |
179 | if (fd < 0) { | |
180 | int err = AVERROR(errno); | |
181 | av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot open temporary file %s\n", *filename); | |
182 | av_freep(filename); | |
183 | return err; | |
184 | } | |
185 | return fd; /* success */ | |
186 | } | |
187 | ||
188 | #ifdef TEST | |
189 | ||
190 | #undef printf | |
191 | ||
192 | int main(void) | |
193 | { | |
194 | uint8_t *buf; | |
195 | size_t size; | |
196 | if (av_file_map("file.c", &buf, &size, 0, NULL) < 0) | |
197 | return 1; | |
198 | ||
199 | buf[0] = 's'; | |
200 | printf("%s", buf); | |
201 | av_file_unmap(buf, size); | |
202 | return 0; | |
203 | } | |
204 | #endif | |
205 |