o_fopen.c 4.2 KB

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