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