1 /* Copyright (c) 2003, 2021, 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 also distributed 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 included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 #include "mysys_priv.h"
29 #include "my_sys.h"
30 #include "mysys_err.h"
31 #include <errno.h>
32 #include "my_thread_local.h"
33
34 static void (*before_sync_wait)(void)= 0;
35 static void (*after_sync_wait)(void)= 0;
36
thr_set_sync_wait_callback(void (* before_wait)(void),void (* after_wait)(void))37 void thr_set_sync_wait_callback(void (*before_wait)(void),
38 void (*after_wait)(void))
39 {
40 before_sync_wait= before_wait;
41 after_sync_wait= after_wait;
42 }
43
44 /*
45 Sync data in file to disk
46
47 SYNOPSIS
48 my_sync()
49 fd File descritor to sync
50 my_flags Flags (now only MY_WME is supported)
51
52 NOTE
53 If file system supports its, only file data is synced, not inode data.
54
55 MY_IGNORE_BADFD is useful when fd is "volatile" - not protected by a
56 mutex. In this case by the time of fsync(), fd may be already closed by
57 another thread, or even reassigned to a different file. With this flag -
58 MY_IGNORE_BADFD - such a situation will not be considered an error.
59 (which is correct behaviour, if we know that the other thread synced the
60 file before closing)
61
62 RETURN
63 0 ok
64 -1 error
65 */
66
my_sync(File fd,myf my_flags)67 int my_sync(File fd, myf my_flags)
68 {
69 int res;
70 DBUG_ENTER("my_sync");
71 DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags));
72
73 if (before_sync_wait)
74 (*before_sync_wait)();
75 do
76 {
77 #if defined(F_FULLFSYNC)
78 /*
79 In Mac OS X >= 10.3 this call is safer than fsync() (it forces the
80 disk's cache and guarantees ordered writes).
81 */
82 if (!(res= fcntl(fd, F_FULLFSYNC, 0)))
83 break; /* ok */
84 /* Some file systems don't support F_FULLFSYNC and fail above: */
85 DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back"));
86 #endif
87 #if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC
88 res= fdatasync(fd);
89 #elif defined(HAVE_FSYNC)
90 res= fsync(fd);
91 #elif defined(_WIN32)
92 res= my_win_fsync(fd);
93 #else
94 #error Cannot find a way to sync a file, durability in danger
95 res= 0; /* No sync (strange OS) */
96 #endif
97 } while (res == -1 && errno == EINTR);
98
99 if (res)
100 {
101 int er= errno;
102 set_my_errno(er);
103 if (!er)
104 set_my_errno(-1); /* Unknown error */
105 if (after_sync_wait)
106 (*after_sync_wait)();
107 if ((my_flags & MY_IGNORE_BADFD) &&
108 (er == EBADF || er == EINVAL || er == EROFS
109 #ifdef __APPLE__
110 || er == ENOTSUP
111 #endif
112 ))
113 {
114 DBUG_PRINT("info", ("ignoring errno %d", er));
115 res= 0;
116 }
117 else if (my_flags & MY_WME)
118 {
119 char errbuf[MYSYS_STRERROR_SIZE];
120 my_error(EE_SYNC, MYF(0), my_filename(fd),
121 my_errno(), my_strerror(errbuf, sizeof(errbuf), my_errno()));
122 }
123 }
124 else
125 {
126 if (after_sync_wait)
127 (*after_sync_wait)();
128 }
129 DBUG_RETURN(res);
130 } /* my_sync */
131
132
133 /*
134 Force directory information to disk.
135
136 SYNOPSIS
137 my_sync_dir()
138 dir_name the name of the directory
139 my_flags flags (MY_WME etc)
140
141 RETURN
142 0 if ok, !=0 if error
143 */
144
145 #ifdef __linux__
146 static const char cur_dir_name[]= {FN_CURLIB, 0};
147 #endif
148
my_sync_dir(const char * dir_name MY_ATTRIBUTE ((unused)),myf my_flags MY_ATTRIBUTE ((unused)))149 int my_sync_dir(const char *dir_name MY_ATTRIBUTE((unused)),
150 myf my_flags MY_ATTRIBUTE((unused)))
151 {
152 /*
153 Only Linux is known to need an explicit sync of the directory to make sure a
154 file creation/deletion/renaming in(from,to) this directory durable.
155 */
156 #ifdef __linux__
157 File dir_fd;
158 int res= 0;
159 const char *correct_dir_name;
160 DBUG_ENTER("my_sync_dir");
161 DBUG_PRINT("my",("Dir: '%s' my_flags: %d", dir_name, my_flags));
162 /* Sometimes the path does not contain an explicit directory */
163 correct_dir_name= (dir_name[0] == 0) ? cur_dir_name : dir_name;
164 /*
165 Syncing a dir may give EINVAL on tmpfs on Linux, which is ok.
166 EIO on the other hand is very important. Hence MY_IGNORE_BADFD.
167 */
168 if ((dir_fd= my_open(correct_dir_name, O_RDONLY, MYF(my_flags))) >= 0)
169 {
170 if (my_sync(dir_fd, MYF(my_flags | MY_IGNORE_BADFD)))
171 res= 2;
172 if (my_close(dir_fd, MYF(my_flags)))
173 res= 3;
174 }
175 else
176 res= 1;
177 DBUG_RETURN(res);
178 #else
179 return 0;
180 #endif
181 }
182
183
184 /*
185 Force directory information to disk.
186
187 SYNOPSIS
188 my_sync_dir_by_file()
189 file_name the name of a file in the directory
190 my_flags flags (MY_WME etc)
191
192 RETURN
193 0 if ok, !=0 if error
194 */
195
my_sync_dir_by_file(const char * file_name MY_ATTRIBUTE ((unused)),myf my_flags MY_ATTRIBUTE ((unused)))196 int my_sync_dir_by_file(const char *file_name MY_ATTRIBUTE((unused)),
197 myf my_flags MY_ATTRIBUTE((unused)))
198 {
199 #ifdef __linux__
200 char dir_name[FN_REFLEN];
201 size_t dir_name_length;
202 dirname_part(dir_name, file_name, &dir_name_length);
203 return my_sync_dir(dir_name, my_flags);
204 #else
205 return 0;
206 #endif
207 }
208