diff options
Diffstat (limited to 'osdep/io.c')
-rw-r--r-- | osdep/io.c | 238 |
1 files changed, 156 insertions, 82 deletions
diff --git a/osdep/io.c b/osdep/io.c index d4dcfc6fba..a58eb6ec04 100644 --- a/osdep/io.c +++ b/osdep/io.c @@ -27,11 +27,12 @@ #include <sys/types.h> #include <sys/stat.h> #include <limits.h> -#include <unistd.h> #include "mpv_talloc.h" #include "config.h" +#include "common/common.h" +#include "misc/random.h" #include "osdep/io.h" #include "osdep/terminal.h" @@ -61,7 +62,7 @@ bool mp_set_cloexec(int fd) return true; } -#ifdef __MINGW32__ +#ifdef _WIN32 int mp_make_cloexec_pipe(int pipes[2]) { pipes[0] = pipes[1] = -1; @@ -81,7 +82,7 @@ int mp_make_cloexec_pipe(int pipes[2]) } #endif -#ifdef __MINGW32__ +#ifdef _WIN32 int mp_make_wakeup_pipe(int pipes[2]) { return mp_make_cloexec_pipe(pipes); @@ -103,7 +104,7 @@ int mp_make_wakeup_pipe(int pipes[2]) void mp_flush_wakeup_pipe(int pipe_end) { -#ifndef __MINGW32__ +#ifndef _WIN32 char buf[100]; (void)read(pipe_end, buf, sizeof(buf)); #endif @@ -141,11 +142,11 @@ char *mp_to_utf8(void *talloc_ctx, const wchar_t *s) #endif // _WIN32 -#ifdef __MINGW32__ +#ifdef _WIN32 #include <io.h> #include <fcntl.h> -#include <pthread.h> +#include "osdep/threads.h" static void set_errno_from_lasterror(void) { @@ -188,7 +189,7 @@ static bool get_file_ids_win8(HANDLE h, dev_t *dev, ino_t *ino) // SDK, but we can ignore that by just memcpying it. This will also // truncate the file ID on 32-bit Windows, which doesn't support __int128. // 128-bit file IDs are only used for ReFS, so that should be okay. - assert(sizeof(*ino) <= sizeof(ii.FileId)); + static_assert(sizeof(*ino) <= sizeof(ii.FileId), ""); memcpy(ino, &ii.FileId, sizeof(*ino)); return true; } @@ -297,62 +298,53 @@ int mp_fstat(int fd, struct mp_stat *buf) return hstat(h, buf); } -#if HAVE_UWP -static int mp_vfprintf(FILE *stream, const char *format, va_list args) -{ - return vfprintf(stream, format, args); -} -#else -static int mp_check_console(HANDLE wstream) +static inline HANDLE get_handle(FILE *stream) { - if (wstream != INVALID_HANDLE_VALUE) { - unsigned int filetype = GetFileType(wstream); + HANDLE wstream = INVALID_HANDLE_VALUE; - if (!((filetype == FILE_TYPE_UNKNOWN) && - (GetLastError() != ERROR_SUCCESS))) - { - filetype &= ~(FILE_TYPE_REMOTE); + if (stream == stdout || stream == stderr) { + wstream = GetStdHandle(stream == stdout ? + STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + } + return wstream; +} - if (filetype == FILE_TYPE_CHAR) { - DWORD ConsoleMode; - int ret = GetConsoleMode(wstream, &ConsoleMode); +size_t mp_fwrite(const void *restrict buffer, size_t size, size_t count, + FILE *restrict stream) +{ + if (!size || !count) + return 0; - if (!(!ret && (GetLastError() == ERROR_INVALID_HANDLE))) { - // This seems to be a console - return 1; - } - } + HANDLE wstream = get_handle(stream); + if (mp_check_console(wstream)) { + unsigned char *start = (unsigned char *)buffer; + size_t c = 0; + for (; c < count; ++c) { + if (mp_console_write(wstream, (bstr){start, size}) <= 0) + break; + start += size; } + return c; } - return 0; +#undef fwrite + return fwrite(buffer, size, count, stream); } +#if HAVE_UWP static int mp_vfprintf(FILE *stream, const char *format, va_list args) { - int done = 0; - - HANDLE wstream = INVALID_HANDLE_VALUE; - - if (stream == stdout || stream == stderr) { - wstream = GetStdHandle(stream == stdout ? - STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); - } - - if (mp_check_console(wstream)) { - size_t len = vsnprintf(NULL, 0, format, args) + 1; - char *buf = talloc_array(NULL, char, len); + return vfprintf(stream, format, args); +} +#else - if (buf) { - done = vsnprintf(buf, len, format, args); - mp_write_console_ansi(wstream, buf); - } - talloc_free(buf); - } else { - done = vfprintf(stream, format, args); - } +static int mp_vfprintf(FILE *stream, const char *format, va_list args) +{ + HANDLE wstream = get_handle(stream); + if (mp_check_console(wstream)) + return mp_console_vfprintf(wstream, format, args); - return done; + return vfprintf(stream, format, args); } #endif @@ -483,6 +475,20 @@ int mp_creat(const char *filename, int mode) return mp_open(filename, _O_CREAT | _O_WRONLY | _O_TRUNC, mode); } +int mp_rename(const char *oldpath, const char *newpath) +{ + wchar_t *woldpath = mp_from_utf8(NULL, oldpath), + *wnewpath = mp_from_utf8(NULL, newpath); + BOOL ok = MoveFileExW(woldpath, wnewpath, MOVEFILE_REPLACE_EXISTING); + talloc_free(woldpath); + talloc_free(wnewpath); + if (!ok) { + set_errno_from_lasterror(); + return -1; + } + return 0; +} + FILE *mp_fopen(const char *filename, const char *mode) { if (!mode[0]) { @@ -543,7 +549,9 @@ FILE *mp_fopen(const char *filename, const char *mode) // Thus we need MP_PATH_MAX as the UTF-8/char version of PATH_MAX. // Also make sure there's free space for the terminating \0. // (For codepoints encoded as UTF-16 surrogate pairs, UTF-8 has the same length.) -#define MP_PATH_MAX (FILENAME_MAX * 3 + 1) +// Lastly, note that neither _wdirent nor WIN32_FIND_DATA can store filenames +// longer than this, so long-path support for readdir() is impossible. +#define MP_FILENAME_MAX (FILENAME_MAX * 3 + 1) struct mp_dir { DIR crap; // must be first member @@ -553,9 +561,9 @@ struct mp_dir { // dirent has space only for FILENAME_MAX bytes. _wdirent has space for // FILENAME_MAX wchar_t, which might end up bigger as UTF-8 in some // cases. Guarantee we can always hold _wdirent.d_name converted to - // UTF-8 (see MP_PATH_MAX). + // UTF-8 (see above). // This works because dirent.d_name is the last member of dirent. - char space[MP_PATH_MAX]; + char space[MP_FILENAME_MAX]; }; }; @@ -605,6 +613,14 @@ int mp_mkdir(const char *path, int mode) return res; } +int mp_unlink(const char *path) +{ + wchar_t *wpath = mp_from_utf8(NULL, path); + int res = _wunlink(wpath); + talloc_free(wpath); + return res; +} + char *mp_win32_getcwd(char *buf, size_t size) { if (size >= SIZE_MAX / 3 - 1) { @@ -669,8 +685,8 @@ static void init_getenv(void) char *mp_getenv(const char *name) { - static pthread_once_t once_init_getenv = PTHREAD_ONCE_INIT; - pthread_once(&once_init_getenv, init_getenv); + static mp_once once_init_getenv = MP_STATIC_ONCE_INITIALIZER; + mp_exec_once(&once_init_getenv, init_getenv); // Copied from musl, http://git.musl-libc.org/cgit/musl/tree/COPYRIGHT // Copyright © 2005-2013 Rich Felker, standard MIT license int i; @@ -682,7 +698,7 @@ char *mp_getenv(const char *name) return NULL; } -char ***mp_penviron() +char ***mp_penviron(void) { mp_getenv(""); // ensure init return &utf8_environ; // `environ' should be an l-value @@ -698,6 +714,90 @@ off_t mp_lseek(int fd, off_t offset, int whence) return _lseeki64(fd, offset, whence); } +_Thread_local +static struct { + DWORD errcode; + char *errstring; +} mp_dl_result = { + .errcode = 0, + .errstring = NULL +}; + +static void mp_dl_free(void) +{ + if (mp_dl_result.errstring != NULL) { + talloc_free(mp_dl_result.errstring); + } +} + +static void mp_dl_init(void) +{ + atexit(mp_dl_free); +} + +void *mp_dlopen(const char *filename, int flag) +{ + HMODULE lib = NULL; + void *ta_ctx = talloc_new(NULL); + wchar_t *wfilename = mp_from_utf8(ta_ctx, filename); + + DWORD len = GetFullPathNameW(wfilename, 0, NULL, NULL); + if (!len) + goto err; + + wchar_t *path = talloc_array(ta_ctx, wchar_t, len); + len = GetFullPathNameW(wfilename, len, path, NULL); + if (!len) + goto err; + + lib = LoadLibraryW(path); + +err: + talloc_free(ta_ctx); + mp_dl_result.errcode = GetLastError(); + return (void *)lib; +} + +void *mp_dlsym(void *handle, const char *symbol) +{ + FARPROC addr = GetProcAddress((HMODULE)handle, symbol); + mp_dl_result.errcode = GetLastError(); + return (void *)addr; +} + +char *mp_dlerror(void) +{ + static mp_once once_init_dlerror = MP_STATIC_ONCE_INITIALIZER; + mp_exec_once(&once_init_dlerror, mp_dl_init); + mp_dl_free(); + + if (mp_dl_result.errcode == 0) + return NULL; + + // convert error code to a string message + LPWSTR werrstring = NULL; + FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + mp_dl_result.errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + (LPWSTR) &werrstring, + 0, + NULL); + mp_dl_result.errcode = 0; + + if (werrstring) { + mp_dl_result.errstring = mp_to_utf8(NULL, werrstring); + LocalFree(werrstring); + } + + return mp_dl_result.errstring == NULL + ? "unknown error" + : mp_dl_result.errstring; +} + #if HAVE_UWP void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { @@ -791,29 +891,3 @@ void freelocale(locale_t locobj) } #endif // __MINGW32__ - -int mp_mkostemps(char *template, int suffixlen, int flags) -{ - size_t len = strlen(template); - char *t = len >= 6 + suffixlen ? &template[len - (6 + suffixlen)] : NULL; - if (!t || strncmp(t, "XXXXXX", 6) != 0) { - errno = EINVAL; - return -1; - } - - for (size_t fuckshit = 0; fuckshit < UINT32_MAX; fuckshit++) { - // Using a random value may make it require fewer iterations (even if - // not truly random; just a counter would be sufficient). - size_t fuckmess = rand(); - char crap[7] = ""; - snprintf(crap, sizeof(crap), "%06zx", fuckmess); - memcpy(t, crap, 6); - - int res = open(template, O_RDWR | O_CREAT | O_EXCL | flags, 0600); - if (res >= 0 || errno != EEXIST) - return res; - } - - errno = EEXIST; - return -1; -} |