2012-02-03 07:05:11 +00:00
|
|
|
/*
|
|
|
|
* unicode/utf-8 I/O helpers and wrappers for Windows
|
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2012-02-03 07:05:11 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2012-02-03 07:05:11 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2012-02-03 07:05:11 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2012-02-03 07:05:11 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2012-02-03 07:05:11 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MPLAYER_OSDEP_IO
|
|
|
|
#define MPLAYER_OSDEP_IO
|
|
|
|
|
2014-02-13 07:18:58 +00:00
|
|
|
#include "config.h"
|
2013-11-30 21:40:51 +00:00
|
|
|
#include <stdbool.h>
|
2014-10-17 19:46:08 +00:00
|
|
|
#include <stdint.h>
|
2012-02-03 07:05:11 +00:00
|
|
|
#include <limits.h>
|
2013-11-30 21:40:51 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2017-11-12 15:20:24 +00:00
|
|
|
#include <locale.h>
|
2013-11-30 21:40:51 +00:00
|
|
|
|
2023-11-24 06:32:25 +00:00
|
|
|
#include "compiler.h"
|
|
|
|
|
2017-07-25 19:14:06 +00:00
|
|
|
#if HAVE_GLOB_POSIX
|
2014-02-13 07:18:58 +00:00
|
|
|
#include <glob.h>
|
|
|
|
#endif
|
|
|
|
|
2018-07-21 08:39:11 +00:00
|
|
|
#if HAVE_ANDROID
|
2017-09-18 17:25:34 +00:00
|
|
|
# include <unistd.h>
|
|
|
|
# include <stdio.h>
|
|
|
|
|
|
|
|
// replace lseek with the 64bit variant
|
|
|
|
#ifdef lseek
|
|
|
|
# undef lseek
|
|
|
|
#endif
|
|
|
|
#define lseek(f,p,w) lseek64((f), (p), (w))
|
|
|
|
|
|
|
|
// replace possible fseeko with a
|
|
|
|
// lseek64 based solution.
|
|
|
|
#ifdef fseeko
|
|
|
|
# undef fseeko
|
|
|
|
#endif
|
|
|
|
static inline int mp_fseeko(FILE* fp, off64_t offset, int whence) {
|
|
|
|
int ret = -1;
|
|
|
|
if ((ret = fflush(fp)) != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lseek64(fileno(fp), offset, whence) >= 0 ? 0 : -1;
|
|
|
|
}
|
|
|
|
#define fseeko(f,p,w) mp_fseeko((f), (p), (w))
|
|
|
|
|
2018-07-21 08:39:11 +00:00
|
|
|
#endif // HAVE_ANDROID
|
2017-09-18 17:25:34 +00:00
|
|
|
|
2013-12-18 16:12:16 +00:00
|
|
|
#ifndef O_BINARY
|
|
|
|
#define O_BINARY 0
|
|
|
|
#endif
|
|
|
|
|
2013-11-30 21:40:51 +00:00
|
|
|
// This is in POSIX.1-2008, but support outside of Linux is scarce.
|
|
|
|
#ifndef O_CLOEXEC
|
|
|
|
#define O_CLOEXEC 0
|
|
|
|
#endif
|
2014-04-12 18:13:07 +00:00
|
|
|
#ifndef FD_CLOEXEC
|
|
|
|
#define FD_CLOEXEC 0
|
|
|
|
#endif
|
2013-11-30 21:40:51 +00:00
|
|
|
|
|
|
|
bool mp_set_cloexec(int fd);
|
2014-10-25 23:18:55 +00:00
|
|
|
int mp_make_cloexec_pipe(int pipes[2]);
|
2014-05-29 21:56:56 +00:00
|
|
|
int mp_make_wakeup_pipe(int pipes[2]);
|
2016-07-29 01:24:52 +00:00
|
|
|
void mp_flush_wakeup_pipe(int pipe_end);
|
2012-02-03 07:05:11 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
2023-12-23 17:46:54 +00:00
|
|
|
|
2015-08-01 18:51:52 +00:00
|
|
|
#include <wchar.h>
|
|
|
|
wchar_t *mp_from_utf8(void *talloc_ctx, const char *s);
|
|
|
|
char *mp_to_utf8(void *talloc_ctx, const wchar_t *s);
|
2023-12-23 17:46:54 +00:00
|
|
|
|
|
|
|
// Use this in win32-specific code rather than PATH_MAX or MAX_PATH.
|
|
|
|
// This is necessary because we declare long-path aware support which raises
|
|
|
|
// the effective limit without affecting any defines.
|
|
|
|
// The actual limit is 32767 but there's a few edge cases that reduce
|
|
|
|
// it. So pick this nice round number.
|
|
|
|
// Note that this is wchars, not chars.
|
|
|
|
#define MP_PATH_MAX (32000)
|
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#endif
|
|
|
|
|
2012-09-30 12:47:37 +00:00
|
|
|
#ifdef __CYGWIN__
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2023-11-24 06:32:25 +00:00
|
|
|
int mp_printf(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
|
|
|
|
int mp_fprintf(FILE *stream, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
|
2012-02-03 07:05:11 +00:00
|
|
|
int mp_open(const char *filename, int oflag, ...);
|
|
|
|
int mp_creat(const char *filename, int mode);
|
2023-11-06 21:24:10 +00:00
|
|
|
int mp_rename(const char *oldpath, const char *newpath);
|
2012-02-03 07:05:11 +00:00
|
|
|
FILE *mp_fopen(const char *filename, const char *mode);
|
|
|
|
DIR *mp_opendir(const char *path);
|
|
|
|
struct dirent *mp_readdir(DIR *dir);
|
|
|
|
int mp_closedir(DIR *dir);
|
|
|
|
int mp_mkdir(const char *path, int mode);
|
2017-04-11 10:16:07 +00:00
|
|
|
char *mp_win32_getcwd(char *buf, size_t size);
|
2013-09-18 15:49:10 +00:00
|
|
|
char *mp_getenv(const char *name);
|
2020-08-05 11:57:23 +00:00
|
|
|
|
|
|
|
#ifdef environ /* mingw defines it as _environ */
|
|
|
|
#undef environ
|
|
|
|
#endif
|
|
|
|
#define environ (*mp_penviron()) /* ensure initialization and l-value */
|
|
|
|
char ***mp_penviron(void);
|
|
|
|
|
2014-10-17 19:37:38 +00:00
|
|
|
off_t mp_lseek(int fd, off_t offset, int whence);
|
2020-06-12 08:41:48 +00:00
|
|
|
void *mp_dlopen(const char *filename, int flag);
|
|
|
|
void *mp_dlsym(void *handle, const char *symbol);
|
|
|
|
char *mp_dlerror(void);
|
2012-02-03 07:05:11 +00:00
|
|
|
|
2017-10-23 10:01:45 +00:00
|
|
|
// mp_stat types. MSVCRT's dev_t and ino_t are way too short to be unique.
|
|
|
|
typedef uint64_t mp_dev_t_;
|
|
|
|
#ifdef _WIN64
|
|
|
|
typedef unsigned __int128 mp_ino_t_;
|
|
|
|
#else
|
|
|
|
// 32-bit Windows doesn't have a __int128-type, which means ReFS file IDs will
|
|
|
|
// be truncated and might collide. This is probably not a problem because ReFS
|
|
|
|
// is not available in consumer versions of Windows.
|
|
|
|
typedef uint64_t mp_ino_t_;
|
|
|
|
#endif
|
|
|
|
#define dev_t mp_dev_t_
|
|
|
|
#define ino_t mp_ino_t_
|
|
|
|
|
|
|
|
// mp_stat uses a different structure to MSVCRT, with 64-bit inodes
|
2014-10-17 19:46:08 +00:00
|
|
|
struct mp_stat {
|
|
|
|
dev_t st_dev;
|
|
|
|
ino_t st_ino;
|
|
|
|
unsigned short st_mode;
|
2017-10-23 10:01:45 +00:00
|
|
|
unsigned int st_nlink;
|
2014-10-17 19:46:08 +00:00
|
|
|
short st_uid;
|
|
|
|
short st_gid;
|
|
|
|
dev_t st_rdev;
|
|
|
|
int64_t st_size;
|
|
|
|
time_t st_atime;
|
|
|
|
time_t st_mtime;
|
|
|
|
time_t st_ctime;
|
|
|
|
};
|
|
|
|
|
|
|
|
int mp_stat(const char *path, struct mp_stat *buf);
|
|
|
|
int mp_fstat(int fd, struct mp_stat *buf);
|
|
|
|
|
2014-02-13 07:18:58 +00:00
|
|
|
typedef struct {
|
|
|
|
size_t gl_pathc;
|
|
|
|
char **gl_pathv;
|
|
|
|
size_t gl_offs;
|
|
|
|
void *ctx;
|
|
|
|
} mp_glob_t;
|
|
|
|
|
|
|
|
// glob-win.c
|
|
|
|
int mp_glob(const char *restrict pattern, int flags,
|
|
|
|
int (*errfunc)(const char*, int), mp_glob_t *restrict pglob);
|
|
|
|
void mp_globfree(mp_glob_t *pglob);
|
|
|
|
|
2012-04-06 21:42:02 +00:00
|
|
|
#define printf(...) mp_printf(__VA_ARGS__)
|
2011-10-22 14:24:16 +00:00
|
|
|
#define fprintf(...) mp_fprintf(__VA_ARGS__)
|
2012-02-03 07:05:11 +00:00
|
|
|
#define open(...) mp_open(__VA_ARGS__)
|
|
|
|
#define creat(...) mp_creat(__VA_ARGS__)
|
2023-11-06 21:24:10 +00:00
|
|
|
#define rename(...) mp_rename(__VA_ARGS__)
|
2012-02-03 07:05:11 +00:00
|
|
|
#define fopen(...) mp_fopen(__VA_ARGS__)
|
|
|
|
#define opendir(...) mp_opendir(__VA_ARGS__)
|
|
|
|
#define readdir(...) mp_readdir(__VA_ARGS__)
|
|
|
|
#define closedir(...) mp_closedir(__VA_ARGS__)
|
|
|
|
#define mkdir(...) mp_mkdir(__VA_ARGS__)
|
2017-04-11 10:16:07 +00:00
|
|
|
#define getcwd(...) mp_win32_getcwd(__VA_ARGS__)
|
2013-09-18 15:49:10 +00:00
|
|
|
#define getenv(...) mp_getenv(__VA_ARGS__)
|
2012-02-03 07:05:11 +00:00
|
|
|
|
2014-10-17 19:37:38 +00:00
|
|
|
#undef lseek
|
|
|
|
#define lseek(...) mp_lseek(__VA_ARGS__)
|
|
|
|
|
2020-06-12 08:41:48 +00:00
|
|
|
#define RTLD_NOW 0
|
|
|
|
#define RTLD_LOCAL 0
|
|
|
|
#define dlopen(fn,fg) mp_dlopen((fn), (fg))
|
|
|
|
#define dlsym(h,s) mp_dlsym((h), (s))
|
|
|
|
#define dlerror mp_dlerror
|
|
|
|
|
2014-10-18 21:40:35 +00:00
|
|
|
// Affects both "stat()" and "struct stat".
|
2014-10-17 19:46:08 +00:00
|
|
|
#undef stat
|
|
|
|
#define stat mp_stat
|
2014-10-18 21:40:35 +00:00
|
|
|
|
2014-10-17 19:46:08 +00:00
|
|
|
#undef fstat
|
|
|
|
#define fstat(...) mp_fstat(__VA_ARGS__)
|
|
|
|
|
player: Optionally validate st_mtime when restoring playback state
I often watch sporting events. On many occasions I get files with the
same filename for each session. For example, for F1 I might have the
following directory structure:
F1/
FP1.mkv
FP2.mkv
FP3.mkv
Qualification.mkv
Race.mkv
Since usually one simply watches one race after the other, I usually
just rsync the new event's files over the old ones, so, for example,
Race.mkv will be replaced from the file for the last event with the file
from the new event.
One problem with this is that I like to use --resume-playback for other
kinds of media, so I have it on by default. That works great for, say, a
movie, but doesn't work so well with this scheme, because you can
trivially forget to pass --no-resume-playback on the command line and
end up 2 hours in, watching spoilers as the race results scroll down the
screen :-)
This patch adds a new option, --resume-playback-check-mtime, which
validates that the file's mtime hasn't changed since the watch_later
configuration was saved. It does this by setting the watch_later
configuration to have the same mtime as the file after it is saved.
Switching back and forth between checking mtime and not checking mtime
works fine, as we only choose whether to compare based on it, but we
update the watch_later configuration mtime regardless of its value.
2019-11-09 18:24:16 +00:00
|
|
|
#define utime(...) _utime(__VA_ARGS__)
|
|
|
|
#define utimbuf _utimbuf
|
|
|
|
|
2014-12-26 16:14:48 +00:00
|
|
|
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
|
|
|
|
int munmap(void *addr, size_t length);
|
|
|
|
int msync(void *addr, size_t length, int flags);
|
|
|
|
#define PROT_READ 1
|
|
|
|
#define PROT_WRITE 2
|
|
|
|
#define MAP_SHARED 1
|
|
|
|
#define MAP_FAILED ((void *)-1)
|
|
|
|
#define MS_ASYNC 1
|
|
|
|
#define MS_SYNC 2
|
|
|
|
#define MS_INVALIDATE 4
|
|
|
|
|
2014-02-13 07:18:58 +00:00
|
|
|
#ifndef GLOB_NOMATCH
|
|
|
|
#define GLOB_NOMATCH 3
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define glob_t mp_glob_t
|
|
|
|
#define glob(...) mp_glob(__VA_ARGS__)
|
|
|
|
#define globfree(...) mp_globfree(__VA_ARGS__)
|
|
|
|
|
2017-11-18 11:36:20 +00:00
|
|
|
// These are stubs since there is not anything that helps with this on Windows.
|
2017-11-12 15:20:24 +00:00
|
|
|
#define locale_t int
|
2019-05-03 16:54:31 +00:00
|
|
|
#define LC_CTYPE_MASK 0
|
2017-11-18 11:36:20 +00:00
|
|
|
locale_t newlocale(int, const char *, locale_t);
|
|
|
|
locale_t uselocale(locale_t);
|
|
|
|
void freelocale(locale_t);
|
2017-11-12 15:20:24 +00:00
|
|
|
|
2014-12-26 16:14:48 +00:00
|
|
|
#else /* __MINGW32__ */
|
|
|
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
2020-08-05 11:57:23 +00:00
|
|
|
extern char **environ;
|
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#endif /* __MINGW32__ */
|
|
|
|
|
osdep: add mkostemps() emulation
Supposed to follow the standard function.
The standard function is not standard, but a GNU extension. Adding some
ifdef mess is pointless too - it has no advantages other than having a
mess, and not spotting implementation bugs in the emulation due to
running it only on "obscure" platforms (like Windows, so most computers
actually, except the developer's platform).
There is mkstemp(), which at least is in POSIX 2008. But it's 100%
useless, except in some obscure cases: it doesn't set O_CLOEXEC, nor can
you pass it to it. Without O_CLOEXEC, we'd leak the temporary file to
all child processes. (The fact that the file, which is expected to reach
double or tripple digit GB sizes, will be deleted only once all
processes unreference the FD, makes this sort of a big deal. You could
ftruncate() it, but that doesn't fix all the other problems.)
Why did POSIX standardize mkstemp() and O_CLOEXEC apparently at the same
time, but provided no way to pass O_CLOEXEC to mkstemp()? With the
introduction of O_CLOEXEC, they acknowledged that there's a need to
atomically set the FD_CLOEXEC flag when creating file descriptors.
(FD_CLOEXEC was standard before that, but setting it with fcntl() is
racy.) You're much more likely to need a temp file that is CLOEXEC
rather than the opposite, and even if they were somehow opposed to
CLOEXEC by default (such as for compat. reasons), surely POSIX could
have standardized mkostemp() too or instead.
And then there's the fact that this whole O_CLOEXEC mess is stupid.
Surely there would have been a better way to handle this, instead of
requiring adding O_CLOEXEC to almost ALL instances of open() in all code
that has been written ever. The justification for this is that the
historic default was wrong, and you can't change it (e.g. this won't
work: changing the behavior of exec() and not inherit the FD to the
child process, unless a hypothetical O_KEEP_EXEC flag is set).
But on the other hand, surely you could have introduced an exec()
variant which does close all FDs, except a whitelist of FDs passed to
it. Let's call it execve2(). In fact, I'm going to argue that exec()
call sites are the most aware of whether (and which) FDs to inherit.
Some programs even tried to explicitly iterate over all opened FDs and
explicitly close "unwanted" FDs (which of course was problematic for
other reasons), and such an execve2() call would have been the ideal
solution.
Maybe this proposed solution would have had problems too. But surely
revisiting and reviewing every exec*() call would have been simpler than
reviewing every open() call. And more importantly, having to extend
every damn library function that either calls open() or creates FDs in
some other way, like mkstemp().
What argument are there going to be against this? That there will be
library code that can't keep working correctly with processes that use
the "old" exec? Well, what about all my legacy library code that uses
open() incorrectly, and that will break no matter what?
Well, I'm not going to claim that I can come up with better solutions
than POSIX (generally or in this case), but this situation is ABSOLUTELY
ATROCIOUS. It makes win32 programming look attractive compared to POSIX,
that standard pandering to dead people from the past. (Note: not trying
to insult dead people.)
I'm not sure what POSIX is even doing. Anything useful? Doesn't look
like it to me. Are they paid? Why? They didn't even fix the locale mess,
nor do they intend to. I bet they're proud of discussing compatibility
to 70ies code day in and day out iwtohut ever producing anything useful.
What a load of crap. They seriously got to do better than this.
Oh, and my wrapper is probably buggy. Fortunately that doesn't matter.
Also I'm dumping this into io.h. Originally, io.h was just supposed to
replace broken implementation of standard functions by MinGW (and then
by Android), but whatever, just give a dumping ground for shit code.
2019-06-13 16:23:05 +00:00
|
|
|
int mp_mkostemps(char *template, int suffixlen, int flags);
|
2023-11-21 07:32:21 +00:00
|
|
|
bool mp_save_to_file(const char *filepath, const void *data, size_t size);
|
osdep: add mkostemps() emulation
Supposed to follow the standard function.
The standard function is not standard, but a GNU extension. Adding some
ifdef mess is pointless too - it has no advantages other than having a
mess, and not spotting implementation bugs in the emulation due to
running it only on "obscure" platforms (like Windows, so most computers
actually, except the developer's platform).
There is mkstemp(), which at least is in POSIX 2008. But it's 100%
useless, except in some obscure cases: it doesn't set O_CLOEXEC, nor can
you pass it to it. Without O_CLOEXEC, we'd leak the temporary file to
all child processes. (The fact that the file, which is expected to reach
double or tripple digit GB sizes, will be deleted only once all
processes unreference the FD, makes this sort of a big deal. You could
ftruncate() it, but that doesn't fix all the other problems.)
Why did POSIX standardize mkstemp() and O_CLOEXEC apparently at the same
time, but provided no way to pass O_CLOEXEC to mkstemp()? With the
introduction of O_CLOEXEC, they acknowledged that there's a need to
atomically set the FD_CLOEXEC flag when creating file descriptors.
(FD_CLOEXEC was standard before that, but setting it with fcntl() is
racy.) You're much more likely to need a temp file that is CLOEXEC
rather than the opposite, and even if they were somehow opposed to
CLOEXEC by default (such as for compat. reasons), surely POSIX could
have standardized mkostemp() too or instead.
And then there's the fact that this whole O_CLOEXEC mess is stupid.
Surely there would have been a better way to handle this, instead of
requiring adding O_CLOEXEC to almost ALL instances of open() in all code
that has been written ever. The justification for this is that the
historic default was wrong, and you can't change it (e.g. this won't
work: changing the behavior of exec() and not inherit the FD to the
child process, unless a hypothetical O_KEEP_EXEC flag is set).
But on the other hand, surely you could have introduced an exec()
variant which does close all FDs, except a whitelist of FDs passed to
it. Let's call it execve2(). In fact, I'm going to argue that exec()
call sites are the most aware of whether (and which) FDs to inherit.
Some programs even tried to explicitly iterate over all opened FDs and
explicitly close "unwanted" FDs (which of course was problematic for
other reasons), and such an execve2() call would have been the ideal
solution.
Maybe this proposed solution would have had problems too. But surely
revisiting and reviewing every exec*() call would have been simpler than
reviewing every open() call. And more importantly, having to extend
every damn library function that either calls open() or creates FDs in
some other way, like mkstemp().
What argument are there going to be against this? That there will be
library code that can't keep working correctly with processes that use
the "old" exec? Well, what about all my legacy library code that uses
open() incorrectly, and that will break no matter what?
Well, I'm not going to claim that I can come up with better solutions
than POSIX (generally or in this case), but this situation is ABSOLUTELY
ATROCIOUS. It makes win32 programming look attractive compared to POSIX,
that standard pandering to dead people from the past. (Note: not trying
to insult dead people.)
I'm not sure what POSIX is even doing. Anything useful? Doesn't look
like it to me. Are they paid? Why? They didn't even fix the locale mess,
nor do they intend to. I bet they're proud of discussing compatibility
to 70ies code day in and day out iwtohut ever producing anything useful.
What a load of crap. They seriously got to do better than this.
Oh, and my wrapper is probably buggy. Fortunately that doesn't matter.
Also I'm dumping this into io.h. Originally, io.h was just supposed to
replace broken implementation of standard functions by MinGW (and then
by Android), but whatever, just give a dumping ground for shit code.
2019-06-13 16:23:05 +00:00
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#endif
|