1 /* crypto/bio/bss_file.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
26 * 1. Redistributions of source code must retain the copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * "This product includes cryptographic software written by
34 * Eric Young (eay@cryptsoft.com)"
35 * The word 'cryptographic' can be left out if the rouines from the library
36 * being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 * the apps directory (application code) you must include an acknowledgement:
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed. i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
60 * 03-Dec-1997 rdenny@dc3.com Fix bug preventing use of stdin/stdout
61 * with binary data (e.g. asn1parse -inform DER < xxx) under
65 #ifndef HEADER_BSS_FILE_C
66 # define HEADER_BSS_FILE_C
68 # if defined(__linux) || defined(__sun) || defined(__hpux)
70 * Following definition aliases fopen to fopen64 on above mentioned
71 * platforms. This makes it possible to open and sequentially access files
72 * larger than 2GB from 32-bit application. It does not allow to traverse
73 * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit
74 * platform permits that, not with fseek/ftell. Not to mention that breaking
75 * 2GB limit for seeking would require surgery to *our* API. But sequential
76 * access suffices for practical cases when you can run into large files,
77 * such as fingerprinting, so we can let API alone. For reference, the list
78 * of 32-bit platforms which allow for sequential access of large files
79 * without extra "magic" comprise *BSD, Darwin, IRIX...
81 # ifndef _FILE_OFFSET_BITS
82 # define _FILE_OFFSET_BITS 64
88 # include "internal/cryptlib.h"
90 # include <openssl/err.h>
92 # if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_CLIB)
93 # include <nwfileio.h>
96 # if !defined(OPENSSL_NO_STDIO)
98 static int file_write(BIO
*h
, const char *buf
, int num
);
99 static int file_read(BIO
*h
, char *buf
, int size
);
100 static int file_puts(BIO
*h
, const char *str
);
101 static int file_gets(BIO
*h
, char *str
, int size
);
102 static long file_ctrl(BIO
*h
, int cmd
, long arg1
, void *arg2
);
103 static int file_new(BIO
*h
);
104 static int file_free(BIO
*data
);
105 static BIO_METHOD methods_filep
= {
118 static FILE *file_fopen(const char *filename
, const char *mode
)
122 # if defined(_WIN32) && defined(CP_UTF8)
123 int sz
, len_0
= (int)strlen(filename
) + 1;
127 * Basically there are three cases to cover: a) filename is
128 * pure ASCII string; b) actual UTF-8 encoded string and
129 * c) locale-ized string, i.e. one containing 8-bit
130 * characters that are meaningful in current system locale.
131 * If filename is pure ASCII or real UTF-8 encoded string,
132 * MultiByteToWideChar succeeds and _wfopen works. If
133 * filename is locale-ized string, chances are that
134 * MultiByteToWideChar fails reporting
135 * ERROR_NO_UNICODE_TRANSLATION, in which case we fall
138 if ((sz
= MultiByteToWideChar(CP_UTF8
, (flags
= MB_ERR_INVALID_CHARS
),
139 filename
, len_0
, NULL
, 0)) > 0 ||
140 (GetLastError() == ERROR_INVALID_FLAGS
&&
141 (sz
= MultiByteToWideChar(CP_UTF8
, (flags
= 0),
142 filename
, len_0
, NULL
, 0)) > 0)
145 WCHAR
*wfilename
= _alloca(sz
* sizeof(WCHAR
));
147 if (MultiByteToWideChar(CP_UTF8
, flags
,
148 filename
, len_0
, wfilename
, sz
) &&
149 MultiByteToWideChar(CP_UTF8
, 0, mode
, strlen(mode
) + 1,
150 wmode
, OSSL_NELEM(wmode
)) &&
151 (file
= _wfopen(wfilename
, wmode
)) == NULL
&&
152 (errno
== ENOENT
|| errno
== EBADF
)
155 * UTF-8 decode succeeded, but no file, filename
156 * could still have been locale-ized...
158 file
= fopen(filename
, mode
);
160 } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION
) {
161 file
= fopen(filename
, mode
);
164 file
= fopen(filename
, mode
);
169 BIO
*BIO_new_file(const char *filename
, const char *mode
)
172 FILE *file
= file_fopen(filename
, mode
);
175 SYSerr(SYS_F_FOPEN
, get_last_sys_error());
176 ERR_add_error_data(5, "fopen('", filename
, "','", mode
, "')");
178 BIOerr(BIO_F_BIO_NEW_FILE
, BIO_R_NO_SUCH_FILE
);
180 BIOerr(BIO_F_BIO_NEW_FILE
, ERR_R_SYS_LIB
);
183 if ((ret
= BIO_new(BIO_s_file())) == NULL
) {
188 BIO_clear_flags(ret
, BIO_FLAGS_UPLINK
); /* we did fopen -> we disengage
190 BIO_set_fp(ret
, file
, BIO_CLOSE
);
194 BIO
*BIO_new_fp(FILE *stream
, int close_flag
)
198 if ((ret
= BIO_new(BIO_s_file())) == NULL
)
201 BIO_set_flags(ret
, BIO_FLAGS_UPLINK
); /* redundant, left for
202 * documentation puposes */
203 BIO_set_fp(ret
, stream
, close_flag
);
207 BIO_METHOD
*BIO_s_file(void)
209 return (&methods_filep
);
212 static int file_new(BIO
*bi
)
217 bi
->flags
= BIO_FLAGS_UPLINK
; /* default to UPLINK */
221 static int file_free(BIO
*a
)
226 if ((a
->init
) && (a
->ptr
!= NULL
)) {
227 if (a
->flags
& BIO_FLAGS_UPLINK
)
232 a
->flags
= BIO_FLAGS_UPLINK
;
239 static int file_read(BIO
*b
, char *out
, int outl
)
243 if (b
->init
&& (out
!= NULL
)) {
244 if (b
->flags
& BIO_FLAGS_UPLINK
)
245 ret
= UP_fread(out
, 1, (int)outl
, b
->ptr
);
247 ret
= fread(out
, 1, (int)outl
, (FILE *)b
->ptr
);
249 && (b
->flags
& BIO_FLAGS_UPLINK
) ? UP_ferror((FILE *)b
->ptr
) :
250 ferror((FILE *)b
->ptr
)) {
251 SYSerr(SYS_F_FREAD
, get_last_sys_error());
252 BIOerr(BIO_F_FILE_READ
, ERR_R_SYS_LIB
);
259 static int file_write(BIO
*b
, const char *in
, int inl
)
263 if (b
->init
&& (in
!= NULL
)) {
264 if (b
->flags
& BIO_FLAGS_UPLINK
)
265 ret
= UP_fwrite(in
, (int)inl
, 1, b
->ptr
);
267 ret
= fwrite(in
, (int)inl
, 1, (FILE *)b
->ptr
);
270 /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */
272 * according to Tim Hudson <tjh@cryptsoft.com>, the commented out
273 * version above can cause 'inl' write calls under some stupid stdio
274 * implementations (VMS)
280 static long file_ctrl(BIO
*b
, int cmd
, long num
, void *ptr
)
283 FILE *fp
= (FILE *)b
->ptr
;
288 case BIO_C_FILE_SEEK
:
290 if (b
->flags
& BIO_FLAGS_UPLINK
)
291 ret
= (long)UP_fseek(b
->ptr
, num
, 0);
293 ret
= (long)fseek(fp
, num
, 0);
296 if (b
->flags
& BIO_FLAGS_UPLINK
)
297 ret
= (long)UP_feof(fp
);
299 ret
= (long)feof(fp
);
301 case BIO_C_FILE_TELL
:
303 if (b
->flags
& BIO_FLAGS_UPLINK
)
304 ret
= UP_ftell(b
->ptr
);
308 case BIO_C_SET_FILE_PTR
:
310 b
->shutdown
= (int)num
& BIO_CLOSE
;
313 # if BIO_FLAGS_UPLINK!=0
314 # if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES)
315 # define _IOB_ENTRIES 20
317 # if defined(_IOB_ENTRIES)
318 /* Safety net to catch purely internal BIO_set_fp calls */
319 if ((size_t)ptr
>= (size_t)stdin
&&
320 (size_t)ptr
< (size_t)(stdin
+ _IOB_ENTRIES
))
321 BIO_clear_flags(b
, BIO_FLAGS_UPLINK
);
325 if (b
->flags
& BIO_FLAGS_UPLINK
)
326 UP_fsetmod(b
->ptr
, (char)((num
& BIO_FP_TEXT
) ? 't' : 'b'));
330 # if defined(OPENSSL_SYS_WINDOWS)
331 int fd
= _fileno((FILE *)ptr
);
332 if (num
& BIO_FP_TEXT
)
333 _setmode(fd
, _O_TEXT
);
335 _setmode(fd
, _O_BINARY
);
336 # elif defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_CLIB)
337 int fd
= fileno((FILE *)ptr
);
338 /* Under CLib there are differences in file modes */
339 if (num
& BIO_FP_TEXT
)
342 setmode(fd
, O_BINARY
);
343 # elif defined(OPENSSL_SYS_MSDOS)
344 int fd
= fileno((FILE *)ptr
);
345 /* Set correct text/binary mode */
346 if (num
& BIO_FP_TEXT
)
347 _setmode(fd
, _O_TEXT
);
348 /* Dangerous to set stdin/stdout to raw (unless redirected) */
350 if (fd
== STDIN_FILENO
|| fd
== STDOUT_FILENO
) {
352 _setmode(fd
, _O_BINARY
);
354 _setmode(fd
, _O_BINARY
);
356 # elif defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_WIN32_CYGWIN)
357 int fd
= fileno((FILE *)ptr
);
358 if (num
& BIO_FP_TEXT
)
361 setmode(fd
, O_BINARY
);
365 case BIO_C_SET_FILENAME
:
367 b
->shutdown
= (int)num
& BIO_CLOSE
;
368 if (num
& BIO_FP_APPEND
) {
369 if (num
& BIO_FP_READ
)
370 OPENSSL_strlcpy(p
, "a+", sizeof p
);
372 OPENSSL_strlcpy(p
, "a", sizeof p
);
373 } else if ((num
& BIO_FP_READ
) && (num
& BIO_FP_WRITE
))
374 OPENSSL_strlcpy(p
, "r+", sizeof p
);
375 else if (num
& BIO_FP_WRITE
)
376 OPENSSL_strlcpy(p
, "w", sizeof p
);
377 else if (num
& BIO_FP_READ
)
378 OPENSSL_strlcpy(p
, "r", sizeof p
);
380 BIOerr(BIO_F_FILE_CTRL
, BIO_R_BAD_FOPEN_MODE
);
384 # if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_WIN32_CYGWIN)
385 if (!(num
& BIO_FP_TEXT
))
390 # if defined(OPENSSL_SYS_NETWARE)
391 if (!(num
& BIO_FP_TEXT
))
396 fp
= file_fopen(ptr
, p
);
398 SYSerr(SYS_F_FOPEN
, get_last_sys_error());
399 ERR_add_error_data(5, "fopen('", ptr
, "','", p
, "')");
400 BIOerr(BIO_F_FILE_CTRL
, ERR_R_SYS_LIB
);
406 BIO_clear_flags(b
, BIO_FLAGS_UPLINK
); /* we did fopen -> we disengage
409 case BIO_C_GET_FILE_PTR
:
410 /* the ptr parameter is actually a FILE ** in this case. */
413 *fpp
= (FILE *)b
->ptr
;
416 case BIO_CTRL_GET_CLOSE
:
417 ret
= (long)b
->shutdown
;
419 case BIO_CTRL_SET_CLOSE
:
420 b
->shutdown
= (int)num
;
423 if (b
->flags
& BIO_FLAGS_UPLINK
)
426 fflush((FILE *)b
->ptr
);
432 case BIO_CTRL_WPENDING
:
433 case BIO_CTRL_PENDING
:
443 static int file_gets(BIO
*bp
, char *buf
, int size
)
448 if (bp
->flags
& BIO_FLAGS_UPLINK
) {
449 if (!UP_fgets(buf
, size
, bp
->ptr
))
452 if (!fgets(buf
, size
, (FILE *)bp
->ptr
))
461 static int file_puts(BIO
*bp
, const char *str
)
466 ret
= file_write(bp
, str
, n
);
472 static int file_write(BIO
*b
, const char *in
, int inl
)
476 static int file_read(BIO
*b
, char *out
, int outl
)
480 static int file_puts(BIO
*bp
, const char *str
)
484 static int file_gets(BIO
*bp
, char *buf
, int size
)
488 static long file_ctrl(BIO
*b
, int cmd
, long num
, void *ptr
)
492 static int file_new(BIO
*bi
)
496 static int file_free(BIO
*a
)
501 static BIO_METHOD methods_filep
= {
514 BIO_METHOD
*BIO_s_file(void)
516 return (&methods_filep
);
519 BIO
*BIO_new_file(const char *filename
, const char *mode
)
524 # endif /* OPENSSL_NO_STDIO */
526 #endif /* HEADER_BSS_FILE_C */