xref: /freebsd-src/crypto/openssl/crypto/LPdir_win.c (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
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