/src/ffmpeg/libavformat/os_support.h
Line | Count | Source |
1 | | /* |
2 | | * various OS-feature replacement utilities |
3 | | * copyright (c) 2000, 2001, 2002 Fabrice Bellard |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifndef AVFORMAT_OS_SUPPORT_H |
23 | | #define AVFORMAT_OS_SUPPORT_H |
24 | | |
25 | | /** |
26 | | * @file |
27 | | * miscellaneous OS support macros and functions. |
28 | | */ |
29 | | |
30 | | #include "config.h" |
31 | | |
32 | | #include <fcntl.h> |
33 | | #include <sys/stat.h> |
34 | | |
35 | | #ifndef O_BINARY |
36 | | #define O_BINARY 0 |
37 | | #endif |
38 | | |
39 | | #ifdef _WIN32 |
40 | | #if HAVE_DIRECT_H |
41 | | #include <direct.h> |
42 | | #endif |
43 | | #if HAVE_IO_H |
44 | | #include <io.h> |
45 | | #endif |
46 | | #endif |
47 | | |
48 | | #ifdef _WIN32 |
49 | | # include <stdint.h> |
50 | | # include <sys/types.h> |
51 | | # ifdef off_t |
52 | | # undef off_t |
53 | | # endif |
54 | | # define off_t int64_t |
55 | | # ifdef lseek |
56 | | # undef lseek |
57 | | # endif |
58 | | # define lseek(f,p,w) _lseeki64((f), (p), (w)) |
59 | | # ifdef stat |
60 | | # undef stat |
61 | | # endif |
62 | | |
63 | | # define stat win32_stat |
64 | | |
65 | | /* |
66 | | * The POSIX definition for the stat() function uses a struct of the |
67 | | * same name (struct stat), that why it takes this extra effort for |
68 | | * redirecting/replacing the stat() function with our own one which |
69 | | * is capable to handle long path names on Windows. |
70 | | * The struct below roughly follows the POSIX definition. Time values |
71 | | * are 64bit, but in cases when _USE_32BIT_TIME_T is defined, they |
72 | | * will be set to values no larger than INT32_MAX which corresponds |
73 | | * to file times up to the year 2038. |
74 | | */ |
75 | | struct win32_stat |
76 | | { |
77 | | _dev_t st_dev; /* ID of device containing file */ |
78 | | _ino_t st_ino; /* inode number */ |
79 | | unsigned short st_mode; /* protection */ |
80 | | short st_nlink; /* number of hard links */ |
81 | | short st_uid; /* user ID of owner */ |
82 | | short st_gid; /* group ID of owner */ |
83 | | _dev_t st_rdev; /* device ID (if special file) */ |
84 | | int64_t st_size; /* total size, in bytes */ |
85 | | int64_t st_atime; /* time of last access */ |
86 | | int64_t st_mtime; /* time of last modification */ |
87 | | int64_t st_ctime; /* time of last status change */ |
88 | | }; |
89 | | |
90 | | # ifdef fstat |
91 | | # undef fstat |
92 | | # endif |
93 | | # define fstat win32_fstat |
94 | | #endif /* defined(_WIN32) */ |
95 | | |
96 | | |
97 | | #ifdef __ANDROID__ |
98 | | # if HAVE_UNISTD_H |
99 | | # include <unistd.h> |
100 | | # endif |
101 | | # ifdef lseek |
102 | | # undef lseek |
103 | | # endif |
104 | | # define lseek(f,p,w) lseek64((f), (p), (w)) |
105 | | #endif |
106 | | |
107 | | static inline int is_dos_path(const char *path) |
108 | 0 | { |
109 | | #if HAVE_DOS_PATHS |
110 | | if (path[0] && path[1] == ':') |
111 | | return 1; |
112 | | #endif |
113 | 0 | return 0; |
114 | 0 | } Unexecuted instantiation: url.c:is_dos_path Unexecuted instantiation: utils.c:is_dos_path Unexecuted instantiation: avio.c:is_dos_path Unexecuted instantiation: network.c:is_dos_path Unexecuted instantiation: os_support.c:is_dos_path |
115 | | |
116 | | #if defined(_WIN32) |
117 | | #ifndef S_IRUSR |
118 | | #define S_IRUSR S_IREAD |
119 | | #endif |
120 | | #ifndef S_IWUSR |
121 | | #define S_IWUSR S_IWRITE |
122 | | #endif |
123 | | #endif |
124 | | |
125 | | #if CONFIG_NETWORK |
126 | | #if defined(_WIN32) |
127 | | #define SHUT_RD SD_RECEIVE |
128 | | #define SHUT_WR SD_SEND |
129 | | #define SHUT_RDWR SD_BOTH |
130 | | #else |
131 | | #include <sys/socket.h> |
132 | | #if !defined(SHUT_RD) /* OS/2, DJGPP */ |
133 | | #define SHUT_RD 0 |
134 | | #define SHUT_WR 1 |
135 | | #define SHUT_RDWR 2 |
136 | | #endif |
137 | | #endif |
138 | | |
139 | | #if !HAVE_SOCKLEN_T |
140 | | typedef int socklen_t; |
141 | | #endif |
142 | | |
143 | | /* most of the time closing a socket is just closing an fd */ |
144 | | #if !HAVE_CLOSESOCKET |
145 | 0 | #define closesocket close |
146 | | #endif |
147 | | |
148 | | #if !HAVE_POLL_H |
149 | | typedef unsigned long nfds_t; |
150 | | |
151 | | #if HAVE_WINSOCK2_H |
152 | | #include <winsock2.h> |
153 | | #endif |
154 | | #if !HAVE_STRUCT_POLLFD |
155 | | struct pollfd { |
156 | | int fd; |
157 | | short events; /* events to look for */ |
158 | | short revents; /* events that occurred */ |
159 | | }; |
160 | | |
161 | | /* events & revents */ |
162 | | #define POLLIN 0x0001 /* any readable data available */ |
163 | | #define POLLOUT 0x0002 /* file descriptor is writeable */ |
164 | | #define POLLRDNORM POLLIN |
165 | | #define POLLWRNORM POLLOUT |
166 | | #define POLLRDBAND 0x0008 /* priority readable data */ |
167 | | #define POLLWRBAND 0x0010 /* priority data can be written */ |
168 | | #define POLLPRI 0x0020 /* high priority readable data */ |
169 | | |
170 | | /* revents only */ |
171 | | #define POLLERR 0x0004 /* errors pending */ |
172 | | #define POLLHUP 0x0080 /* disconnected */ |
173 | | #define POLLNVAL 0x1000 /* invalid file descriptor */ |
174 | | #endif |
175 | | |
176 | | |
177 | | int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout); |
178 | | #define poll ff_poll |
179 | | #endif /* HAVE_POLL_H */ |
180 | | #endif /* CONFIG_NETWORK */ |
181 | | |
182 | | #ifdef _WIN32 |
183 | | #include <errno.h> |
184 | | #include <limits.h> |
185 | | #include <stdio.h> |
186 | | #include <windows.h> |
187 | | #include "libavutil/mem.h" |
188 | | #include "libavutil/wchar_filename.h" |
189 | | |
190 | | #ifndef _SSIZE_T_DEFINED |
191 | | #define _SSIZE_T_DEFINED |
192 | | typedef SSIZE_T ssize_t; |
193 | | #endif |
194 | | |
195 | | #define DEF_FS_FUNCTION(name, wfunc, afunc) \ |
196 | | static inline int win32_##name(const char *filename_utf8) \ |
197 | | { \ |
198 | | wchar_t *filename_w; \ |
199 | | int ret; \ |
200 | | \ |
201 | | if (get_extended_win32_path(filename_utf8, &filename_w)) \ |
202 | | return -1; \ |
203 | | if (!filename_w) \ |
204 | | goto fallback; \ |
205 | | \ |
206 | | ret = wfunc(filename_w); \ |
207 | | av_free(filename_w); \ |
208 | | return ret; \ |
209 | | \ |
210 | | fallback: \ |
211 | | /* filename may be be in CP_ACP */ \ |
212 | | return afunc(filename_utf8); \ |
213 | | } |
214 | | |
215 | | DEF_FS_FUNCTION(unlink, _wunlink, _unlink) |
216 | | DEF_FS_FUNCTION(mkdir, _wmkdir, _mkdir) |
217 | | DEF_FS_FUNCTION(rmdir, _wrmdir , _rmdir) |
218 | | |
219 | | static inline int win32_access(const char *filename_utf8, int mode) |
220 | | { |
221 | | wchar_t *filename_w; |
222 | | int ret; |
223 | | if (get_extended_win32_path(filename_utf8, &filename_w)) |
224 | | return -1; |
225 | | if (!filename_w) |
226 | | goto fallback; |
227 | | ret = _waccess(filename_w, mode); |
228 | | av_free(filename_w); |
229 | | return ret; |
230 | | fallback: |
231 | | return _access(filename_utf8, mode); |
232 | | } |
233 | | |
234 | | static inline void copy_stat(struct _stat64 *crtstat, struct win32_stat *buf) |
235 | | { |
236 | | buf->st_dev = crtstat->st_dev; |
237 | | buf->st_ino = crtstat->st_ino; |
238 | | buf->st_mode = crtstat->st_mode; |
239 | | buf->st_nlink = crtstat->st_nlink; |
240 | | buf->st_uid = crtstat->st_uid; |
241 | | buf->st_gid = crtstat->st_gid; |
242 | | buf->st_rdev = crtstat->st_rdev; |
243 | | buf->st_size = crtstat->st_size; |
244 | | buf->st_atime = crtstat->st_atime; |
245 | | buf->st_mtime = crtstat->st_mtime; |
246 | | buf->st_ctime = crtstat->st_ctime; |
247 | | } |
248 | | |
249 | | static inline int win32_stat(const char *filename_utf8, struct win32_stat *buf) |
250 | | { |
251 | | struct _stat64 crtstat = { 0 }; |
252 | | wchar_t *filename_w; |
253 | | int ret; |
254 | | |
255 | | if (get_extended_win32_path(filename_utf8, &filename_w)) |
256 | | return -1; |
257 | | |
258 | | if (filename_w) { |
259 | | ret = _wstat64(filename_w, &crtstat); |
260 | | av_free(filename_w); |
261 | | } else |
262 | | ret = _stat64(filename_utf8, &crtstat); |
263 | | |
264 | | copy_stat(&crtstat, buf); |
265 | | |
266 | | return ret; |
267 | | } |
268 | | |
269 | | static inline int win32_fstat(int fd, struct win32_stat *buf) |
270 | | { |
271 | | struct _stat64 crtstat = { 0 }; |
272 | | int ret; |
273 | | |
274 | | ret = _fstat64(fd, &crtstat); |
275 | | |
276 | | copy_stat(&crtstat, buf); |
277 | | |
278 | | return ret; |
279 | | } |
280 | | |
281 | | static inline int win32_rename(const char *src_utf8, const char *dest_utf8) |
282 | | { |
283 | | wchar_t *src_w, *dest_w; |
284 | | int ret; |
285 | | |
286 | | if (get_extended_win32_path(src_utf8, &src_w)) |
287 | | return -1; |
288 | | if (get_extended_win32_path(dest_utf8, &dest_w)) { |
289 | | av_free(src_w); |
290 | | return -1; |
291 | | } |
292 | | if (!src_w || !dest_w) { |
293 | | av_free(src_w); |
294 | | av_free(dest_w); |
295 | | goto fallback; |
296 | | } |
297 | | |
298 | | ret = (MoveFileExW(src_w, dest_w, MOVEFILE_REPLACE_EXISTING) == 0) ? -1 : 0; |
299 | | av_free(src_w); |
300 | | av_free(dest_w); |
301 | | // Lacking proper mapping from GetLastError() error codes to errno codes |
302 | | if (ret) |
303 | | errno = EPERM; |
304 | | return ret; |
305 | | |
306 | | fallback: |
307 | | /* filename may be be in CP_ACP */ |
308 | | #if !HAVE_UWP |
309 | | ret = (MoveFileExA(src_utf8, dest_utf8, MOVEFILE_REPLACE_EXISTING) == 0) ? -1 : 0; |
310 | | if (ret) |
311 | | errno = EPERM; |
312 | | #else |
313 | | /* Windows Phone doesn't have MoveFileExA, and for Windows Store apps, |
314 | | * it is available but not allowed by the app certification kit. However, |
315 | | * it's unlikely that anybody would input filenames in CP_ACP there, so this |
316 | | * fallback is kept mostly for completeness. Alternatively we could |
317 | | * do MultiByteToWideChar(CP_ACP) and use MoveFileExW, but doing |
318 | | * explicit conversions with CP_ACP is allegedly forbidden in windows |
319 | | * store apps (or windows phone), and the notion of a native code page |
320 | | * doesn't make much sense there. */ |
321 | | ret = rename(src_utf8, dest_utf8); |
322 | | #endif |
323 | | return ret; |
324 | | } |
325 | | |
326 | | /* |
327 | | * Positional I/O and file locking. Unlike pread() and pwrite() the Windows |
328 | | * versions move the file position of the descriptor. A flock() lock covers |
329 | | * only the first byte of the file, ReadFile() and WriteFile() of that byte |
330 | | * from other processes block or fail while the lock is held. Mapped |
331 | | * views of the file are not affected. |
332 | | */ |
333 | | #ifndef LOCK_SH |
334 | | #define LOCK_SH 1 |
335 | | #define LOCK_EX 2 |
336 | | #define LOCK_NB 4 |
337 | | #define LOCK_UN 8 |
338 | | #endif |
339 | | |
340 | | static inline ssize_t win32_pread(int fd, void *buf, size_t size, off_t offset) |
341 | | { |
342 | | HANDLE fh = (HANDLE)_get_osfhandle(fd); |
343 | | OVERLAPPED ov = { .Offset = offset, .OffsetHigh = offset >> 32 }; |
344 | | DWORD n; |
345 | | |
346 | | if (fh == INVALID_HANDLE_VALUE) |
347 | | return -1; |
348 | | if (size > INT_MAX) |
349 | | size = INT_MAX; |
350 | | if (!ReadFile(fh, buf, size, &n, &ov)) { |
351 | | if (GetLastError() == ERROR_HANDLE_EOF) |
352 | | return 0; |
353 | | errno = EIO; |
354 | | return -1; |
355 | | } |
356 | | return n; |
357 | | } |
358 | | |
359 | | static inline ssize_t win32_pwrite(int fd, const void *buf, size_t size, off_t offset) |
360 | | { |
361 | | HANDLE fh = (HANDLE)_get_osfhandle(fd); |
362 | | OVERLAPPED ov = { .Offset = offset, .OffsetHigh = offset >> 32 }; |
363 | | DWORD n; |
364 | | |
365 | | if (fh == INVALID_HANDLE_VALUE) |
366 | | return -1; |
367 | | if (size > INT_MAX) |
368 | | size = INT_MAX; |
369 | | if (!WriteFile(fh, buf, size, &n, &ov)) { |
370 | | errno = GetLastError() == ERROR_DISK_FULL ? ENOSPC : EIO; |
371 | | return -1; |
372 | | } |
373 | | return n; |
374 | | } |
375 | | |
376 | | static inline int win32_flock(int fd, int op) |
377 | | { |
378 | | HANDLE fh = (HANDLE)_get_osfhandle(fd); |
379 | | OVERLAPPED ov = { 0 }; |
380 | | BOOL ok; |
381 | | |
382 | | if (fh == INVALID_HANDLE_VALUE) |
383 | | return -1; |
384 | | if (op & LOCK_UN) { |
385 | | ok = UnlockFileEx(fh, 0, 1, 0, &ov); |
386 | | } else { |
387 | | DWORD flags = 0; |
388 | | if (op & LOCK_EX) |
389 | | flags |= LOCKFILE_EXCLUSIVE_LOCK; |
390 | | if (op & LOCK_NB) |
391 | | flags |= LOCKFILE_FAIL_IMMEDIATELY; |
392 | | ok = LockFileEx(fh, flags, 0, 1, 0, &ov); |
393 | | } |
394 | | if (!ok) { |
395 | | errno = GetLastError() == ERROR_LOCK_VIOLATION ? EWOULDBLOCK : EIO; |
396 | | return -1; |
397 | | } |
398 | | return 0; |
399 | | } |
400 | | |
401 | | #define mkdir(a, b) win32_mkdir(a) |
402 | | #define rename win32_rename |
403 | | #define rmdir win32_rmdir |
404 | | #define unlink win32_unlink |
405 | | #define access win32_access |
406 | | #define pread win32_pread |
407 | | #define pwrite win32_pwrite |
408 | | #define flock win32_flock |
409 | | |
410 | | #endif |
411 | | |
412 | | #endif /* AVFORMAT_OS_SUPPORT_H */ |