1a89c9211Schristos /*
25af53050Schristos * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
35af53050Schristos *
4*8fbed61eSchristos * Licensed under the Apache License 2.0 (the "License"). You may not use
55af53050Schristos * this file except in compliance with the License. You can obtain a copy
65af53050Schristos * in the file LICENSE in the source distribution or at
75af53050Schristos * https://www.openssl.org/source/license.html
85af53050Schristos */
95af53050Schristos
105af53050Schristos /*
11e0ea3921Schristos * This file is dual-licensed and is also available under the following
12e0ea3921Schristos * terms:
13e0ea3921Schristos *
14a89c9211Schristos * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
15a89c9211Schristos * All rights reserved.
16a89c9211Schristos *
17a89c9211Schristos * Redistribution and use in source and binary forms, with or without
18a89c9211Schristos * modification, are permitted provided that the following conditions
19a89c9211Schristos * are met:
20a89c9211Schristos * 1. Redistributions of source code must retain the above copyright
21a89c9211Schristos * notice, this list of conditions and the following disclaimer.
22a89c9211Schristos * 2. Redistributions in binary form must reproduce the above copyright
23a89c9211Schristos * notice, this list of conditions and the following disclaimer in the
24a89c9211Schristos * documentation and/or other materials provided with the distribution.
25a89c9211Schristos *
26a89c9211Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27a89c9211Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28a89c9211Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29a89c9211Schristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30a89c9211Schristos * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31a89c9211Schristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32a89c9211Schristos * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33a89c9211Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34a89c9211Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35a89c9211Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36a89c9211Schristos * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37a89c9211Schristos */
385af53050Schristos
39a89c9211Schristos #include <windows.h>
40a89c9211Schristos #include <tchar.h>
415af53050Schristos #include "internal/numbers.h"
42a89c9211Schristos #ifndef LPDIR_H
43a89c9211Schristos # include "LPdir.h"
44a89c9211Schristos #endif
45a89c9211Schristos
469cef71b6Sspz /*
479cef71b6Sspz * We're most likely overcautious here, but let's reserve for broken WinCE
489cef71b6Sspz * headers and explicitly opt for UNICODE call. Keep in mind that our WinCE
499cef71b6Sspz * builds are compiled with -DUNICODE [as well as -D_UNICODE].
509cef71b6Sspz */
51a89c9211Schristos #if defined(LP_SYS_WINCE) && !defined(FindFirstFile)
52a89c9211Schristos # define FindFirstFile FindFirstFileW
53a89c9211Schristos #endif
54805debc4Sspz #if defined(LP_SYS_WINCE) && !defined(FindNextFile)
55a89c9211Schristos # define FindNextFile FindNextFileW
56a89c9211Schristos #endif
57a89c9211Schristos
58a89c9211Schristos #ifndef NAME_MAX
59a89c9211Schristos # define NAME_MAX 255
60a89c9211Schristos #endif
61a89c9211Schristos
625af53050Schristos #ifdef CP_UTF8
635af53050Schristos # define CP_DEFAULT CP_UTF8
645af53050Schristos #else
655af53050Schristos # define CP_DEFAULT CP_ACP
665af53050Schristos #endif
675af53050Schristos
689cef71b6Sspz struct LP_dir_context_st {
69a89c9211Schristos WIN32_FIND_DATA ctx;
70a89c9211Schristos HANDLE handle;
71a89c9211Schristos char entry_name[NAME_MAX + 1];
72a89c9211Schristos };
73a89c9211Schristos
LP_find_file(LP_DIR_CTX ** ctx,const char * directory)74a89c9211Schristos const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
75a89c9211Schristos {
769cef71b6Sspz if (ctx == NULL || directory == NULL) {
77a89c9211Schristos errno = EINVAL;
78a89c9211Schristos return 0;
79a89c9211Schristos }
80a89c9211Schristos
81a89c9211Schristos errno = 0;
829cef71b6Sspz if (*ctx == NULL) {
83e289ce59Sspz size_t dirlen = strlen(directory);
84e289ce59Sspz
855af53050Schristos if (dirlen == 0 || dirlen > INT_MAX - 3) {
86e289ce59Sspz errno = ENOENT;
87e289ce59Sspz return 0;
88e289ce59Sspz }
89e289ce59Sspz
905af53050Schristos *ctx = malloc(sizeof(**ctx));
919cef71b6Sspz if (*ctx == NULL) {
92a89c9211Schristos errno = ENOMEM;
93a89c9211Schristos return 0;
94a89c9211Schristos }
955af53050Schristos memset(*ctx, 0, sizeof(**ctx));
96e289ce59Sspz
979cef71b6Sspz if (sizeof(TCHAR) != sizeof(char)) {
98a89c9211Schristos TCHAR *wdir = NULL;
99a89c9211Schristos /* len_0 denotes string length *with* trailing 0 */
1005af53050Schristos size_t index = 0, len_0 = dirlen + 1;
1015af53050Schristos #ifdef LP_MULTIBYTE_AVAILABLE
1025af53050Schristos int sz = 0;
1035af53050Schristos UINT cp;
104a89c9211Schristos
1055af53050Schristos do {
1065af53050Schristos # ifdef CP_UTF8
1075af53050Schristos if ((sz = MultiByteToWideChar((cp = CP_UTF8), 0,
1085af53050Schristos directory, len_0,
1095af53050Schristos NULL, 0)) > 0 ||
1105af53050Schristos GetLastError() != ERROR_NO_UNICODE_TRANSLATION)
1115af53050Schristos break;
1125af53050Schristos # endif
1135af53050Schristos sz = MultiByteToWideChar((cp = CP_ACP), 0,
1145af53050Schristos directory, len_0,
1155af53050Schristos NULL, 0);
1165af53050Schristos } while (0);
1175af53050Schristos
1185af53050Schristos if (sz > 0) {
1195af53050Schristos /*
1205af53050Schristos * allocate two additional characters in case we need to
1215af53050Schristos * concatenate asterisk, |sz| covers trailing '\0'!
1225af53050Schristos */
1235af53050Schristos wdir = _alloca((sz + 2) * sizeof(TCHAR));
1245af53050Schristos if (!MultiByteToWideChar(cp, 0, directory, len_0,
1255af53050Schristos (WCHAR *)wdir, sz)) {
126a89c9211Schristos free(*ctx);
127a89c9211Schristos *ctx = NULL;
1285af53050Schristos errno = EINVAL;
129a89c9211Schristos return 0;
130a89c9211Schristos }
1315af53050Schristos } else
132a89c9211Schristos #endif
1335af53050Schristos {
1345af53050Schristos sz = len_0;
1355af53050Schristos /*
1365af53050Schristos * allocate two additional characters in case we need to
1375af53050Schristos * concatenate asterisk, |sz| covers trailing '\0'!
1385af53050Schristos */
1395af53050Schristos wdir = _alloca((sz + 2) * sizeof(TCHAR));
140a89c9211Schristos for (index = 0; index < len_0; index++)
1415af53050Schristos wdir[index] = (TCHAR)directory[index];
1425af53050Schristos }
1435af53050Schristos
1445af53050Schristos sz--; /* wdir[sz] is trailing '\0' now */
1455af53050Schristos if (wdir[sz - 1] != TEXT('*')) {
1465af53050Schristos if (wdir[sz - 1] != TEXT('/') && wdir[sz - 1] != TEXT('\\'))
1475af53050Schristos _tcscpy(wdir + sz, TEXT("/*"));
1485af53050Schristos else
1495af53050Schristos _tcscpy(wdir + sz, TEXT("*"));
1505af53050Schristos }
151a89c9211Schristos
152a89c9211Schristos (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
1539cef71b6Sspz } else {
1545af53050Schristos if (directory[dirlen - 1] != '*') {
1555af53050Schristos char *buf = _alloca(dirlen + 3);
1565af53050Schristos
1575af53050Schristos strcpy(buf, directory);
1585af53050Schristos if (buf[dirlen - 1] != '/' && buf[dirlen - 1] != '\\')
1595af53050Schristos strcpy(buf + dirlen, "/*");
1605af53050Schristos else
1615af53050Schristos strcpy(buf + dirlen, "*");
1625af53050Schristos
1635af53050Schristos directory = buf;
164e289ce59Sspz }
1655af53050Schristos
1665af53050Schristos (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
167e289ce59Sspz }
168a89c9211Schristos
1699cef71b6Sspz if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
170a89c9211Schristos free(*ctx);
171a89c9211Schristos *ctx = NULL;
172a89c9211Schristos errno = EINVAL;
173a89c9211Schristos return 0;
174a89c9211Schristos }
1759cef71b6Sspz } else {
1769cef71b6Sspz if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
177a89c9211Schristos return 0;
178a89c9211Schristos }
179a89c9211Schristos }
1809cef71b6Sspz if (sizeof(TCHAR) != sizeof(char)) {
181a89c9211Schristos TCHAR *wdir = (*ctx)->ctx.cFileName;
182a89c9211Schristos size_t index, len_0 = 0;
183a89c9211Schristos
1849cef71b6Sspz while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1))
1859cef71b6Sspz len_0++;
186a89c9211Schristos len_0++;
187a89c9211Schristos
188a89c9211Schristos #ifdef LP_MULTIBYTE_AVAILABLE
1895af53050Schristos if (!WideCharToMultiByte(CP_DEFAULT, 0, (WCHAR *)wdir, len_0,
1905af53050Schristos (*ctx)->entry_name,
191a89c9211Schristos sizeof((*ctx)->entry_name), NULL, 0))
192a89c9211Schristos #endif
193a89c9211Schristos for (index = 0; index < len_0; index++)
194a89c9211Schristos (*ctx)->entry_name[index] = (char)wdir[index];
1959cef71b6Sspz } else
196a89c9211Schristos strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
197a89c9211Schristos sizeof((*ctx)->entry_name) - 1);
198a89c9211Schristos
199a89c9211Schristos (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
200a89c9211Schristos
201a89c9211Schristos return (*ctx)->entry_name;
202a89c9211Schristos }
203a89c9211Schristos
LP_find_file_end(LP_DIR_CTX ** ctx)204a89c9211Schristos int LP_find_file_end(LP_DIR_CTX **ctx)
205a89c9211Schristos {
2069cef71b6Sspz if (ctx != NULL && *ctx != NULL) {
207a89c9211Schristos FindClose((*ctx)->handle);
208a89c9211Schristos free(*ctx);
209a89c9211Schristos *ctx = NULL;
210a89c9211Schristos return 1;
211a89c9211Schristos }
212a89c9211Schristos errno = EINVAL;
213a89c9211Schristos return 0;
214a89c9211Schristos }
215