Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 */