1*e0c4386eSCy Schubert /*
2*e0c4386eSCy Schubert * Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert *
4*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
6*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert */
9*e0c4386eSCy Schubert
10*e0c4386eSCy Schubert /*
11*e0c4386eSCy Schubert * This file is dual-licensed and is also available under the following
12*e0c4386eSCy Schubert * terms:
13*e0c4386eSCy Schubert *
14*e0c4386eSCy Schubert * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
15*e0c4386eSCy Schubert * All rights reserved.
16*e0c4386eSCy Schubert *
17*e0c4386eSCy Schubert * Redistribution and use in source and binary forms, with or without
18*e0c4386eSCy Schubert * modification, are permitted provided that the following conditions
19*e0c4386eSCy Schubert * are met:
20*e0c4386eSCy Schubert * 1. Redistributions of source code must retain the above copyright
21*e0c4386eSCy Schubert * notice, this list of conditions and the following disclaimer.
22*e0c4386eSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
23*e0c4386eSCy Schubert * notice, this list of conditions and the following disclaimer in the
24*e0c4386eSCy Schubert * documentation and/or other materials provided with the distribution.
25*e0c4386eSCy Schubert *
26*e0c4386eSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27*e0c4386eSCy Schubert * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28*e0c4386eSCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29*e0c4386eSCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30*e0c4386eSCy Schubert * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31*e0c4386eSCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32*e0c4386eSCy Schubert * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33*e0c4386eSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34*e0c4386eSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35*e0c4386eSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36*e0c4386eSCy Schubert * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*e0c4386eSCy Schubert */
38*e0c4386eSCy Schubert
39*e0c4386eSCy Schubert #include <windows.h>
40*e0c4386eSCy Schubert #include <tchar.h>
41*e0c4386eSCy Schubert #include "internal/numbers.h"
42*e0c4386eSCy Schubert #ifndef LPDIR_H
43*e0c4386eSCy Schubert # include "LPdir.h"
44*e0c4386eSCy Schubert #endif
45*e0c4386eSCy Schubert
46*e0c4386eSCy Schubert /*
47*e0c4386eSCy Schubert * We're most likely overcautious here, but let's reserve for broken WinCE
48*e0c4386eSCy Schubert * headers and explicitly opt for UNICODE call. Keep in mind that our WinCE
49*e0c4386eSCy Schubert * builds are compiled with -DUNICODE [as well as -D_UNICODE].
50*e0c4386eSCy Schubert */
51*e0c4386eSCy Schubert #if defined(LP_SYS_WINCE) && !defined(FindFirstFile)
52*e0c4386eSCy Schubert # define FindFirstFile FindFirstFileW
53*e0c4386eSCy Schubert #endif
54*e0c4386eSCy Schubert #if defined(LP_SYS_WINCE) && !defined(FindNextFile)
55*e0c4386eSCy Schubert # define FindNextFile FindNextFileW
56*e0c4386eSCy Schubert #endif
57*e0c4386eSCy Schubert
58*e0c4386eSCy Schubert #ifndef NAME_MAX
59*e0c4386eSCy Schubert # define NAME_MAX 255
60*e0c4386eSCy Schubert #endif
61*e0c4386eSCy Schubert
62*e0c4386eSCy Schubert #ifdef CP_UTF8
63*e0c4386eSCy Schubert # define CP_DEFAULT CP_UTF8
64*e0c4386eSCy Schubert #else
65*e0c4386eSCy Schubert # define CP_DEFAULT CP_ACP
66*e0c4386eSCy Schubert #endif
67*e0c4386eSCy Schubert
68*e0c4386eSCy Schubert struct LP_dir_context_st {
69*e0c4386eSCy Schubert WIN32_FIND_DATA ctx;
70*e0c4386eSCy Schubert HANDLE handle;
71*e0c4386eSCy Schubert char entry_name[NAME_MAX + 1];
72*e0c4386eSCy Schubert };
73*e0c4386eSCy Schubert
LP_find_file(LP_DIR_CTX ** ctx,const char * directory)74*e0c4386eSCy Schubert const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
75*e0c4386eSCy Schubert {
76*e0c4386eSCy Schubert if (ctx == NULL || directory == NULL) {
77*e0c4386eSCy Schubert errno = EINVAL;
78*e0c4386eSCy Schubert return 0;
79*e0c4386eSCy Schubert }
80*e0c4386eSCy Schubert
81*e0c4386eSCy Schubert errno = 0;
82*e0c4386eSCy Schubert if (*ctx == NULL) {
83*e0c4386eSCy Schubert size_t dirlen = strlen(directory);
84*e0c4386eSCy Schubert
85*e0c4386eSCy Schubert if (dirlen == 0 || dirlen > INT_MAX - 3) {
86*e0c4386eSCy Schubert errno = ENOENT;
87*e0c4386eSCy Schubert return 0;
88*e0c4386eSCy Schubert }
89*e0c4386eSCy Schubert
90*e0c4386eSCy Schubert *ctx = malloc(sizeof(**ctx));
91*e0c4386eSCy Schubert if (*ctx == NULL) {
92*e0c4386eSCy Schubert errno = ENOMEM;
93*e0c4386eSCy Schubert return 0;
94*e0c4386eSCy Schubert }
95*e0c4386eSCy Schubert memset(*ctx, 0, sizeof(**ctx));
96*e0c4386eSCy Schubert
97*e0c4386eSCy Schubert if (sizeof(TCHAR) != sizeof(char)) {
98*e0c4386eSCy Schubert TCHAR *wdir = NULL;
99*e0c4386eSCy Schubert /* len_0 denotes string length *with* trailing 0 */
100*e0c4386eSCy Schubert size_t index = 0, len_0 = dirlen + 1;
101*e0c4386eSCy Schubert #ifdef LP_MULTIBYTE_AVAILABLE
102*e0c4386eSCy Schubert int sz = 0;
103*e0c4386eSCy Schubert UINT cp;
104*e0c4386eSCy Schubert
105*e0c4386eSCy Schubert do {
106*e0c4386eSCy Schubert # ifdef CP_UTF8
107*e0c4386eSCy Schubert if ((sz = MultiByteToWideChar((cp = CP_UTF8), 0,
108*e0c4386eSCy Schubert directory, len_0,
109*e0c4386eSCy Schubert NULL, 0)) > 0 ||
110*e0c4386eSCy Schubert GetLastError() != ERROR_NO_UNICODE_TRANSLATION)
111*e0c4386eSCy Schubert break;
112*e0c4386eSCy Schubert # endif
113*e0c4386eSCy Schubert sz = MultiByteToWideChar((cp = CP_ACP), 0,
114*e0c4386eSCy Schubert directory, len_0,
115*e0c4386eSCy Schubert NULL, 0);
116*e0c4386eSCy Schubert } while (0);
117*e0c4386eSCy Schubert
118*e0c4386eSCy Schubert if (sz > 0) {
119*e0c4386eSCy Schubert /*
120*e0c4386eSCy Schubert * allocate two additional characters in case we need to
121*e0c4386eSCy Schubert * concatenate asterisk, |sz| covers trailing '\0'!
122*e0c4386eSCy Schubert */
123*e0c4386eSCy Schubert wdir = _alloca((sz + 2) * sizeof(TCHAR));
124*e0c4386eSCy Schubert if (!MultiByteToWideChar(cp, 0, directory, len_0,
125*e0c4386eSCy Schubert (WCHAR *)wdir, sz)) {
126*e0c4386eSCy Schubert free(*ctx);
127*e0c4386eSCy Schubert *ctx = NULL;
128*e0c4386eSCy Schubert errno = EINVAL;
129*e0c4386eSCy Schubert return 0;
130*e0c4386eSCy Schubert }
131*e0c4386eSCy Schubert } else
132*e0c4386eSCy Schubert #endif
133*e0c4386eSCy Schubert {
134*e0c4386eSCy Schubert sz = len_0;
135*e0c4386eSCy Schubert /*
136*e0c4386eSCy Schubert * allocate two additional characters in case we need to
137*e0c4386eSCy Schubert * concatenate asterisk, |sz| covers trailing '\0'!
138*e0c4386eSCy Schubert */
139*e0c4386eSCy Schubert wdir = _alloca((sz + 2) * sizeof(TCHAR));
140*e0c4386eSCy Schubert for (index = 0; index < len_0; index++)
141*e0c4386eSCy Schubert wdir[index] = (TCHAR)directory[index];
142*e0c4386eSCy Schubert }
143*e0c4386eSCy Schubert
144*e0c4386eSCy Schubert sz--; /* wdir[sz] is trailing '\0' now */
145*e0c4386eSCy Schubert if (wdir[sz - 1] != TEXT('*')) {
146*e0c4386eSCy Schubert if (wdir[sz - 1] != TEXT('/') && wdir[sz - 1] != TEXT('\\'))
147*e0c4386eSCy Schubert _tcscpy(wdir + sz, TEXT("/*"));
148*e0c4386eSCy Schubert else
149*e0c4386eSCy Schubert _tcscpy(wdir + sz, TEXT("*"));
150*e0c4386eSCy Schubert }
151*e0c4386eSCy Schubert
152*e0c4386eSCy Schubert (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
153*e0c4386eSCy Schubert } else {
154*e0c4386eSCy Schubert if (directory[dirlen - 1] != '*') {
155*e0c4386eSCy Schubert char *buf = _alloca(dirlen + 3);
156*e0c4386eSCy Schubert
157*e0c4386eSCy Schubert strcpy(buf, directory);
158*e0c4386eSCy Schubert if (buf[dirlen - 1] != '/' && buf[dirlen - 1] != '\\')
159*e0c4386eSCy Schubert strcpy(buf + dirlen, "/*");
160*e0c4386eSCy Schubert else
161*e0c4386eSCy Schubert strcpy(buf + dirlen, "*");
162*e0c4386eSCy Schubert
163*e0c4386eSCy Schubert directory = buf;
164*e0c4386eSCy Schubert }
165*e0c4386eSCy Schubert
166*e0c4386eSCy Schubert (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
167*e0c4386eSCy Schubert }
168*e0c4386eSCy Schubert
169*e0c4386eSCy Schubert if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
170*e0c4386eSCy Schubert free(*ctx);
171*e0c4386eSCy Schubert *ctx = NULL;
172*e0c4386eSCy Schubert errno = EINVAL;
173*e0c4386eSCy Schubert return 0;
174*e0c4386eSCy Schubert }
175*e0c4386eSCy Schubert } else {
176*e0c4386eSCy Schubert if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
177*e0c4386eSCy Schubert return 0;
178*e0c4386eSCy Schubert }
179*e0c4386eSCy Schubert }
180*e0c4386eSCy Schubert if (sizeof(TCHAR) != sizeof(char)) {
181*e0c4386eSCy Schubert TCHAR *wdir = (*ctx)->ctx.cFileName;
182*e0c4386eSCy Schubert size_t index, len_0 = 0;
183*e0c4386eSCy Schubert
184*e0c4386eSCy Schubert while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1))
185*e0c4386eSCy Schubert len_0++;
186*e0c4386eSCy Schubert len_0++;
187*e0c4386eSCy Schubert
188*e0c4386eSCy Schubert #ifdef LP_MULTIBYTE_AVAILABLE
189*e0c4386eSCy Schubert if (!WideCharToMultiByte(CP_DEFAULT, 0, (WCHAR *)wdir, len_0,
190*e0c4386eSCy Schubert (*ctx)->entry_name,
191*e0c4386eSCy Schubert sizeof((*ctx)->entry_name), NULL, 0))
192*e0c4386eSCy Schubert #endif
193*e0c4386eSCy Schubert for (index = 0; index < len_0; index++)
194*e0c4386eSCy Schubert (*ctx)->entry_name[index] = (char)wdir[index];
195*e0c4386eSCy Schubert } else
196*e0c4386eSCy Schubert strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
197*e0c4386eSCy Schubert sizeof((*ctx)->entry_name) - 1);
198*e0c4386eSCy Schubert
199*e0c4386eSCy Schubert (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
200*e0c4386eSCy Schubert
201*e0c4386eSCy Schubert return (*ctx)->entry_name;
202*e0c4386eSCy Schubert }
203*e0c4386eSCy Schubert
LP_find_file_end(LP_DIR_CTX ** ctx)204*e0c4386eSCy Schubert int LP_find_file_end(LP_DIR_CTX **ctx)
205*e0c4386eSCy Schubert {
206*e0c4386eSCy Schubert if (ctx != NULL && *ctx != NULL) {
207*e0c4386eSCy Schubert FindClose((*ctx)->handle);
208*e0c4386eSCy Schubert free(*ctx);
209*e0c4386eSCy Schubert *ctx = NULL;
210*e0c4386eSCy Schubert return 1;
211*e0c4386eSCy Schubert }
212*e0c4386eSCy Schubert errno = EINVAL;
213*e0c4386eSCy Schubert return 0;
214*e0c4386eSCy Schubert }
215