/src/openssl/crypto/o_fopen.c
Line  | Count  | Source  | 
1  |  | /*  | 
2  |  |  * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.  | 
3  |  |  *  | 
4  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use  | 
5  |  |  * this file except in compliance with the License.  You can obtain a copy  | 
6  |  |  * in the file LICENSE in the source distribution or at  | 
7  |  |  * https://www.openssl.org/source/license.html  | 
8  |  |  */  | 
9  |  |  | 
10  |  | # if defined(__linux) || defined(__sun) || defined(__hpux)  | 
11  |  | /*  | 
12  |  |  * Following definition aliases fopen to fopen64 on above mentioned  | 
13  |  |  * platforms. This makes it possible to open and sequentially access files  | 
14  |  |  * larger than 2GB from 32-bit application. It does not allow to traverse  | 
15  |  |  * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit  | 
16  |  |  * platform permits that, not with fseek/ftell. Not to mention that breaking  | 
17  |  |  * 2GB limit for seeking would require surgery to *our* API. But sequential  | 
18  |  |  * access suffices for practical cases when you can run into large files,  | 
19  |  |  * such as fingerprinting, so we can let API alone. For reference, the list  | 
20  |  |  * of 32-bit platforms which allow for sequential access of large files  | 
21  |  |  * without extra "magic" comprise *BSD, Darwin, IRIX...  | 
22  |  |  */  | 
23  |  | #  ifndef _FILE_OFFSET_BITS  | 
24  |  | #   define _FILE_OFFSET_BITS 64  | 
25  |  | #  endif  | 
26  |  | # endif  | 
27  |  |  | 
28  |  | #include "e_os.h"  | 
29  |  | #include "internal/cryptlib.h"  | 
30  |  |  | 
31  |  | #if !defined(OPENSSL_NO_STDIO)  | 
32  |  |  | 
33  |  | # include <stdio.h>  | 
34  |  | # ifdef __DJGPP__  | 
35  |  | #  include <unistd.h>  | 
36  |  | # endif  | 
37  |  |  | 
38  |  | FILE *openssl_fopen(const char *filename, const char *mode)  | 
39  | 12  | { | 
40  | 12  |     FILE *file = NULL;  | 
41  |  | # if defined(_WIN32) && defined(CP_UTF8)  | 
42  |  |     int sz, len_0 = (int)strlen(filename) + 1;  | 
43  |  |     DWORD flags;  | 
44  |  |  | 
45  |  |     /*  | 
46  |  |      * Basically there are three cases to cover: a) filename is  | 
47  |  |      * pure ASCII string; b) actual UTF-8 encoded string and  | 
48  |  |      * c) locale-ized string, i.e. one containing 8-bit  | 
49  |  |      * characters that are meaningful in current system locale.  | 
50  |  |      * If filename is pure ASCII or real UTF-8 encoded string,  | 
51  |  |      * MultiByteToWideChar succeeds and _wfopen works. If  | 
52  |  |      * filename is locale-ized string, chances are that  | 
53  |  |      * MultiByteToWideChar fails reporting  | 
54  |  |      * ERROR_NO_UNICODE_TRANSLATION, in which case we fall  | 
55  |  |      * back to fopen...  | 
56  |  |      */  | 
57  |  |     if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS),  | 
58  |  |                                   filename, len_0, NULL, 0)) > 0 ||  | 
59  |  |         (GetLastError() == ERROR_INVALID_FLAGS &&  | 
60  |  |          (sz = MultiByteToWideChar(CP_UTF8, (flags = 0),  | 
61  |  |                                    filename, len_0, NULL, 0)) > 0)  | 
62  |  |         ) { | 
63  |  |         WCHAR wmode[8];  | 
64  |  |         WCHAR *wfilename = _alloca(sz * sizeof(WCHAR));  | 
65  |  |  | 
66  |  |         if (MultiByteToWideChar(CP_UTF8, flags,  | 
67  |  |                                 filename, len_0, wfilename, sz) &&  | 
68  |  |             MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1,  | 
69  |  |                                 wmode, OSSL_NELEM(wmode)) &&  | 
70  |  |             (file = _wfopen(wfilename, wmode)) == NULL &&  | 
71  |  |             (errno == ENOENT || errno == EBADF)  | 
72  |  |             ) { | 
73  |  |             /*  | 
74  |  |              * UTF-8 decode succeeded, but no file, filename  | 
75  |  |              * could still have been locale-ized...  | 
76  |  |              */  | 
77  |  |             file = fopen(filename, mode);  | 
78  |  |         }  | 
79  |  |     } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { | 
80  |  |         file = fopen(filename, mode);  | 
81  |  |     }  | 
82  |  | # elif defined(__DJGPP__)  | 
83  |  |     { | 
84  |  |         char *newname = NULL;  | 
85  |  |  | 
86  |  |         if (pathconf(filename, _PC_NAME_MAX) <= 12) {  /* 8.3 file system? */ | 
87  |  |             char *iterator;  | 
88  |  |             char lastchar;  | 
89  |  |  | 
90  |  |             if ((newname = OPENSSL_malloc(strlen(filename) + 1)) == NULL) { | 
91  |  |                 CRYPTOerr(CRYPTO_F_OPENSSL_FOPEN, ERR_R_MALLOC_FAILURE);  | 
92  |  |                 return NULL;  | 
93  |  |             }  | 
94  |  |  | 
95  |  |             for (iterator = newname, lastchar = '\0';  | 
96  |  |                 *filename; filename++, iterator++) { | 
97  |  |                 if (lastchar == '/' && filename[0] == '.'  | 
98  |  |                     && filename[1] != '.' && filename[1] != '/') { | 
99  |  |                     /* Leading dots are not permitted in plain DOS. */  | 
100  |  |                     *iterator = '_';  | 
101  |  |                 } else { | 
102  |  |                     *iterator = *filename;  | 
103  |  |                 }  | 
104  |  |                 lastchar = *filename;  | 
105  |  |             }  | 
106  |  |             *iterator = '\0';  | 
107  |  |             filename = newname;  | 
108  |  |         }  | 
109  |  |         file = fopen(filename, mode);  | 
110  |  |  | 
111  |  |         OPENSSL_free(newname);  | 
112  |  |     }  | 
113  |  | # else  | 
114  | 12  |     file = fopen(filename, mode);  | 
115  | 12  | # endif  | 
116  | 12  |     return file;  | 
117  | 12  | }  | 
118  |  |  | 
119  |  | #else  | 
120  |  |  | 
121  |  | void *openssl_fopen(const char *filename, const char *mode)  | 
122  |  | { | 
123  |  |     return NULL;  | 
124  |  | }  | 
125  |  |  | 
126  |  | #endif  |