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