/src/mysql-server/mysys/my_read.cc
Line | Count | Source |
1 | | /* Copyright (c) 2000, 2025, Oracle and/or its affiliates. |
2 | | |
3 | | This program is free software; you can redistribute it and/or modify |
4 | | it under the terms of the GNU General Public License, version 2.0, |
5 | | as published by the Free Software Foundation. |
6 | | |
7 | | This program is designed to work with certain software (including |
8 | | but not limited to OpenSSL) that is licensed under separate terms, |
9 | | as designated in a particular file or component or in included license |
10 | | documentation. The authors of MySQL hereby grant you an additional |
11 | | permission to link the program and your derivative works with the |
12 | | separately licensed software that they have either included with |
13 | | the program or referenced in the documentation. |
14 | | |
15 | | Without limiting anything contained in the foregoing, this file, |
16 | | which is part of C Driver for MySQL (Connector/C), is also subject to the |
17 | | Universal FOSS Exception, version 1.0, a copy of which can be found at |
18 | | http://oss.oracle.com/licenses/universal-foss-exception. |
19 | | |
20 | | This program is distributed in the hope that it will be useful, |
21 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | | GNU General Public License, version 2.0, for more details. |
24 | | |
25 | | You should have received a copy of the GNU General Public License |
26 | | along with this program; if not, write to the Free Software |
27 | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
28 | | |
29 | | /** |
30 | | @file mysys/my_read.cc |
31 | | */ |
32 | | |
33 | | #include "my_config.h" |
34 | | |
35 | | #include <sys/types.h> |
36 | | #include <cerrno> |
37 | | #include <cstddef> |
38 | | #include <cstdint> |
39 | | #ifdef HAVE_UNISTD_H |
40 | | #include <unistd.h> |
41 | | #endif |
42 | | |
43 | | #include "my_base.h" |
44 | | #include "my_dbug.h" |
45 | | #include "my_inttypes.h" |
46 | | #include "my_sys.h" |
47 | | #include "my_thread_local.h" |
48 | | #include "mysys_err.h" |
49 | | #ifdef _WIN32 |
50 | | #include "mysys/mysys_priv.h" |
51 | | #endif |
52 | | |
53 | | #ifndef _WIN32 |
54 | | // Mock away read() for unit testing. |
55 | | ssize_t (*mock_read)(int fd, void *buf, size_t count) = nullptr; |
56 | | #endif |
57 | | |
58 | | /** |
59 | | Read a chunk of bytes from a file with retry's if needed |
60 | | If flag MY_FULL_IO is set then keep reading until EOF is found. |
61 | | |
62 | | @param fd File descriptor to read from |
63 | | @param[out] Buffer Buffer to hold at least Count bytes |
64 | | @param Count Bytes to read |
65 | | @param MyFlags Flags on what to do on error |
66 | | |
67 | | @return Operation status |
68 | | @retval -1 on error |
69 | | @retval 0 if flag has bits MY_NABP or MY_FNABP set |
70 | | @retval N number of bytes read |
71 | | */ |
72 | | |
73 | 0 | size_t my_read(File fd, uchar *Buffer, size_t Count, myf MyFlags) { |
74 | 0 | int64_t savedbytes = 0; |
75 | 0 | DBUG_TRACE; |
76 | |
|
77 | 0 | for (;;) { |
78 | 0 | errno = 0; /* Linux, Windows don't reset this on EOF/success */ |
79 | 0 | int64_t readbytes = |
80 | | #ifdef _WIN32 |
81 | | // Using my_win_pread() with offset -1 which will cause |
82 | | // ReadFile() to be called with nullptr for the OVERLAPPED |
83 | | // argument. This way we avoid having both my_win_read() |
84 | | // my_win_pread() which were identical except for the OVERLAPPED |
85 | | // arg passed to ReadFile(). |
86 | | my_win_pread(fd, Buffer, Count, -1); |
87 | | #else |
88 | 0 | (mock_read ? mock_read(fd, Buffer, Count) : read(fd, Buffer, Count)); |
89 | 0 | #endif |
90 | 0 | DBUG_EXECUTE_IF("simulate_file_read_error", { |
91 | 0 | errno = ENOSPC; |
92 | 0 | readbytes = -1; |
93 | 0 | DBUG_SET("-d,simulate_file_read_error"); |
94 | 0 | DBUG_SET("-d,simulate_my_b_fill_error"); |
95 | 0 | }); |
96 | |
|
97 | 0 | if (readbytes != static_cast<int64_t>(Count)) { |
98 | 0 | set_my_errno(errno); |
99 | 0 | if (errno == 0 || (readbytes != -1 && (MyFlags & (MY_NABP | MY_FNABP)))) |
100 | 0 | set_my_errno(HA_ERR_FILE_TOO_SHORT); |
101 | |
|
102 | 0 | if ((readbytes == 0 || readbytes == -1) && errno == EINTR) { |
103 | 0 | continue; /* Interrupted */ |
104 | 0 | } |
105 | | |
106 | 0 | if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { |
107 | 0 | if (readbytes == -1) |
108 | 0 | MyOsError(my_errno(), EE_READ, MYF(0), my_filename(fd)); |
109 | 0 | else if (MyFlags & (MY_NABP | MY_FNABP)) |
110 | 0 | MyOsError(my_errno(), EE_EOFERR, MYF(0), my_filename(fd)); |
111 | 0 | } |
112 | 0 | if (readbytes == -1 || |
113 | 0 | ((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO))) |
114 | 0 | return MY_FILE_ERROR; /* Return with error */ |
115 | | /* readbytes == 0 when EOF. No need to continue in case of EOF */ |
116 | 0 | if (readbytes != 0 && (MyFlags & MY_FULL_IO)) { |
117 | 0 | Buffer += readbytes; |
118 | 0 | Count -= readbytes; |
119 | 0 | savedbytes += readbytes; |
120 | 0 | continue; |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | 0 | if (MyFlags & (MY_NABP | MY_FNABP)) |
125 | 0 | readbytes = 0; /* Ok on read */ |
126 | 0 | else if (MyFlags & MY_FULL_IO) |
127 | 0 | readbytes += savedbytes; |
128 | |
|
129 | 0 | return readbytes; |
130 | 0 | } // for (;;) |
131 | 0 | } |