1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22: #include "tool_setup.h"
23:
24: #if defined(MSDOS) || defined(WIN32)
25:
26: #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
27: # include <libgen.h>
28: #endif
29:
30: #ifdef WIN32
31: # include <tlhelp32.h>
32: # include "tool_cfgable.h"
33: # include "tool_libinfo.h"
34: #endif
35:
36: #include "tool_bname.h"
37: #include "tool_doswin.h"
38:
39: #include "memdebug.h" /* keep this as LAST include */
40:
41: #ifdef WIN32
42: # undef PATH_MAX
43: # define PATH_MAX MAX_PATH
44: #endif
45:
46: #ifndef S_ISCHR
47: # ifdef S_IFCHR
48: # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
49: # else
50: # define S_ISCHR(m) (0) /* cannot tell if file is a device */
51: # endif
52: #endif
53:
54: #ifdef WIN32
55: # define _use_lfn(f) (1) /* long file names always available */
56: #elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
57: # define _use_lfn(f) (0) /* long file names never available */
58: #elif defined(__DJGPP__)
59: # include <fcntl.h> /* _use_lfn(f) prototype */
60: #endif
61:
62: #ifndef UNITTESTS
63: static SANITIZEcode truncate_dryrun(const char *path,
64: const size_t truncate_pos);
65: #ifdef MSDOS
66: static SANITIZEcode msdosify(char **const sanitized, const char *file_name,
67: int flags);
68: #endif
69: static SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
70: const char *file_name,
71: int flags);
72: #endif /* !UNITTESTS (static declarations used if no unit tests) */
73:
74:
75: /*
76: Sanitize a file or path name.
77:
78: All banned characters are replaced by underscores, for example:
79: f?*foo => f__foo
80: f:foo::$DATA => f_foo__$DATA
81: f:\foo:bar => f__foo_bar
82: f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH)
83:
84: This function was implemented according to the guidelines in 'Naming Files,
85: Paths, and Namespaces' section 'Naming Conventions'.
86: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
87:
88: Flags
89: -----
90: SANITIZE_ALLOW_COLONS: Allow colons.
91: Without this flag colons are sanitized.
92:
93: SANITIZE_ALLOW_PATH: Allow path separators and colons.
94: Without this flag path separators and colons are sanitized.
95:
96: SANITIZE_ALLOW_RESERVED: Allow reserved device names.
97: Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's
98: in a UNC prefixed path.
99:
100: SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename.
101: Without this flag if the sanitized filename or path will be too long an error
102: occurs. With this flag the filename --and not any other parts of the path-- may
103: be truncated to at least a single character. A filename followed by an
104: alternate data stream (ADS) cannot be truncated in any case.
105:
106: Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
107: Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
108: */
109: SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
110: int flags)
111: {
112: char *p, *target;
113: size_t len;
114: SANITIZEcode sc;
115: size_t max_sanitized_len;
116:
117: if(!sanitized)
118: return SANITIZE_ERR_BAD_ARGUMENT;
119:
120: *sanitized = NULL;
121:
122: if(!file_name)
123: return SANITIZE_ERR_BAD_ARGUMENT;
124:
125: if((flags & SANITIZE_ALLOW_PATH)) {
126: #ifndef MSDOS
127: if(file_name[0] == '\\' && file_name[1] == '\\')
128: /* UNC prefixed path \\ (eg \\?\C:\foo) */
129: max_sanitized_len = 32767-1;
130: else
131: #endif
132: max_sanitized_len = PATH_MAX-1;
133: }
134: else
135: /* The maximum length of a filename.
136: FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and
137: does not discount the path information therefore we shouldn't use it. */
138: max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;
139:
140: len = strlen(file_name);
141: if(len > max_sanitized_len) {
142: if(!(flags & SANITIZE_ALLOW_TRUNCATE) ||
143: truncate_dryrun(file_name, max_sanitized_len))
144: return SANITIZE_ERR_INVALID_PATH;
145:
146: len = max_sanitized_len;
147: }
148:
149: target = malloc(len + 1);
150: if(!target)
151: return SANITIZE_ERR_OUT_OF_MEMORY;
152:
153: strncpy(target, file_name, len);
154: target[len] = '\0';
155:
156: #ifndef MSDOS
157: if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4))
158: /* Skip the literal path prefix \\?\ */
159: p = target + 4;
160: else
161: #endif
162: p = target;
163:
164: /* replace control characters and other banned characters */
165: for(; *p; ++p) {
166: const char *banned;
167:
168: if((1 <= *p && *p <= 31) ||
169: (!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *p == ':') ||
170: (!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) {
171: *p = '_';
172: continue;
173: }
174:
175: for(banned = "|<>\"?*"; *banned; ++banned) {
176: if(*p == *banned) {
177: *p = '_';
178: break;
179: }
180: }
181: }
182:
183: /* remove trailing spaces and periods if not allowing paths */
184: if(!(flags & SANITIZE_ALLOW_PATH) && len) {
185: char *clip = NULL;
186:
187: p = &target[len];
188: do {
189: --p;
190: if(*p != ' ' && *p != '.')
191: break;
192: clip = p;
193: } while(p != target);
194:
195: if(clip) {
196: *clip = '\0';
197: len = clip - target;
198: }
199: }
200:
201: #ifdef MSDOS
202: sc = msdosify(&p, target, flags);
203: free(target);
204: if(sc)
205: return sc;
206: target = p;
207: len = strlen(target);
208:
209: if(len > max_sanitized_len) {
210: free(target);
211: return SANITIZE_ERR_INVALID_PATH;
212: }
213: #endif
214:
215: if(!(flags & SANITIZE_ALLOW_RESERVED)) {
216: sc = rename_if_reserved_dos_device_name(&p, target, flags);
217: free(target);
218: if(sc)
219: return sc;
220: target = p;
221: len = strlen(target);
222:
223: if(len > max_sanitized_len) {
224: free(target);
225: return SANITIZE_ERR_INVALID_PATH;
226: }
227: }
228:
229: *sanitized = target;
230: return SANITIZE_ERR_OK;
231: }
232:
233:
234: /*
235: Test if truncating a path to a file will leave at least a single character in
236: the filename. Filenames suffixed by an alternate data stream can't be
237: truncated. This performs a dry run, nothing is modified.
238:
239: Good truncate_pos 9: C:\foo\bar => C:\foo\ba
240: Good truncate_pos 6: C:\foo => C:\foo
241: Good truncate_pos 5: C:\foo => C:\fo
242: Bad* truncate_pos 5: C:foo => C:foo
243: Bad truncate_pos 5: C:\foo:ads => C:\fo
244: Bad truncate_pos 9: C:\foo:ads => C:\foo:ad
245: Bad truncate_pos 5: C:\foo\bar => C:\fo
246: Bad truncate_pos 5: C:\foo\ => C:\fo
247: Bad truncate_pos 7: C:\foo\ => C:\foo\
248: Error truncate_pos 7: C:\foo => (pos out of range)
249: Bad truncate_pos 1: C:\foo\ => C
250:
251: * C:foo is ambiguous, C could end up being a drive or file therefore something
252: like C:superlongfilename can't be truncated.
253:
254: Returns
255: SANITIZE_ERR_OK: Good -- 'path' can be truncated
256: SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
257: != SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
258: */
259: SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
260: {
261: size_t len;
262:
263: if(!path)
264: return SANITIZE_ERR_BAD_ARGUMENT;
265:
266: len = strlen(path);
267:
268: if(truncate_pos > len)
269: return SANITIZE_ERR_BAD_ARGUMENT;
270:
271: if(!len || !truncate_pos)
272: return SANITIZE_ERR_INVALID_PATH;
273:
274: if(strpbrk(&path[truncate_pos - 1], "\\/:"))
275: return SANITIZE_ERR_INVALID_PATH;
276:
277: /* C:\foo can be truncated but C:\foo:ads can't */
278: if(truncate_pos > 1) {
279: const char *p = &path[truncate_pos - 1];
280: do {
281: --p;
282: if(*p == ':')
283: return SANITIZE_ERR_INVALID_PATH;
284: } while(p != path && *p != '\\' && *p != '/');
285: }
286:
287: return SANITIZE_ERR_OK;
288: }
289:
290: /* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function
291: * were taken with modification from the DJGPP port of tar 1.12. They use
292: * algorithms originally from DJTAR.
293: */
294:
295: /*
296: Extra sanitization MSDOS for file_name.
297:
298: This is a supporting function for sanitize_file_name.
299:
300: Warning: This is an MSDOS legacy function and was purposely written in a way
301: that some path information may pass through. For example drive letter names
302: (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
303: sanitize_file_name.
304:
305: Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
306: Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
307: */
308: #if defined(MSDOS) || defined(UNITTESTS)
309: SANITIZEcode msdosify(char **const sanitized, const char *file_name,
310: int flags)
311: {
312: char dos_name[PATH_MAX];
313: static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
314: "|<>/\\\":?*"; /* illegal in DOS & W95 */
315: static const char *illegal_chars_w95 = &illegal_chars_dos[8];
316: int idx, dot_idx;
317: const char *s = file_name;
318: char *d = dos_name;
319: const char *const dlimit = dos_name + sizeof(dos_name) - 1;
320: const char *illegal_aliens = illegal_chars_dos;
321: size_t len = sizeof(illegal_chars_dos) - 1;
322:
323: if(!sanitized)
324: return SANITIZE_ERR_BAD_ARGUMENT;
325:
326: *sanitized = NULL;
327:
328: if(!file_name)
329: return SANITIZE_ERR_BAD_ARGUMENT;
330:
331: if(strlen(file_name) > PATH_MAX-1 &&
332: (!(flags & SANITIZE_ALLOW_TRUNCATE) ||
333: truncate_dryrun(file_name, PATH_MAX-1)))
334: return SANITIZE_ERR_INVALID_PATH;
335:
336: /* Support for Windows 9X VFAT systems, when available. */
337: if(_use_lfn(file_name)) {
338: illegal_aliens = illegal_chars_w95;
339: len -= (illegal_chars_w95 - illegal_chars_dos);
340: }
341:
342: /* Get past the drive letter, if any. */
343: if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
344: *d++ = *s++;
345: *d = ((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) ? ':' : '_';
346: ++d, ++s;
347: }
348:
349: for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
350: if(memchr(illegal_aliens, *s, len)) {
351:
352: if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':')
353: *d = ':';
354: else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
355: *d = *s;
356: /* Dots are special: DOS doesn't allow them as the leading character,
357: and a file name cannot have more than a single dot. We leave the
358: first non-leading dot alone, unless it comes too close to the
359: beginning of the name: we want sh.lex.c to become sh_lex.c, not
360: sh.lex-c. */
361: else if(*s == '.') {
362: if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
363: (s[1] == '/' || s[1] == '\\' ||
364: (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {
365: /* Copy "./" and "../" verbatim. */
366: *d++ = *s++;
367: if(d == dlimit)
368: break;
369: if(*s == '.') {
370: *d++ = *s++;
371: if(d == dlimit)
372: break;
373: }
374: *d = *s;
375: }
376: else if(idx == 0)
377: *d = '_';
378: else if(dot_idx >= 0) {
379: if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
380: d[dot_idx - idx] = '_'; /* replace previous dot */
381: *d = '.';
382: }
383: else
384: *d = '-';
385: }
386: else
387: *d = '.';
388:
389: if(*s == '.')
390: dot_idx = idx;
391: }
392: else if(*s == '+' && s[1] == '+') {
393: if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
394: *d++ = 'x';
395: if(d == dlimit)
396: break;
397: *d = 'x';
398: }
399: else {
400: /* libg++ etc. */
401: if(dlimit - d < 4) {
402: *d++ = 'x';
403: if(d == dlimit)
404: break;
405: *d = 'x';
406: }
407: else {
408: memcpy(d, "plus", 4);
409: d += 3;
410: }
411: }
412: s++;
413: idx++;
414: }
415: else
416: *d = '_';
417: }
418: else
419: *d = *s;
420: if(*s == '/' || *s == '\\') {
421: idx = 0;
422: dot_idx = -1;
423: }
424: else
425: idx++;
426: }
427: *d = '\0';
428:
429: if(*s) {
430: /* dos_name is truncated, check that truncation requirements are met,
431: specifically truncating a filename suffixed by an alternate data stream
432: or truncating the entire filename is not allowed. */
433: if(!(flags & SANITIZE_ALLOW_TRUNCATE) || strpbrk(s, "\\/:") ||
434: truncate_dryrun(dos_name, d - dos_name))
435: return SANITIZE_ERR_INVALID_PATH;
436: }
437:
438: *sanitized = strdup(dos_name);
439: return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
440: }
441: #endif /* MSDOS || UNITTESTS */
442:
443: /*
444: Rename file_name if it's a reserved dos device name.
445:
446: This is a supporting function for sanitize_file_name.
447:
448: Warning: This is an MSDOS legacy function and was purposely written in a way
449: that some path information may pass through. For example drive letter names
450: (C:, D:, etc) are allowed to pass through. For sanitizing a filename use
451: sanitize_file_name.
452:
453: Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
454: Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
455: */
456: SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
457: const char *file_name,
458: int flags)
459: {
460: /* We could have a file whose name is a device on MS-DOS. Trying to
461: * retrieve such a file would fail at best and wedge us at worst. We need
462: * to rename such files. */
463: char *p, *base;
464: char fname[PATH_MAX];
465: #ifdef MSDOS
466: struct_stat st_buf;
467: #endif
468:
469: if(!sanitized)
470: return SANITIZE_ERR_BAD_ARGUMENT;
471:
472: *sanitized = NULL;
473:
474: if(!file_name)
475: return SANITIZE_ERR_BAD_ARGUMENT;
476:
477: /* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */
478: #ifndef MSDOS
479: if((flags & SANITIZE_ALLOW_PATH) &&
480: file_name[0] == '\\' && file_name[1] == '\\') {
481: size_t len = strlen(file_name);
482: *sanitized = malloc(len + 1);
483: if(!*sanitized)
484: return SANITIZE_ERR_OUT_OF_MEMORY;
485: strncpy(*sanitized, file_name, len + 1);
486: return SANITIZE_ERR_OK;
487: }
488: #endif
489:
490: if(strlen(file_name) > PATH_MAX-1 &&
491: (!(flags & SANITIZE_ALLOW_TRUNCATE) ||
492: truncate_dryrun(file_name, PATH_MAX-1)))
493: return SANITIZE_ERR_INVALID_PATH;
494:
495: strncpy(fname, file_name, PATH_MAX-1);
496: fname[PATH_MAX-1] = '\0';
497: base = basename(fname);
498:
499: /* Rename reserved device names that are known to be accessible without \\.\
500: Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS
501: https://support.microsoft.com/en-us/kb/74496
502: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx
503: */
504: for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) {
505: size_t p_len;
506: int x = (curl_strnequal(p, "CON", 3) ||
507: curl_strnequal(p, "PRN", 3) ||
508: curl_strnequal(p, "AUX", 3) ||
509: curl_strnequal(p, "NUL", 3)) ? 3 :
510: (curl_strnequal(p, "CLOCK$", 6)) ? 6 :
511: (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ?
512: (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0;
513:
514: if(!x)
515: continue;
516:
517: /* the devices may be accessible with an extension or ADS, for
518: example CON.AIR and 'CON . AIR' and CON:AIR access console */
519:
520: for(; p[x] == ' '; ++x)
521: ;
522:
523: if(p[x] == '.') {
524: p[x] = '_';
525: continue;
526: }
527: else if(p[x] == ':') {
528: if(!(flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH))) {
529: p[x] = '_';
530: continue;
531: }
532: ++x;
533: }
534: else if(p[x]) /* no match */
535: continue;
536:
537: /* p points to 'CON' or 'CON ' or 'CON:', etc */
538: p_len = strlen(p);
539:
540: /* Prepend a '_' */
541: if(strlen(fname) == PATH_MAX-1) {
542: --p_len;
543: if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(p, p_len))
544: return SANITIZE_ERR_INVALID_PATH;
545: p[p_len] = '\0';
546: }
547: memmove(p + 1, p, p_len + 1);
548: p[0] = '_';
549: ++p_len;
550:
551: /* if fname was just modified then the basename pointer must be updated */
552: if(p == fname)
553: base = basename(fname);
554: }
555:
556: /* This is the legacy portion from rename_if_dos_device_name that checks for
557: reserved device names. It only works on MSDOS. On Windows XP the stat
558: check errors with EINVAL if the device name is reserved. On Windows
559: Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN
560: stat doc the latter behavior is correct, but that doesn't help us identify
561: whether it's a reserved device name and not a regular file name. */
562: #ifdef MSDOS
563: if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
564: /* Prepend a '_' */
565: size_t blen = strlen(base);
566: if(blen) {
567: if(strlen(fname) == PATH_MAX-1) {
568: --blen;
569: if(!(flags & SANITIZE_ALLOW_TRUNCATE) || truncate_dryrun(base, blen))
570: return SANITIZE_ERR_INVALID_PATH;
571: base[blen] = '\0';
572: }
573: memmove(base + 1, base, blen + 1);
574: base[0] = '_';
575: }
576: }
577: #endif
578:
579: *sanitized = strdup(fname);
580: return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
581: }
582:
583: #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
584:
585: /*
586: * Disable program default argument globbing. We do it on our own.
587: */
588: char **__crt0_glob_function(char *arg)
589: {
590: (void)arg;
591: return (char **)0;
592: }
593:
594: #endif /* MSDOS && (__DJGPP__ || __GO32__) */
595:
596: #ifdef WIN32
597:
598: /*
599: * Function to find CACert bundle on a Win32 platform using SearchPath.
600: * (SearchPath is already declared via inclusions done in setup header file)
601: * (Use the ASCII version instead of the unicode one!)
602: * The order of the directories it searches is:
603: * 1. application's directory
604: * 2. current working directory
605: * 3. Windows System directory (e.g. C:\windows\system32)
606: * 4. Windows Directory (e.g. C:\windows)
607: * 5. all directories along %PATH%
608: *
609: * For WinXP and later search order actually depends on registry value:
610: * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
611: */
612:
613: CURLcode FindWin32CACert(struct OperationConfig *config,
614: curl_sslbackend backend,
615: const char *bundle_file)
616: {
617: CURLcode result = CURLE_OK;
618:
619: /* Search and set cert file only if libcurl supports SSL.
620: *
621: * If Schannel is the selected SSL backend then these locations are
622: * ignored. We allow setting CA location for schannel only when explicitly
623: * specified by the user via CURLOPT_CAINFO / --cacert.
624: */
625: if((curlinfo->features & CURL_VERSION_SSL) &&
626: backend != CURLSSLBACKEND_SCHANNEL) {
627:
628: DWORD res_len;
629: char buf[PATH_MAX];
630: char *ptr = NULL;
631:
632: buf[0] = '\0';
633:
634: res_len = SearchPathA(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr);
635: if(res_len > 0) {
636: Curl_safefree(config->cacert);
637: config->cacert = strdup(buf);
638: if(!config->cacert)
639: result = CURLE_OUT_OF_MEMORY;
640: }
641: }
642:
643: return result;
644: }
645:
646:
647: /* Get a list of all loaded modules with full paths.
648: * Returns slist on success or NULL on error.
649: */
650: struct curl_slist *GetLoadedModulePaths(void)
651: {
652: HANDLE hnd = INVALID_HANDLE_VALUE;
653: MODULEENTRY32 mod = {0};
654: struct curl_slist *slist = NULL;
655:
656: mod.dwSize = sizeof(MODULEENTRY32);
657:
658: do {
659: hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
660: } while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH);
661:
662: if(hnd == INVALID_HANDLE_VALUE)
663: goto error;
664:
665: if(!Module32First(hnd, &mod))
666: goto error;
667:
668: do {
669: char *path; /* points to stack allocated buffer */
670: struct curl_slist *temp;
671:
672: #ifdef UNICODE
673: /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
674: bytes of multibyte chars won't be more than twice that. */
675: char buffer[sizeof(mod.szExePath) * 2];
676: if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
677: buffer, sizeof(buffer), NULL, NULL))
678: goto error;
679: path = buffer;
680: #else
681: path = mod.szExePath;
682: #endif
683: temp = curl_slist_append(slist, path);
684: if(!temp)
685: goto error;
686: slist = temp;
687: } while(Module32Next(hnd, &mod));
688:
689: goto cleanup;
690:
691: error:
692: curl_slist_free_all(slist);
693: slist = NULL;
694: cleanup:
695: if(hnd != INVALID_HANDLE_VALUE)
696: CloseHandle(hnd);
697: return slist;
698: }
699:
700: LARGE_INTEGER tool_freq;
701: bool tool_isVistaOrGreater;
702:
703: CURLcode win32_init(void)
704: {
705: OSVERSIONINFOEXA osvi;
706: unsigned __int64 mask = 0;
707: unsigned char op = VER_GREATER_EQUAL;
708:
709: memset(&osvi, 0, sizeof(osvi));
710: osvi.dwOSVersionInfoSize = sizeof(osvi);
711: osvi.dwMajorVersion = 6;
712: VER_SET_CONDITION(mask, VER_MAJORVERSION, op);
713: VER_SET_CONDITION(mask, VER_MINORVERSION, op);
714:
715: if(VerifyVersionInfoA(&osvi, (VER_MAJORVERSION | VER_MINORVERSION), mask))
716: tool_isVistaOrGreater = true;
717: else if(GetLastError() == ERROR_OLD_WIN_VERSION)
718: tool_isVistaOrGreater = false;
719: else
720: return CURLE_FAILED_INIT;
721:
722: QueryPerformanceFrequency(&tool_freq);
723: return CURLE_OK;
724: }
725:
726: #endif /* WIN32 */
727:
728: #endif /* MSDOS || WIN32 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>