123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
- #include "tool_setup.h"
- #if defined(_WIN32) || defined(MSDOS)
- #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
- # include <libgen.h>
- #endif
- #ifdef _WIN32
- # include <stdlib.h>
- # include <tlhelp32.h>
- # include "tool_cfgable.h"
- # include "tool_libinfo.h"
- #endif
- #include "tool_bname.h"
- #include "tool_doswin.h"
- #include "curlx.h"
- #include "memdebug.h" /* keep this as LAST include */
- #ifdef _WIN32
- # undef PATH_MAX
- # define PATH_MAX MAX_PATH
- #endif
- #ifndef S_ISCHR
- # ifdef S_IFCHR
- # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
- # else
- # define S_ISCHR(m) (0) /* cannot tell if file is a device */
- # endif
- #endif
- #ifdef _WIN32
- # define _use_lfn(f) (1) /* long file names always available */
- #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
- # define _use_lfn(f) (0) /* long file names never available */
- #elif defined(__DJGPP__)
- # include <fcntl.h> /* _use_lfn(f) prototype */
- #endif
- #ifndef UNITTESTS
- static SANITIZEcode truncate_dryrun(const char *path,
- const size_t truncate_pos);
- #ifdef MSDOS
- static SANITIZEcode msdosify(char **const sanitized, const char *file_name,
- int flags);
- #endif
- static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
- const char *file_name,
- int flags);
- #endif /* !UNITTESTS (static declarations used if no unit tests) */
- /*
- Sanitize a file or path name.
- All banned characters are replaced by underscores, for example:
- f?*foo => f__foo
- f:foo::$DATA => f_foo__$DATA
- f:\foo:bar => f__foo_bar
- f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH)
- This function was implemented according to the guidelines in 'Naming Files,
- Paths, and Namespaces' section 'Naming Conventions'.
- https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
- Flags
- -----
- SANITIZE_ALLOW_COLONS: Allow colons.
- Without this flag colons are sanitized.
- SANITIZE_ALLOW_PATH: Allow path separators and colons.
- Without this flag path separators and colons are sanitized.
- SANITIZE_ALLOW_RESERVED: Allow reserved device names.
- Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's
- in a UNC prefixed path.
- SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename.
- Without this flag if the sanitized filename or path will be too long an error
- occurs. With this flag the filename --and not any other parts of the path-- may
- be truncated to at least a single character. A filename followed by an
- alternate data stream (ADS) cannot be truncated in any case.
- Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
- Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
- */
- SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
- int flags)
- {
- char *p, *target;
- size_t len;
- SANITIZEcode sc;
- size_t max_sanitized_len;
- if(!sanitized)
- return SANITIZE_ERR_BAD_ARGUMENT;
- *sanitized = NULL;
- if(!file_name)
- return SANITIZE_ERR_BAD_ARGUMENT;
- if((flags & SANITIZE_ALLOW_PATH)) {
- #ifndef MSDOS
- if(file_name[0] == '\\' && file_name[1] == '\\')
- /* UNC prefixed path \\ (eg \\?\C:\foo) */
- max_sanitized_len = 32767-1;
- else
- #endif
- max_sanitized_len = PATH_MAX-1;
- }
- else
- /* The maximum length of a filename.
- FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and
- does not discount the path information therefore we shouldn't use it. */
- max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;
- len = strlen(file_name);
- if(len > max_sanitized_len) {
- if(!(flags & SANITIZE_ALLOW_TRUNCATE) ||
- truncate_dryrun(file_name, max_sanitized_len))
- return SANITIZE_ERR_INVALID_PATH;
- len = max_sanitized_len;
- }
- target = malloc(len + 1);
- if(!target)
- return SANITIZE_ERR_OUT_OF_MEMORY;
- strncpy(target, file_name, len);
- target[len] = '\0';
- #ifndef MSDOS
- if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4))
- /* Skip the literal path prefix \\?\ */
- p = target + 4;
- else
- #endif
- p = target;
- /* replace control characters and other banned characters */
- for(; *p; ++p) {
- const char *banned;
- if((1 <= *p && *p <= 31) ||
- (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') ||
- (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) {
- *p = '_';
- continue;
- }
- for(banned = "|<>\"?*"; *banned; ++banned) {
- if(*p == *banned) {
- *p = '_';
- break;
- }
- }
- }
- /* remove trailing spaces and periods if not allowing paths */
- if(!(flags & SANITIZE_ALLOW_PATH) && len) {
- char *clip = NULL;
- p = &target[len];
- do {
- --p;
- if(*p != ' ' && *p != '.')
- break;
- clip = p;
- } while(p != target);
- if(clip) {
- *clip = '\0';
- len = clip - target;
- }
- }
- #ifdef MSDOS
- sc = msdosify(&p, target, flags);
- free(target);
- if(sc)
- return sc;
- target = p;
- len = strlen(target);
- if(len > max_sanitized_len) {
- free(target);
- return SANITIZE_ERR_INVALID_PATH;
- }
- #endif
- if(!(flags & SANITIZE_ALLOW_RESERVED)) {
- sc = rename_if_reserved_dos_device_name(&p, target, flags);
- free(target);
- if(sc)
- return sc;
- target = p;
- len = strlen(target);
- if(len > max_sanitized_len) {
- free(target);
- return SANITIZE_ERR_INVALID_PATH;
- }
- }
- *sanitized = target;
- return SANITIZE_ERR_OK;
- }
- /*
- Test if truncating a path to a file will leave at least a single character in
- the filename. Filenames suffixed by an alternate data stream can't be
- truncated. This performs a dry run, nothing is modified.
- Good truncate_pos 9: C:\foo\bar => C:\foo\ba
- Good truncate_pos 6: C:\foo => C:\foo
- Good truncate_pos 5: C:\foo => C:\fo
- Bad* truncate_pos 5: C:foo => C:foo
- Bad truncate_pos 5: C:\foo:ads => C:\fo
- Bad truncate_pos 9: C:\foo:ads => C:\foo:ad
- Bad truncate_pos 5: C:\foo\bar => C:\fo
- Bad truncate_pos 5: C:\foo\ => C:\fo
- Bad truncate_pos 7: C:\foo\ => C:\foo\
- Error truncate_pos 7: C:\foo => (pos out of range)
- Bad truncate_pos 1: C:\foo\ => C
- * C:foo is ambiguous, C could end up being a drive or file therefore something
- like C:superlongfilename can't be truncated.
- Returns
- SANITIZE_ERR_OK: Good -- 'path' can be truncated
- SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
- != SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
- */
- SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
- {
- size_t len;
- if(!path)
- return SANITIZE_ERR_BAD_ARGUMENT;
- len = strlen(path);
- if(truncate_pos > len)
- return SANITIZE_ERR_BAD_ARGUMENT;
- if(!len || !truncate_pos)
- return SANITIZE_ERR_INVALID_PATH;
- if(strpbrk(&path[truncate_pos - 1], "\\/:"))
- return SANITIZE_ERR_INVALID_PATH;
- /* C:\foo can be truncated but C:\foo:ads can't */
- if(truncate_pos > 1) {
- const char *p = &path[truncate_pos - 1];
- do {
- --p;
- if(*p == ':')
- return SANITIZE_ERR_INVALID_PATH;
- } while(p != path && *p != '\\' && *p != '/');
- }
- return SANITIZE_ERR_OK;
- }
- /* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function
- * were taken with modification from the DJGPP port of tar 1.12. They use
- * algorithms originally from DJTAR.
- */
- /*
- Extra sanitization MSDOS for file_name.
- This is a supporting function for sanitize_file_name.
- Warning: This is an MSDOS legacy function and was purposely written in a way
- that some path information may pass through. For example drive letter names
- (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
- sanitize_file_name.
- Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
- Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
- */
- #if defined(MSDOS) || defined(UNITTESTS)
- SANITIZEcode msdosify(char **const sanitized, const char *file_name,
- int flags)
- {
- char dos_name[PATH_MAX];
- static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
- "|<>/\\\":?*"; /* illegal in DOS & W95 */
- static const char *illegal_chars_w95 = &illegal_chars_dos[8];
- int idx, dot_idx;
- const char *s = file_name;
- char *d = dos_name;
- const char *const dlimit = dos_name + sizeof(dos_name) - 1;
- const char *illegal_aliens = illegal_chars_dos;
- size_t len = sizeof(illegal_chars_dos) - 1;
- if(!sanitized)
- return SANITIZE_ERR_BAD_ARGUMENT;
- *sanitized = NULL;
- if(!file_name)
- return SANITIZE_ERR_BAD_ARGUMENT;
- if(strlen(file_name) > PATH_MAX-1 &&
- (!(flags & SANITIZE_ALLOW_TRUNCATE) ||
- truncate_dryrun(file_name, PATH_MAX-1)))
- return SANITIZE_ERR_INVALID_PATH;
- /* Support for Windows 9X VFAT systems, when available. */
- if(_use_lfn(file_name)) {
- illegal_aliens = illegal_chars_w95;
- len -= (illegal_chars_w95 - illegal_chars_dos);
- }
- /* Get past the drive letter, if any. */
- if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
- *d++ = *s++;
- *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_';
- ++d; ++s;
- }
- for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
- if(memchr(illegal_aliens, *s, len)) {
- if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':')
- *d = ':';
- else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
- *d = *s;
- /* Dots are special: DOS doesn't allow them as the leading character,
- and a file name cannot have more than a single dot. We leave the
- first non-leading dot alone, unless it comes too close to the
- beginning of the name: we want sh.lex.c to become sh_lex.c, not
- sh.lex-c. */
- else if(*s == '.') {
- if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
- (s[1] == '/' || s[1] == '\\' ||
- (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {
- /* Copy "./" and "../" verbatim. */
- *d++ = *s++;
- if(d == dlimit)
- break;
- if(*s == '.') {
- *d++ = *s++;
- if(d == dlimit)
- break;
- }
- *d = *s;
- }
- else if(idx == 0)
- *d = '_';
- else if(dot_idx >= 0) {
- if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
- d[dot_idx - idx] = '_'; /* replace previous dot */
- *d = '.';
- }
- else
- *d = '-';
- }
- else
- *d = '.';
- if(*s == '.')
- dot_idx = idx;
- }
- else if(*s == '+' && s[1] == '+') {
- if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
- *d++ = 'x';
- if(d == dlimit)
- break;
- *d = 'x';
- }
- else {
- /* libg++ etc. */
- if(dlimit - d < 4) {
- *d++ = 'x';
- if(d == dlimit)
- break;
- *d = 'x';
- }
- else {
- memcpy(d, "plus", 4);
- d += 3;
- }
- }
- s++;
- idx++;
- }
- else
- *d = '_';
- }
- else
- *d = *s;
- if(*s == '/' || *s == '\\') {
- idx = 0;
- dot_idx = -1;
- }
- else
- idx++;
- }
- *d = '\0';
- if(*s) {
- /* dos_name is truncated, check that truncation requirements are met,
- specifically truncating a filename suffixed by an alternate data stream
- or truncating the entire filename is not allowed. */
- if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") ||
- truncate_dryrun(dos_name, d - dos_name))
- return SANITIZE_ERR_INVALID_PATH;
- }
- *sanitized = strdup(dos_name);
- return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
- }
- #endif /* MSDOS || UNITTESTS */
- /*
- Rename file_name if it's a reserved dos device name.
- This is a supporting function for sanitize_file_name.
- Warning: This is an MSDOS legacy function and was purposely written in a way
- that some path information may pass through. For example drive letter names
- (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
- sanitize_file_name.
- Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
- Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
- */
- SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
- const char *file_name,
- int flags)
- {
- /* We could have a file whose name is a device on MS-DOS. Trying to
- * retrieve such a file would fail at best and wedge us at worst. We need
- * to rename such files. */
- char *p, *base;
- char fname[PATH_MAX];
- #ifdef MSDOS
- struct_stat st_buf;
- #endif
- if(!sanitized)
- return SANITIZE_ERR_BAD_ARGUMENT;
- *sanitized = NULL;
- if(!file_name)
- return SANITIZE_ERR_BAD_ARGUMENT;
- /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */
- #ifndef MSDOS
- if((flags & SANITIZE_ALLOW_PATH) &&
- file_name[0] == '\\' && file_name[1] == '\\') {
- size_t len = strlen(file_name);
- *sanitized = malloc(len + 1);
- if(!*sanitized)
- return SANITIZE_ERR_OUT_OF_MEMORY;
- strncpy(*sanitized, file_name, len + 1);
- return SANITIZE_ERR_OK;
- }
- #endif
- if(strlen(file_name) > PATH_MAX-1 &&
- (!(flags & SANITIZE_ALLOW_TRUNCATE) ||
- truncate_dryrun(file_name, PATH_MAX-1)))
- return SANITIZE_ERR_INVALID_PATH;
- strncpy(fname, file_name, PATH_MAX-1);
- fname[PATH_MAX-1] = '\0';
- base = basename(fname);
- /* Rename reserved device names that are known to be accessible without \\.\
- Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS
- https://support.microsoft.com/en-us/kb/74496
- https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
- */
- for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) {
- size_t p_len;
- int x = (curl_strnequal(p, "CON", 3) ||
- curl_strnequal(p, "PRN", 3) ||
- curl_strnequal(p, "AUX", 3) ||
- curl_strnequal(p, "NUL", 3)) ? 3 :
- (curl_strnequal(p, "CLOCK$", 6)) ? 6 :
- (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ?
- (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0;
- if(!x)
- continue;
- /* the devices may be accessible with an extension or ADS, for
- example CON.AIR and 'CON . AIR' and CON:AIR access console */
- for(; p[x] == ' '; ++x)
- ;
- if(p[x] == '.') {
- p[x] = '_';
- continue;
- }
- else if(p[x] == ':') {
- if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) {
- p[x] = '_';
- continue;
- }
- ++x;
- }
- else if(p[x]) /* no match */
- continue;
- /* p points to 'CON' or 'CON ' or 'CON:', etc */
- p_len = strlen(p);
- /* Prepend a '_' */
- if(strlen(fname) == PATH_MAX-1) {
- --p_len;
- if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len))
- return SANITIZE_ERR_INVALID_PATH;
- p[p_len] = '\0';
- }
- memmove(p + 1, p, p_len + 1);
- p[0] = '_';
- ++p_len;
- /* if fname was just modified then the basename pointer must be updated */
- if(p == fname)
- base = basename(fname);
- }
- /* This is the legacy portion from rename_if_dos_device_name that checks for
- reserved device names. It only works on MSDOS. On Windows XP the stat
- check errors with EINVAL if the device name is reserved. On Windows
- Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN
- stat doc the latter behavior is correct, but that doesn't help us identify
- whether it's a reserved device name and not a regular file name. */
- #ifdef MSDOS
- if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
- /* Prepend a '_' */
- size_t blen = strlen(base);
- if(blen) {
- if(strlen(fname) == PATH_MAX-1) {
- --blen;
- if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen))
- return SANITIZE_ERR_INVALID_PATH;
- base[blen] = '\0';
- }
- memmove(base + 1, base, blen + 1);
- base[0] = '_';
- }
- }
- #endif
- *sanitized = strdup(fname);
- return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
- }
- #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
- /*
- * Disable program default argument globbing. We do it on our own.
- */
- char **__crt0_glob_function(char *arg)
- {
- (void)arg;
- return (char **)0;
- }
- #endif /* MSDOS && (__DJGPP__ || __GO32__) */
- #ifdef _WIN32
- /*
- * Function to find CACert bundle on a Win32 platform using SearchPath.
- * (SearchPath is already declared via inclusions done in setup header file)
- * (Use the ASCII version instead of the unicode one!)
- * The order of the directories it searches is:
- * 1. application's directory
- * 2. current working directory
- * 3. Windows System directory (e.g. C:\windows\system32)
- * 4. Windows Directory (e.g. C:\windows)
- * 5. all directories along %PATH%
- *
- * For WinXP and later search order actually depends on registry value:
- * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
- */
- CURLcode FindWin32CACert(struct OperationConfig *config,
- curl_sslbackend backend,
- const TCHAR *bundle_file)
- {
- CURLcode result = CURLE_OK;
- /* Search and set cert file only if libcurl supports SSL.
- *
- * If Schannel is the selected SSL backend then these locations are
- * ignored. We allow setting CA location for schannel only when explicitly
- * specified by the user via CURLOPT_CAINFO / --cacert.
- */
- if(feature_ssl && backend != CURLSSLBACKEND_SCHANNEL) {
- DWORD res_len;
- TCHAR buf[PATH_MAX];
- TCHAR *ptr = NULL;
- buf[0] = TEXT('\0');
- res_len = SearchPath(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr);
- if(res_len > 0) {
- char *mstr = curlx_convert_tchar_to_UTF8(buf);
- Curl_safefree(config->cacert);
- if(mstr)
- config->cacert = strdup(mstr);
- curlx_unicodefree(mstr);
- if(!config->cacert)
- result = CURLE_OUT_OF_MEMORY;
- }
- }
- return result;
- }
- /* Get a list of all loaded modules with full paths.
- * Returns slist on success or NULL on error.
- */
- struct curl_slist *GetLoadedModulePaths(void)
- {
- HANDLE hnd = INVALID_HANDLE_VALUE;
- MODULEENTRY32 mod = {0};
- struct curl_slist *slist = NULL;
- mod.dwSize = sizeof(MODULEENTRY32);
- do {
- hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
- } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH);
- if(hnd == INVALID_HANDLE_VALUE)
- goto error;
- if(!Module32First(hnd, &mod))
- goto error;
- do {
- char *path; /* points to stack allocated buffer */
- struct curl_slist *temp;
- #ifdef UNICODE
- /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
- bytes of multibyte chars won't be more than twice that. */
- char buffer[sizeof(mod.szExePath) * 2];
- if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
- buffer, sizeof(buffer), NULL, NULL))
- goto error;
- path = buffer;
- #else
- path = mod.szExePath;
- #endif
- temp = curl_slist_append(slist, path);
- if(!temp)
- goto error;
- slist = temp;
- } while(Module32Next(hnd, &mod));
- goto cleanup;
- error:
- curl_slist_free_all(slist);
- slist = NULL;
- cleanup:
- if(hnd != INVALID_HANDLE_VALUE)
- CloseHandle(hnd);
- return slist;
- }
- /* The terminal settings to restore on exit */
- static struct TerminalSettings {
- HANDLE hStdOut;
- DWORD dwOutputMode;
- LONG valid;
- } TerminalSettings;
- #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
- #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
- #endif
- bool tool_term_has_bold;
- static void restore_terminal(void)
- {
- if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
- SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
- }
- /* This is the console signal handler.
- * The system calls it in a separate thread.
- */
- static BOOL WINAPI signal_handler(DWORD type)
- {
- if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
- restore_terminal();
- return FALSE;
- }
- static void init_terminal(void)
- {
- TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- /*
- * Enable VT (Virtual Terminal) output.
- * Note: VT mode flag can be set on any version of Windows, but VT
- * processing only performed on Win10 >= version 1709 (OS build 16299)
- * Creator's Update. Also, ANSI bold on/off supported since then.
- */
- if(TerminalSettings.hStdOut == INVALID_HANDLE_VALUE ||
- !GetConsoleMode(TerminalSettings.hStdOut,
- &TerminalSettings.dwOutputMode) ||
- !curlx_verify_windows_version(10, 0, 16299, PLATFORM_WINNT,
- VERSION_GREATER_THAN_EQUAL))
- return;
- if((TerminalSettings.dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
- tool_term_has_bold = true;
- else {
- /* The signal handler is set before attempting to change the console mode
- because otherwise a signal would not be caught after the change but
- before the handler was installed. */
- (void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE);
- if(SetConsoleCtrlHandler(signal_handler, TRUE)) {
- if(SetConsoleMode(TerminalSettings.hStdOut,
- (TerminalSettings.dwOutputMode |
- ENABLE_VIRTUAL_TERMINAL_PROCESSING))) {
- tool_term_has_bold = true;
- atexit(restore_terminal);
- }
- else {
- SetConsoleCtrlHandler(signal_handler, FALSE);
- (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
- }
- }
- }
- }
- LARGE_INTEGER tool_freq;
- bool tool_isVistaOrGreater;
- CURLcode win32_init(void)
- {
- /* curlx_verify_windows_version must be called during init at least once
- because it has its own initialization routine. */
- if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
- VERSION_GREATER_THAN_EQUAL))
- tool_isVistaOrGreater = true;
- else
- tool_isVistaOrGreater = false;
- QueryPerformanceFrequency(&tool_freq);
- init_terminal();
- return CURLE_OK;
- }
- #endif /* _WIN32 */
- #endif /* _WIN32 || MSDOS */
|