1 /*
2 Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <ndb_global.h>
26
27 #include "Win32AsyncFile.hpp"
28
29 #include <signaldata/FsRef.hpp>
30 #include <signaldata/FsOpenReq.hpp>
31 #include <signaldata/FsReadWriteReq.hpp>
32
33 #define JAM_FILE_ID 399
34
35
Win32AsyncFile(SimulatedBlock & fs)36 Win32AsyncFile::Win32AsyncFile(SimulatedBlock& fs) :
37 AsyncFile(fs),hFile(INVALID_HANDLE_VALUE)
38 {
39 }
40
~Win32AsyncFile()41 Win32AsyncFile::~Win32AsyncFile()
42 {
43
44 }
45
46 int
init()47 Win32AsyncFile::init()
48 {
49 return 0;
50 }
51
openReq(Request * request)52 void Win32AsyncFile::openReq(Request* request)
53 {
54 m_auto_sync_freq = 0;
55 m_write_wo_sync = 0;
56 m_open_flags = request->par.open.flags;
57
58 // for open.flags, see signal FSOPENREQ
59 DWORD dwCreationDisposition;
60 DWORD dwDesiredAccess = 0;
61 DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
62 /**
63 * FIXME:
64 * Previously we had FILE_FLAG_NO_BUFFERING also set here.
65 * This has similar alignment rules to O_DIRECT on 2.4 kernels.
66 * which means we should obey the directio req as we can't do it
67 * everywhere (this seemingly "worked" in 5.0 though), e.g. by default
68 * LCP isn't aligned IO.
69 */
70 DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
71 Uint32 flags = request->par.open.flags;
72
73 // Convert file open flags from Solaris to Windows
74 if ((flags & FsOpenReq::OM_CREATE) && (flags & FsOpenReq::OM_TRUNCATE)){
75 dwCreationDisposition = CREATE_ALWAYS;
76 } else if (flags & FsOpenReq::OM_TRUNCATE){
77 dwCreationDisposition = TRUNCATE_EXISTING;
78 } else if (flags & (FsOpenReq::OM_CREATE|FsOpenReq::OM_CREATE_IF_NONE)){
79 dwCreationDisposition = CREATE_NEW;
80 } else {
81 dwCreationDisposition = OPEN_EXISTING;
82 }
83
84 m_always_sync = false;
85 if (flags & FsOpenReq::OM_SYNC)
86 {
87 m_always_sync = true;
88 }
89
90 switch(flags & 3){
91 case FsOpenReq::OM_READONLY:
92 dwDesiredAccess = GENERIC_READ;
93 break;
94 case FsOpenReq::OM_WRITEONLY:
95 dwDesiredAccess = GENERIC_WRITE;
96 break;
97 case FsOpenReq::OM_READWRITE:
98 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
99 break;
100 default:
101 request->error = 1000;
102 break;
103 return;
104 }
105
106 hFile = CreateFile(theFileName.c_str(), dwDesiredAccess, dwShareMode,
107 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
108
109 if(INVALID_HANDLE_VALUE == hFile) {
110 request->error = GetLastError();
111
112 if((ERROR_FILE_EXISTS == request->error) && (flags & (FsOpenReq::OM_CREATE|FsOpenReq::OM_CREATE_IF_NONE))) {
113 request->error = FsRef::fsErrFileExists;
114 return;
115 }
116
117 if(((ERROR_PATH_NOT_FOUND == request->error) || (ERROR_INVALID_NAME == request->error))
118 && (flags & (FsOpenReq::OM_CREATE|FsOpenReq::OM_CREATE_IF_NONE))) {
119 createDirectories();
120 hFile = CreateFile(theFileName.c_str(), dwDesiredAccess, dwShareMode,
121 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
122
123 if(INVALID_HANDLE_VALUE == hFile)
124 request->error = GetLastError();
125 else
126 request->error = 0;
127 }
128 }
129 else {
130 request->error = 0;
131 }
132
133 if (flags & FsOpenReq::OM_INIT)
134 {
135 LARGE_INTEGER off;
136 off.QuadPart= 0;
137 LARGE_INTEGER sz;
138 sz.QuadPart= request->par.open.file_size;
139 char buf[4096];
140 bzero(buf,sizeof(buf));
141 while(off.QuadPart < sz.QuadPart)
142 {
143 BOOL r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
144 if(r==0)
145 {
146 request->error= GetLastError();
147 return;
148 }
149 DWORD dwWritten;
150 BOOL bWrite= WriteFile(hFile, buf, sizeof(buf), &dwWritten, 0);
151 if(!bWrite || dwWritten!=sizeof(buf))
152 {
153 request->error= GetLastError();
154 }
155 off.QuadPart+=sizeof(buf);
156 }
157 off.QuadPart= 0;
158 BOOL r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
159 if(r==0)
160 {
161 request->error= GetLastError();
162 return;
163 }
164
165 /* Write initial data */
166 SignalT<25> tmp;
167 Signal * signal = (Signal*)(&tmp);
168 bzero(signal, sizeof(tmp));
169 FsReadWriteReq* req = (FsReadWriteReq*)signal->getDataPtrSend();
170 Uint32 index = 0;
171 Uint32 block = refToMain(request->theUserReference);
172 Uint32 instance = refToInstance(request->theUserReference);
173
174 off.QuadPart= 0;
175 sz.QuadPart= request->par.open.file_size;
176 while(off.QuadPart < sz.QuadPart)
177 {
178 req->filePointer = 0; // DATA 0
179 req->userPointer = request->theUserPointer; // DATA 2
180 req->numberOfPages = 1; // DATA 5
181 req->varIndex = index++;
182 req->data.pageData[0] = m_page_ptr.i;
183
184 m_fs.EXECUTE_DIRECT(block, GSN_FSWRITEREQ, signal,
185 FsReadWriteReq::FixedLength + 1,
186 instance // wl4391_todo This EXECUTE_DIRECT is thread safe
187 );
188 Uint32 size = request->par.open.page_size;
189 char* buf = (char*)m_page_ptr.p;
190 DWORD dwWritten;
191 while(size > 0){
192 BOOL bWrite= WriteFile(hFile, buf, size, &dwWritten, 0);
193 if(!bWrite || dwWritten!=size)
194 {
195 request->error= GetLastError();
196 }
197 size -= dwWritten;
198 buf += dwWritten;
199 }
200 if(size != 0)
201 {
202 int err = errno;
203 /* close(theFd);
204 unlink(theFileName.c_str());*/
205 request->error = err;
206 return;
207 }
208 off.QuadPart += request->par.open.page_size;
209 }
210
211 off.QuadPart= 0;
212 r= SetFilePointerEx(hFile, off, NULL, FILE_BEGIN);
213 if(r==0)
214 {
215 request->error= GetLastError();
216 return;
217 }
218 }
219
220 return;
221 }
222
223 int
readBuffer(Request * req,char * buf,size_t size,off_t offset)224 Win32AsyncFile::readBuffer(Request* req, char * buf, size_t size, off_t offset)
225 {
226 req->par.readWrite.pages[0].size = 0;
227
228 while (size > 0) {
229 size_t bytes_read = 0;
230
231 OVERLAPPED ov;
232 bzero(&ov, sizeof(ov));
233
234 LARGE_INTEGER li;
235 li.QuadPart = offset;
236 ov.Offset = li.LowPart;
237 ov.OffsetHigh = li.HighPart;
238
239 DWORD dwBytesRead;
240 BOOL bRead = ReadFile(hFile,
241 buf,
242 (DWORD)size,
243 &dwBytesRead,
244 &ov);
245 if(!bRead){
246 int err = GetLastError();
247 if (err == ERROR_HANDLE_EOF && req->action == Request::readPartial)
248 {
249 return 0;
250 }
251 return err;
252 }
253 bytes_read = dwBytesRead;
254
255 req->par.readWrite.pages[0].size += bytes_read;
256 if(bytes_read == 0){
257 if(req->action == Request::readPartial)
258 {
259 return 0;
260 }
261 DEBUG(ndbout_c("Read underflow %d %d\n %x\n%d %d",
262 size, offset, buf, bytes_read, return_value));
263 return ERR_ReadUnderflow;
264 }
265
266 if(bytes_read != size){
267 DEBUG(ndbout_c("Warning partial read %d != %d",
268 bytes_read, size));
269 }
270
271 buf += bytes_read;
272 size -= bytes_read;
273 offset += (off_t)bytes_read;
274 }
275 return 0;
276 }
277
278 int
writeBuffer(const char * buf,size_t size,off_t offset)279 Win32AsyncFile::writeBuffer(const char * buf, size_t size, off_t offset)
280 {
281 size_t chunk_size = 256 * 1024;
282 size_t bytes_to_write = chunk_size;
283
284 m_write_wo_sync += size;
285
286 while (size > 0) {
287 OVERLAPPED ov;
288 bzero(&ov, sizeof(ov));
289
290 LARGE_INTEGER li;
291 li.QuadPart = offset;
292 ov.Offset = li.LowPart;
293 ov.OffsetHigh = li.HighPart;
294
295 if (size < bytes_to_write){
296 // We are at the last chunk
297 bytes_to_write = size;
298 }
299 size_t bytes_written = 0;
300
301 DWORD dwWritten;
302 BOOL bWrite = WriteFile(hFile, buf, (DWORD)bytes_to_write, &dwWritten, &ov);
303 if(!bWrite) {
304 return GetLastError();
305 }
306 bytes_written = dwWritten;
307 if (bytes_written != bytes_to_write) {
308 DEBUG(ndbout_c("Warning partial write %d != %d", bytes_written, bytes_to_write));
309 }
310
311 buf += bytes_written;
312 size -= bytes_written;
313 offset += (off_t)bytes_written;
314 }
315 return 0;
316 }
317
318 void
closeReq(Request * request)319 Win32AsyncFile::closeReq(Request * request)
320 {
321 if (m_open_flags & (
322 FsOpenReq::OM_WRITEONLY |
323 FsOpenReq::OM_READWRITE |
324 FsOpenReq::OM_APPEND )) {
325 syncReq(request);
326 }
327
328 if(!CloseHandle(hFile)) {
329 request->error = GetLastError();
330 }
331 hFile = INVALID_HANDLE_VALUE;
332 }
333
isOpen()334 bool Win32AsyncFile::isOpen(){
335 return (hFile != INVALID_HANDLE_VALUE);
336 }
337
338
339 void
syncReq(Request * request)340 Win32AsyncFile::syncReq(Request * request)
341 {
342 if ((m_auto_sync_freq && m_write_wo_sync == 0) ||
343 m_always_sync)
344 {
345 return;
346 }
347 if(!FlushFileBuffers(hFile)) {
348 request->error = GetLastError();
349 return;
350 }
351 m_write_wo_sync = 0;
352 }
353
354 void
appendReq(Request * request)355 Win32AsyncFile::appendReq(Request * request){
356
357 const char * buf = request->par.append.buf;
358 Uint32 size = Uint32(request->par.append.size);
359
360 m_write_wo_sync += size;
361
362 DWORD dwWritten = 0;
363 while(size > 0){
364 if(!WriteFile(hFile, buf, size, &dwWritten, 0)){
365 request->error = GetLastError();
366 return ;
367 }
368
369 buf += dwWritten;
370 size -= dwWritten;
371 }
372
373 if((m_auto_sync_freq && m_write_wo_sync > m_auto_sync_freq) ||
374 m_always_sync)
375 {
376 syncReq(request);
377 }
378 }
379
380 void
removeReq(Request * request)381 Win32AsyncFile::removeReq(Request * request)
382 {
383 if(!DeleteFile(theFileName.c_str())) {
384 request->error = GetLastError();
385 }
386 }
387
388 void
rmrfReq(Request * request,const char * src,bool removePath)389 Win32AsyncFile::rmrfReq(Request * request, const char * src, bool removePath){
390 if (!request->par.rmrf.directory)
391 {
392 // Remove file
393 if (!DeleteFile(src))
394 {
395 DWORD dwError = GetLastError();
396 if (dwError != ERROR_FILE_NOT_FOUND)
397 request->error = dwError;
398 }
399 return;
400 }
401
402 char path[PATH_MAX];
403 strcpy(path, src);
404 strcat(path, "\\*");
405
406 WIN32_FIND_DATA ffd;
407 HANDLE hFindFile;
408 loop:
409 hFindFile = FindFirstFile(path, &ffd);
410 if (INVALID_HANDLE_VALUE == hFindFile)
411 {
412 DWORD dwError = GetLastError();
413 if (dwError != ERROR_PATH_NOT_FOUND)
414 request->error = dwError;
415 return;
416 }
417 path[strlen(path) - 1] = 0; // remove '*'
418
419 do {
420 if (0 != strcmp(".", ffd.cFileName) && 0 != strcmp("..", ffd.cFileName))
421 {
422 int len = (int)strlen(path);
423 strcat(path, ffd.cFileName);
424 if(DeleteFile(path) || RemoveDirectory(path))
425 {
426 path[len] = 0;
427 continue;
428 }//if
429
430 FindClose(hFindFile);
431 strcat(path, "\\*");
432 goto loop;
433 }
434 } while(FindNextFile(hFindFile, &ffd));
435
436 FindClose(hFindFile);
437 path[strlen(path)-1] = 0; // remove '\'
438 if (strcmp(src, path) != 0)
439 {
440 char * t = strrchr(path, '\\');
441 t[1] = '*';
442 t[2] = 0;
443 goto loop;
444 }
445
446 if(removePath && !RemoveDirectory(src))
447 request->error = GetLastError();
448 }
449
createDirectories()450 void Win32AsyncFile::createDirectories()
451 {
452 char* tmp;
453 const char * name = theFileName.c_str();
454 const char * base = theFileName.get_base_name();
455 while((tmp = (char *)strstr(base, DIR_SEPARATOR)))
456 {
457 char t = tmp[0];
458 tmp[0] = 0;
459 CreateDirectory(name, 0);
460 tmp[0] = t;
461 base = tmp + sizeof(DIR_SEPARATOR);
462 }
463 }
464