1 /*************************************************************************************************
2 * Filesystem abstraction
3 * Copyright (C) 2009-2012 Mikio Hirabayashi
4 * This file is part of Kyoto Cabinet.
5 * This program is free software: you can redistribute it and/or modify it under the terms of
6 * the GNU General Public License as published by the Free Software Foundation, either version
7 * 3 of the License, or any later version.
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
13 *************************************************************************************************/
14
15
16 #include "kcfile.h"
17 #include "myconf.h"
18
19 namespace kyotocabinet { // common namespace
20
21
22 /**
23 * Constants for implementation.
24 */
25 namespace {
26 const int32_t FILEPERM = 00644; ///< default permission of a new file
27 const int32_t DIRPERM = 00755; ///< default permission of a new directory
28 const int32_t PATHBUFSIZ = 8192; ///< size of the path buffer
29 const int32_t IOBUFSIZ = 16384; ///< size of the IO buffer
30 const int64_t FILEMAXSIZ = INT64MAX - INT32MAX; // maximum size of a file
31 const char* const WALPATHEXT = "wal"; ///< extension of the WAL file
32 const char WALMAGICDATA[] = "KW\n"; ///< magic data of the WAL file
33 const uint8_t WALMSGMAGIC = 0xee; ///< magic data for WAL record
34 }
35
36
37 /**
38 * File internal.
39 */
40 struct FileCore {
41 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
42 Mutex alock; ///< attribute lock
43 TSDKey errmsg; ///< error message
44 ::HANDLE fh; ///< file handle
45 ::HANDLE mh; ///< map view handle
46 char* map; ///< mapped memory
47 int64_t msiz; ///< map size
48 int64_t lsiz; ///< logical size
49 int64_t psiz; ///< physical size
50 std::string path; ///< file path
51 bool recov; ///< flag of recovery
52 uint32_t omode; ///< open mode
53 ::HANDLE walfh; ///< file handle for WAL
54 int64_t walsiz; ///< size of WAL
55 bool tran; ///< whether in transaction
56 bool trhard; ///< whether hard transaction
57 int64_t trbase; ///< base offset of guarded region
58 int64_t trmsiz; ///< minimum size during transaction
59 #else
60 Mutex alock; ///< attribute lock
61 TSDKey errmsg; ///< error message
62 int32_t fd; ///< file descriptor
63 char* map; ///< mapped memory
64 int64_t msiz; ///< map size
65 int64_t lsiz; ///< logical size
66 int64_t psiz; ///< physical size
67 std::string path; ///< file path
68 bool recov; ///< flag of recovery
69 uint32_t omode; ///< open mode
70 int32_t walfd; ///< file descriptor for WAL
71 int64_t walsiz; ///< size of WAL
72 bool tran; ///< whether in transaction
73 bool trhard; ///< whether hard transaction
74 int64_t trbase; ///< base offset of guarded region
75 int64_t trmsiz; ///< minimum size during transaction
76 #endif
77 };
78
79
80 /**
81 * WAL message.
82 */
83 struct WALMessage {
84 int64_t off; ///< offset of the region
85 std::string body; ///< body data
86 };
87
88
89 /**
90 * DirStream internal.
91 */
92 struct DirStreamCore {
93 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
94 Mutex alock; ///< attribute lock
95 ::HANDLE dh; ///< directory handle
96 std::string cur; ///< current file
97 #else
98 Mutex alock; ///< attribute lock
99 ::DIR* dh; ///< directory handle
100 #endif
101 };
102
103
104 /**
105 * Set the error message.
106 * @param core the inner condition.
107 * @param msg the error message.
108 */
109 static void seterrmsg(FileCore* core, const char* msg);
110
111
112 /**
113 * Get the path of the WAL file.
114 * @param path the path of the destination file.
115 * @return the path of the WAL file.
116 */
117 static std::string walpath(const std::string& path);
118
119
120 /**
121 * Write a log message into the WAL file.
122 * @param core the inner condition.
123 * @param off the offset of the destination.
124 * @param size the size of the data region.
125 * @param base the base offset.
126 * @return true on success, or false on failure.
127 */
128 static bool walwrite(FileCore *core, int64_t off, size_t size, int64_t base);
129
130
131 /**
132 * Apply log messages in the WAL file.
133 * @param core the inner condition.
134 * @return true on success, or false on failure.
135 */
136 static bool walapply(FileCore* core);
137
138
139 /**
140 * Write data into a file.
141 * @param fd the file descriptor.
142 * @param off the offset of the destination.
143 * @param buf the pointer to the data region.
144 * @param size the size of the data region.
145 * @return true on success, or false on failure.
146 */
147 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
148 static bool mywrite(::HANDLE fh, int64_t off, const void* buf, size_t size);
149 #else
150 static bool mywrite(int32_t fd, int64_t off, const void* buf, size_t size);
151 #endif
152
153
154 /**
155 * Read data from a file.
156 * @param fd the file descriptor.
157 * @param buf the pointer to the destination region.
158 * @param size the size of the data to be read.
159 * @return true on success, or false on failure.
160 */
161 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
162 static size_t myread(::HANDLE fh, void* buf, size_t size);
163 #else
164 static size_t myread(int32_t fd, void* buf, size_t count);
165 #endif
166
167
168 /**
169 * System call emulation for Win32.
170 */
171 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
172 static int64_t win_pwrite(::HANDLE fh, const void* buf, size_t count, int64_t offset);
173 static int64_t win_pread(::HANDLE fh, void* buf, size_t count, int64_t offset);
174 static int64_t win_write(::HANDLE fh, const void* buf, size_t count);
175 static int64_t win_read(::HANDLE fh, void* buf, size_t count);
176 static int32_t win_ftruncate(::HANDLE fh, int64_t length);
177 #endif
178
179
180 /** Path delimiter character. */
181 const char File::PATHCHR = MYPATHCHR;
182
183
184 /** Path delimiter string. */
185 const char* const File::PATHSTR = MYPATHSTR;
186
187
188 /** Extension delimiter character. */
189 const char File::EXTCHR = MYEXTCHR;
190
191
192 /** Extension delimiter string. */
193 const char* const File::EXTSTR = MYEXTSTR;
194
195
196 /** Current directory string. */
197 const char* const File::CDIRSTR = MYCDIRSTR;
198
199
200 /** Parent directory string. */
201 const char* const File::PDIRSTR = MYPDIRSTR;
202
203
204 /**
205 * Default constructor.
206 */
File()207 File::File() : opq_(NULL) {
208 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
209 _assert_(true);
210 FileCore* core = new FileCore;
211 core->fh = NULL;
212 core->mh = NULL;
213 core->map = NULL;
214 core->msiz = 0;
215 core->lsiz = 0;
216 core->psiz = 0;
217 core->recov = false;
218 core->omode = 0;
219 core->walfh = NULL;
220 core->walsiz = 0;
221 core->tran = false;
222 core->trhard = false;
223 core->trmsiz = 0;
224 opq_ = core;
225 #else
226 _assert_(true);
227 FileCore* core = new FileCore;
228 core->fd = -1;
229 core->map = NULL;
230 core->msiz = 0;
231 core->lsiz = 0;
232 core->psiz = 0;
233 core->recov = false;
234 core->omode = 0;
235 core->walfd = -1;
236 core->walsiz = 0;
237 core->tran = false;
238 core->trhard = false;
239 core->trmsiz = 0;
240 opq_ = core;
241 #endif
242 }
243
244
245 /**
246 * Destructor.
247 */
~File()248 File::~File() {
249 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
250 _assert_(true);
251 FileCore* core = (FileCore*)opq_;
252 if (core->fh) close();
253 delete core;
254 #else
255 _assert_(true);
256 FileCore* core = (FileCore*)opq_;
257 if (core->fd >= 0) close();
258 delete core;
259 #endif
260 }
261
262
263 /**
264 * Get the last happened error information.
265 */
error() const266 const char* File::error() const {
267 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
268 _assert_(true);
269 FileCore* core = (FileCore*)opq_;
270 const char* msg = (const char*)core->errmsg.get();
271 if (!msg) msg = "no error";
272 return msg;
273 #else
274 _assert_(true);
275 FileCore* core = (FileCore*)opq_;
276 const char* msg = (const char*)core->errmsg.get();
277 if (!msg) msg = "no error";
278 return msg;
279 #endif
280 }
281
282
283 /**
284 * Open a file.
285 */
open(const std::string & path,uint32_t mode,int64_t msiz)286 bool File::open(const std::string& path, uint32_t mode, int64_t msiz) {
287 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
288 _assert_(msiz >= 0 && msiz <= FILEMAXSIZ);
289 FileCore* core = (FileCore*)opq_;
290 ::DWORD amode = GENERIC_READ;
291 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
292 ::DWORD cmode = OPEN_EXISTING;
293 if (mode & OWRITER) {
294 amode |= GENERIC_WRITE;
295 if (mode & OCREATE) {
296 cmode = OPEN_ALWAYS;
297 if (mode & OTRUNCATE) cmode = CREATE_ALWAYS;
298 } else {
299 if (mode & OTRUNCATE) cmode = TRUNCATE_EXISTING;
300 }
301 }
302 ::HANDLE fh = ::CreateFile(path.c_str(), amode, smode, NULL, cmode,
303 FILE_ATTRIBUTE_NORMAL, NULL);
304 if (!fh || fh == INVALID_HANDLE_VALUE) {
305 seterrmsg(core, "CreateFile failed");
306 return false;
307 }
308 if (!(mode & ONOLOCK)) {
309 ::DWORD lmode = mode & OWRITER ? LOCKFILE_EXCLUSIVE_LOCK : 0;
310 if (mode & OTRYLOCK) lmode |= LOCKFILE_FAIL_IMMEDIATELY;
311 OVERLAPPED ol;
312 ol.Offset = INT32MAX;
313 ol.OffsetHigh = 0;
314 ol.hEvent = 0;
315 if (!::LockFileEx(fh, lmode, 0, 1, 0, &ol)) {
316 seterrmsg(core, "LockFileEx failed");
317 ::CloseHandle(fh);
318 return false;
319 }
320 }
321 ::LARGE_INTEGER sbuf;
322 if (!::GetFileSizeEx(fh, &sbuf)) {
323 seterrmsg(core, "GetFileSizeEx failed");
324 ::CloseHandle(fh);
325 return false;
326 }
327 bool recov = false;
328 if ((!(mode & OWRITER) || !(mode & OTRUNCATE)) && !(mode & ONOLOCK)) {
329 const std::string& wpath = walpath(path);
330 ::HANDLE walfh = ::CreateFile(wpath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING,
331 FILE_ATTRIBUTE_NORMAL, NULL);
332 if (walfh && walfh != INVALID_HANDLE_VALUE) {
333 recov = true;
334 ::LARGE_INTEGER li;
335 if (::GetFileSizeEx(walfh, &li) && li.QuadPart >= (int64_t)sizeof(WALMAGICDATA)) {
336 char mbuf[sizeof(WALMAGICDATA)];
337 if (myread(walfh, mbuf, sizeof(mbuf)) &&
338 !std::memcmp(mbuf, WALMAGICDATA, sizeof(WALMAGICDATA))) {
339 ::HANDLE ofh = fh;
340 if (!(mode & OWRITER)) ofh = ::CreateFile(wpath.c_str(), GENERIC_WRITE, 0, NULL,
341 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
342 if (ofh && ofh != INVALID_HANDLE_VALUE) {
343 core->fh = ofh;
344 core->walfh = walfh;
345 walapply(core);
346 if (ofh != fh && !::CloseHandle(ofh)) seterrmsg(core, "CloseHandle failed");
347 li.QuadPart = 0;
348 if (win_ftruncate(walfh, 0) != 0) seterrmsg(core, "win_ftruncate failed");
349 core->fh = NULL;
350 core->walfh = NULL;
351 if (!::GetFileSizeEx(fh, &sbuf)) {
352 seterrmsg(core, "GetFileSizeEx failed");
353 ::CloseHandle(fh);
354 return false;
355 }
356 } else {
357 seterrmsg(core, "CreateFile failed");
358 }
359 }
360 }
361 if (!::CloseHandle(walfh)) seterrmsg(core, "CloseHandle failed");
362 ::DeleteFile(wpath.c_str());
363 }
364 }
365 int64_t lsiz = sbuf.QuadPart;
366 int64_t psiz = lsiz;
367 int64_t diff = msiz % PAGESIZ;
368 if (diff > 0) msiz += PAGESIZ - diff;
369 ::DWORD mprot = PAGE_READONLY;
370 ::DWORD vmode = FILE_MAP_READ;
371 if (mode & OWRITER) {
372 mprot = PAGE_READWRITE;
373 vmode = FILE_MAP_WRITE;
374 } else if (msiz > lsiz) {
375 msiz = lsiz;
376 }
377 sbuf.QuadPart = msiz;
378 ::HANDLE mh = NULL;
379 void* map = NULL;
380 if (msiz > 0) {
381 mh = ::CreateFileMapping(fh, NULL, mprot, sbuf.HighPart, sbuf.LowPart, NULL);
382 if (!mh || mh == INVALID_HANDLE_VALUE) {
383 seterrmsg(core, "CreateFileMapping failed");
384 ::CloseHandle(fh);
385 return false;
386 }
387 map = ::MapViewOfFile(mh, vmode, 0, 0, 0);
388 if (!map) {
389 seterrmsg(core, "MapViewOfFile failed");
390 ::CloseHandle(mh);
391 ::CloseHandle(fh);
392 return false;
393 }
394 if (psiz < msiz) psiz = msiz;
395 }
396 core->fh = fh;
397 core->mh = mh;
398 core->map = (char*)map;
399 core->msiz = msiz;
400 core->lsiz = lsiz;
401 core->psiz = psiz;
402 core->recov = recov;
403 core->omode = mode;
404 core->path.append(path);
405 return true;
406 #else
407 _assert_(msiz >= 0 && msiz <= FILEMAXSIZ);
408 FileCore* core = (FileCore*)opq_;
409 int32_t oflags = O_RDONLY;
410 if (mode & OWRITER) {
411 oflags = O_RDWR;
412 if (mode & OCREATE) oflags |= O_CREAT;
413 if (mode & OTRUNCATE) oflags |= O_TRUNC;
414 }
415 int32_t fd = ::open(path.c_str(), oflags, FILEPERM);
416 if (fd < 0) {
417 switch (errno) {
418 case EACCES: seterrmsg(core, "open failed (permission denied)"); break;
419 case EISDIR: seterrmsg(core, "open failed (directory)"); break;
420 case ENOENT: seterrmsg(core, "open failed (file not found)"); break;
421 case ENOTDIR: seterrmsg(core, "open failed (invalid path)"); break;
422 case ENOSPC: seterrmsg(core, "open failed (no space)"); break;
423 default: seterrmsg(core, "open failed"); break;
424 }
425 return false;
426 }
427 if (!(mode & ONOLOCK)) {
428 struct flock flbuf;
429 std::memset(&flbuf, 0, sizeof(flbuf));
430 flbuf.l_type = mode & OWRITER ? F_WRLCK : F_RDLCK;
431 flbuf.l_whence = SEEK_SET;
432 flbuf.l_start = 0;
433 flbuf.l_len = 0;
434 flbuf.l_pid = 0;
435 int32_t cmd = mode & OTRYLOCK ? F_SETLK : F_SETLKW;
436 while (::fcntl(fd, cmd, &flbuf) != 0) {
437 if (errno != EINTR) {
438 seterrmsg(core, "fcntl failed");
439 ::close(fd);
440 return false;
441 }
442 }
443 }
444 struct ::stat sbuf;
445 if (::fstat(fd, &sbuf) != 0) {
446 seterrmsg(core, "fstat failed");
447 ::close(fd);
448 return false;
449 }
450 if (!S_ISREG(sbuf.st_mode)) {
451 seterrmsg(core, "not a regular file");
452 ::close(fd);
453 return false;
454 }
455 bool recov = false;
456 if ((!(mode & OWRITER) || !(mode & OTRUNCATE)) && !(mode & ONOLOCK)) {
457 const std::string& wpath = walpath(path);
458 int32_t walfd = ::open(wpath.c_str(), O_RDWR, FILEPERM);
459 if (walfd >= 0) {
460 struct ::stat wsbuf;
461 if (::fstat(walfd, &wsbuf) == 0 && wsbuf.st_uid == sbuf.st_uid) {
462 recov = true;
463 if (wsbuf.st_size >= (int64_t)sizeof(WALMAGICDATA)) {
464 char mbuf[sizeof(WALMAGICDATA)];
465 if (myread(walfd, mbuf, sizeof(mbuf)) &&
466 !std::memcmp(mbuf, WALMAGICDATA, sizeof(WALMAGICDATA))) {
467 int32_t ofd = mode & OWRITER ? fd : ::open(path.c_str(), O_WRONLY, FILEPERM);
468 if (ofd >= 0) {
469 core->fd = ofd;
470 core->walfd = walfd;
471 walapply(core);
472 if (ofd != fd && ::close(ofd) != 0) seterrmsg(core, "close failed");
473 if (::ftruncate(walfd, 0) != 0) seterrmsg(core, "ftruncate failed");
474 core->fd = -1;
475 core->walfd = -1;
476 if (::fstat(fd, &sbuf) != 0) {
477 seterrmsg(core, "fstat failed");
478 ::close(fd);
479 return false;
480 }
481 } else {
482 seterrmsg(core, "open failed");
483 }
484 }
485 }
486 }
487 if (::close(walfd) != 0) seterrmsg(core, "close failed");
488 if (::unlink(wpath.c_str()) != 0) seterrmsg(core, "unlink failed");
489 }
490 }
491 int64_t lsiz = sbuf.st_size;
492 int64_t psiz = lsiz;
493 int64_t diff = msiz % PAGESIZ;
494 if (diff > 0) msiz += PAGESIZ - diff;
495 int32_t mprot = PROT_READ;
496 if (mode & OWRITER) {
497 mprot |= PROT_WRITE;
498 } else if (msiz > lsiz) {
499 msiz = lsiz;
500 }
501 void* map = NULL;
502 if (msiz > 0) {
503 map = ::mmap(0, msiz, mprot, MAP_SHARED, fd, 0);
504 if (map == MAP_FAILED) {
505 seterrmsg(core, "mmap failed");
506 ::close(fd);
507 return false;
508 }
509 }
510 core->fd = fd;
511 core->map = (char*)map;
512 core->msiz = msiz;
513 core->lsiz = lsiz;
514 core->psiz = psiz;
515 core->recov = recov;
516 core->omode = mode;
517 core->path.append(path);
518 return true;
519 #endif
520 }
521
522
523 /**
524 * Close the file.
525 */
close()526 bool File::close() {
527 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
528 _assert_(true);
529 FileCore* core = (FileCore*)opq_;
530 bool err = false;
531 if (core->tran && !end_transaction(false)) err = true;
532 if (core->walfh) {
533 if (!::CloseHandle(core->walfh)) {
534 seterrmsg(core, "CloseHandle failed");
535 err = true;
536 }
537 const std::string& wpath = walpath(core->path);
538 ::DeleteFile(wpath.c_str());
539 }
540 if (core->msiz > 0) {
541 if (!::UnmapViewOfFile(core->map)) {
542 seterrmsg(core, "UnmapViewOfFile failed");
543 err = true;
544 }
545 if (!::CloseHandle(core->mh)) {
546 seterrmsg(core, "CloseHandle failed");
547 err = true;
548 }
549 }
550 ::LARGE_INTEGER li;
551 if (::GetFileSizeEx(core->fh, &li)) {
552 if ((li.QuadPart != core->lsiz || core->psiz != core->lsiz) &&
553 win_ftruncate(core->fh, core->lsiz) != 0) {
554 seterrmsg(core, "win_ftruncate failed");
555 err = true;
556 }
557 } else {
558 seterrmsg(core, "GetFileSizeEx failed");
559 err = true;
560 }
561 if (!(core->omode & ONOLOCK)) {
562 OVERLAPPED ol;
563 ol.Offset = INT32MAX;
564 ol.OffsetHigh = 0;
565 ol.hEvent = 0;
566 if (!::UnlockFileEx(core->fh, 0, 1, 0, &ol)) {
567 seterrmsg(core, "UnlockFileEx failed");
568 err = true;
569 }
570 }
571 if (!::CloseHandle(core->fh)) {
572 seterrmsg(core, "CloseHandle failed");
573 err = true;
574 }
575 core->fh = NULL;
576 core->mh = NULL;
577 core->map = NULL;
578 core->msiz = 0;
579 core->lsiz = 0;
580 core->psiz = 0;
581 core->path.clear();
582 core->walfh = NULL;
583 core->walsiz = 0;
584 core->tran = false;
585 core->trhard = false;
586 core->trmsiz = 0;
587 return !err;
588 #else
589 _assert_(true);
590 FileCore* core = (FileCore*)opq_;
591 bool err = false;
592 if (core->tran && !end_transaction(false)) err = true;
593 if (core->walfd >= 0) {
594 if (::close(core->walfd) != 0) {
595 seterrmsg(core, "close failed");
596 err = true;
597 }
598 const std::string& wpath = walpath(core->path);
599 struct ::stat sbuf;
600 if (::lstat(wpath.c_str(), &sbuf) == 0 && S_ISREG(sbuf.st_mode) &&
601 ::unlink(wpath.c_str()) != 0) {
602 seterrmsg(core, "unlink failed");
603 err = true;
604 }
605 }
606 if (core->msiz > 0 && ::munmap(core->map, core->msiz) != 0) {
607 seterrmsg(core, "munmap failed");
608 err = true;
609 }
610 if (core->psiz != core->lsiz && ::ftruncate(core->fd, core->lsiz) != 0) {
611 seterrmsg(core, "ftruncate failed");
612 err = true;
613 }
614 if (!(core->omode & ONOLOCK)) {
615 struct flock flbuf;
616 std::memset(&flbuf, 0, sizeof(flbuf));
617 flbuf.l_type = F_UNLCK;
618 flbuf.l_whence = SEEK_SET;
619 flbuf.l_start = 0;
620 flbuf.l_len = 0;
621 flbuf.l_pid = 0;
622 while (::fcntl(core->fd, F_SETLKW, &flbuf) != 0) {
623 if (errno != EINTR) {
624 seterrmsg(core, "fcntl failed");
625 err = true;
626 break;
627 }
628 }
629 }
630 if (::close(core->fd) != 0) {
631 seterrmsg(core, "close failed");
632 err = true;
633 }
634 core->fd = -1;
635 core->map = NULL;
636 core->msiz = 0;
637 core->lsiz = 0;
638 core->psiz = 0;
639 core->path.clear();
640 core->walfd = -1;
641 core->walsiz = 0;
642 core->tran = false;
643 core->trhard = false;
644 core->trmsiz = 0;
645 return !err;
646 #endif
647 }
648
649
650 /**
651 * Write data.
652 */
write(int64_t off,const void * buf,size_t size)653 bool File::write(int64_t off, const void* buf, size_t size) {
654 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
655 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
656 if (size < 1) return true;
657 FileCore* core = (FileCore*)opq_;
658 if (core->tran && !walwrite(core, off, size, core->trbase)) return false;
659 int64_t end = off + size;
660 core->alock.lock();
661 if (end <= core->msiz) {
662 if (end > core->psiz) {
663 int64_t psiz = end + core->psiz / 2;
664 int64_t diff = psiz % PAGESIZ;
665 if (diff > 0) psiz += PAGESIZ - diff;
666 if (psiz > core->msiz) psiz = core->msiz;
667 if (win_ftruncate(core->fh, psiz) != 0) {
668 seterrmsg(core, "win_ftruncate failed");
669 core->alock.unlock();
670 return false;
671 }
672 core->psiz = psiz;
673 }
674 if (end > core->lsiz) core->lsiz = end;
675 core->alock.unlock();
676 std::memcpy(core->map + off, buf, size);
677 return true;
678 }
679 if (off < core->msiz) {
680 if (end > core->psiz) {
681 if (win_ftruncate(core->fh, end) != 0) {
682 seterrmsg(core, "win_ftruncate failed");
683 core->alock.unlock();
684 return false;
685 }
686 core->psiz = end;
687 }
688 size_t hsiz = core->msiz - off;
689 std::memcpy(core->map + off, buf, hsiz);
690 off += hsiz;
691 buf = (char*)buf + hsiz;
692 size -= hsiz;
693 }
694 if (end > core->lsiz) core->lsiz = end;
695 if (end > core->psiz) {
696 if (core->psiz < core->msiz && win_ftruncate(core->fh, core->msiz) != 0) {
697 seterrmsg(core, "win_ftruncate failed");
698 core->alock.unlock();
699 return false;
700 }
701 core->psiz = end;
702 }
703 core->alock.unlock();
704 if (!mywrite(core->fh, off, buf, size)) {
705 seterrmsg(core, "mywrite failed");
706 return false;
707 }
708 return true;
709 #else
710 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
711 if (size < 1) return true;
712 FileCore* core = (FileCore*)opq_;
713 if (core->tran && !walwrite(core, off, size, core->trbase)) return false;
714 int64_t end = off + size;
715 core->alock.lock();
716 if (end <= core->msiz) {
717 if (end > core->psiz) {
718 int64_t psiz = end + core->psiz / 2;
719 int64_t diff = psiz % PAGESIZ;
720 if (diff > 0) psiz += PAGESIZ - diff;
721 if (psiz > core->msiz) psiz = core->msiz;
722 if (::ftruncate(core->fd, psiz) != 0) {
723 seterrmsg(core, "ftruncate failed");
724 core->alock.unlock();
725 return false;
726 }
727 core->psiz = psiz;
728 }
729 if (end > core->lsiz) core->lsiz = end;
730 core->alock.unlock();
731 std::memcpy(core->map + off, buf, size);
732 return true;
733 }
734 if (off < core->msiz) {
735 if (end > core->psiz) {
736 if (::ftruncate(core->fd, end) != 0) {
737 seterrmsg(core, "ftruncate failed");
738 core->alock.unlock();
739 return false;
740 }
741 core->psiz = end;
742 }
743 size_t hsiz = core->msiz - off;
744 std::memcpy(core->map + off, buf, hsiz);
745 off += hsiz;
746 buf = (char*)buf + hsiz;
747 size -= hsiz;
748 }
749 if (end > core->lsiz) core->lsiz = end;
750 if (end > core->psiz) {
751 if (core->psiz < core->msiz && ::ftruncate(core->fd, core->msiz) != 0) {
752 seterrmsg(core, "ftruncate failed");
753 core->alock.unlock();
754 return false;
755 }
756 core->psiz = end;
757 }
758 core->alock.unlock();
759 if (!mywrite(core->fd, off, buf, size)) {
760 seterrmsg(core, "mywrite failed");
761 return false;
762 }
763 return true;
764 #endif
765 }
766
767
768 /**
769 * Write data with assuring the region does not spill from the file size.
770 */
write_fast(int64_t off,const void * buf,size_t size)771 bool File::write_fast(int64_t off, const void* buf, size_t size) {
772 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
773 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
774 FileCore* core = (FileCore*)opq_;
775 if (core->tran && !walwrite(core, off, size, core->trbase)) return false;
776 int64_t end = off + size;
777 if (end <= core->msiz) {
778 std::memcpy(core->map + off, buf, size);
779 return true;
780 }
781 if (off < core->msiz) {
782 size_t hsiz = core->msiz - off;
783 std::memcpy(core->map + off, buf, hsiz);
784 off += hsiz;
785 buf = (char*)buf + hsiz;
786 size -= hsiz;
787 }
788 if (!mywrite(core->fh, off, buf, size)) {
789 seterrmsg(core, "mywrite failed");
790 return false;
791 }
792 return true;
793 #else
794 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
795 FileCore* core = (FileCore*)opq_;
796 if (core->tran && !walwrite(core, off, size, core->trbase)) return false;
797 int64_t end = off + size;
798 if (end <= core->msiz) {
799 std::memcpy(core->map + off, buf, size);
800 return true;
801 }
802 if (off < core->msiz) {
803 size_t hsiz = core->msiz - off;
804 std::memcpy(core->map + off, buf, hsiz);
805 off += hsiz;
806 buf = (char*)buf + hsiz;
807 size -= hsiz;
808 }
809 if (!mywrite(core->fd, off, buf, size)) {
810 seterrmsg(core, "mywrite failed");
811 return false;
812 }
813 return true;
814 #endif
815 }
816
817
818 /**
819 * Write data at the end of the file.
820 */
append(const void * buf,size_t size)821 bool File::append(const void* buf, size_t size) {
822 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
823 _assert_(buf && size <= MEMMAXSIZ);
824 if (size < 1) return true;
825 FileCore* core = (FileCore*)opq_;
826 core->alock.lock();
827 int64_t off = core->lsiz;
828 int64_t end = off + size;
829 if (end <= core->msiz) {
830 if (end > core->psiz) {
831 int64_t psiz = end + core->psiz / 2;
832 int64_t diff = psiz % PAGESIZ;
833 if (diff > 0) psiz += PAGESIZ - diff;
834 if (psiz > core->msiz) psiz = core->msiz;
835 if (win_ftruncate(core->fh, psiz) != 0) {
836 seterrmsg(core, "win_ftruncate failed");
837 core->alock.unlock();
838 return false;
839 }
840 core->psiz = psiz;
841 }
842 core->lsiz = end;
843 core->alock.unlock();
844 std::memcpy(core->map + off, buf, size);
845 return true;
846 }
847 if (off < core->msiz) {
848 if (end > core->psiz) {
849 if (win_ftruncate(core->fh, end) != 0) {
850 seterrmsg(core, "win_ftruncate failed");
851 core->alock.unlock();
852 return false;
853 }
854 core->psiz = end;
855 }
856 size_t hsiz = core->msiz - off;
857 std::memcpy(core->map + off, buf, hsiz);
858 off += hsiz;
859 buf = (char*)buf + hsiz;
860 size -= hsiz;
861 }
862 core->lsiz = end;
863 core->psiz = end;
864 core->alock.unlock();
865 while (true) {
866 int64_t wb = win_pwrite(core->fh, buf, size, off);
867 if (wb >= (int64_t)size) {
868 return true;
869 } else if (wb > 0) {
870 buf = (char*)buf + wb;
871 size -= wb;
872 off += wb;
873 } else if (wb == -1) {
874 seterrmsg(core, "win_pwrite failed");
875 return false;
876 } else if (size > 0) {
877 seterrmsg(core, "win_pwrite failed");
878 return false;
879 }
880 }
881 return true;
882 #else
883 _assert_(buf && size <= MEMMAXSIZ);
884 if (size < 1) return true;
885 FileCore* core = (FileCore*)opq_;
886 core->alock.lock();
887 int64_t off = core->lsiz;
888 int64_t end = off + size;
889 if (end <= core->msiz) {
890 if (end > core->psiz) {
891 int64_t psiz = end + core->psiz / 2;
892 int64_t diff = psiz % PAGESIZ;
893 if (diff > 0) psiz += PAGESIZ - diff;
894 if (psiz > core->msiz) psiz = core->msiz;
895 if (::ftruncate(core->fd, psiz) != 0) {
896 seterrmsg(core, "ftruncate failed");
897 core->alock.unlock();
898 return false;
899 }
900 core->psiz = psiz;
901 }
902 core->lsiz = end;
903 core->alock.unlock();
904 std::memcpy(core->map + off, buf, size);
905 return true;
906 }
907 if (off < core->msiz) {
908 if (end > core->psiz) {
909 if (::ftruncate(core->fd, end) != 0) {
910 seterrmsg(core, "ftruncate failed");
911 core->alock.unlock();
912 return false;
913 }
914 core->psiz = end;
915 }
916 size_t hsiz = core->msiz - off;
917 std::memcpy(core->map + off, buf, hsiz);
918 off += hsiz;
919 buf = (char*)buf + hsiz;
920 size -= hsiz;
921 }
922 core->lsiz = end;
923 core->psiz = end;
924 core->alock.unlock();
925 while (true) {
926 ssize_t wb = ::pwrite(core->fd, buf, size, off);
927 if (wb >= (ssize_t)size) {
928 return true;
929 } else if (wb > 0) {
930 buf = (char*)buf + wb;
931 size -= wb;
932 off += wb;
933 } else if (wb == -1) {
934 if (errno != EINTR) {
935 seterrmsg(core, "pwrite failed");
936 return false;
937 }
938 } else if (size > 0) {
939 seterrmsg(core, "pwrite failed");
940 return false;
941 }
942 }
943 return true;
944 #endif
945 }
946
947
948 /**
949 * Read data.
950 */
read(int64_t off,void * buf,size_t size)951 bool File::read(int64_t off, void* buf, size_t size) {
952 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
953 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
954 if (size < 1) return true;
955 FileCore* core = (FileCore*)opq_;
956 int64_t end = off + size;
957 core->alock.lock();
958 if (end > core->lsiz) {
959 seterrmsg(core, "out of bounds");
960 core->alock.unlock();
961 return false;
962 }
963 core->alock.unlock();
964 if (end <= core->msiz) {
965 std::memcpy(buf, core->map + off, size);
966 return true;
967 }
968 if (off < core->msiz) {
969 int64_t hsiz = core->msiz - off;
970 std::memcpy(buf, core->map + off, hsiz);
971 off += hsiz;
972 buf = (char*)buf + hsiz;
973 size -= hsiz;
974 }
975 while (true) {
976 int64_t rb = win_pread(core->fh, buf, size, off);
977 if (rb >= (int64_t)size) {
978 break;
979 } else if (rb > 0) {
980 buf = (char*)buf + rb;
981 size -= rb;
982 off += rb;
983 } else if (rb == -1) {
984 seterrmsg(core, "win_pread failed");
985 return false;
986 } else if (size > 0) {
987 Thread::yield();
988 }
989 }
990 return true;
991 #else
992 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
993 if (size < 1) return true;
994 FileCore* core = (FileCore*)opq_;
995 int64_t end = off + size;
996 core->alock.lock();
997 if (end > core->lsiz) {
998 seterrmsg(core, "out of bounds");
999 core->alock.unlock();
1000 return false;
1001 }
1002 core->alock.unlock();
1003 if (end <= core->msiz) {
1004 std::memcpy(buf, core->map + off, size);
1005 return true;
1006 }
1007 if (off < core->msiz) {
1008 int64_t hsiz = core->msiz - off;
1009 std::memcpy(buf, core->map + off, hsiz);
1010 off += hsiz;
1011 buf = (char*)buf + hsiz;
1012 size -= hsiz;
1013 }
1014 while (true) {
1015 ssize_t rb = ::pread(core->fd, buf, size, off);
1016 if (rb >= (ssize_t)size) {
1017 break;
1018 } else if (rb > 0) {
1019 buf = (char*)buf + rb;
1020 size -= rb;
1021 off += rb;
1022 } else if (rb == -1) {
1023 if (errno != EINTR) {
1024 seterrmsg(core, "pread failed");
1025 return false;
1026 }
1027 } else if (size > 0) {
1028 Thread::yield();
1029 }
1030 }
1031 return true;
1032 #endif
1033 }
1034
1035
1036 /**
1037 * Read data with assuring the region does not spill from the file size.
1038 */
read_fast(int64_t off,void * buf,size_t size)1039 bool File::read_fast(int64_t off, void* buf, size_t size) {
1040 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1041 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
1042 FileCore* core = (FileCore*)opq_;
1043 int64_t end = off + size;
1044 if (end <= core->msiz) {
1045 std::memcpy(buf, core->map + off, size);
1046 return true;
1047 }
1048 if (off < core->msiz) {
1049 int64_t hsiz = core->msiz - off;
1050 std::memcpy(buf, core->map + off, hsiz);
1051 off += hsiz;
1052 buf = (char*)buf + hsiz;
1053 size -= hsiz;
1054 }
1055 while (true) {
1056 int64_t rb = win_pread(core->fh, buf, size, off);
1057 if (rb >= (int64_t)size) {
1058 break;
1059 } else if (rb > 0) {
1060 buf = (char*)buf + rb;
1061 size -= rb;
1062 off += rb;
1063 Thread::yield();
1064 } else if (rb == -1) {
1065 seterrmsg(core, "win_pread failed");
1066 return false;
1067 } else if (size > 0) {
1068 if (end > core->lsiz) {
1069 seterrmsg(core, "out of bounds");
1070 return false;
1071 }
1072 Thread::yield();
1073 }
1074 }
1075 return true;
1076 #else
1077 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
1078 FileCore* core = (FileCore*)opq_;
1079 int64_t end = off + size;
1080 if (end <= core->msiz) {
1081 std::memcpy(buf, core->map + off, size);
1082 return true;
1083 }
1084 if (off < core->msiz) {
1085 int64_t hsiz = core->msiz - off;
1086 std::memcpy(buf, core->map + off, hsiz);
1087 off += hsiz;
1088 buf = (char*)buf + hsiz;
1089 size -= hsiz;
1090 }
1091 while (true) {
1092 ssize_t rb = ::pread(core->fd, buf, size, off);
1093 if (rb >= (ssize_t)size) {
1094 break;
1095 } else if (rb > 0) {
1096 buf = (char*)buf + rb;
1097 size -= rb;
1098 off += rb;
1099 Thread::yield();
1100 } else if (rb == -1) {
1101 if (errno != EINTR) {
1102 seterrmsg(core, "pread failed");
1103 return false;
1104 }
1105 } else if (size > 0) {
1106 if (end > core->lsiz) {
1107 seterrmsg(core, "out of bounds");
1108 return false;
1109 }
1110 Thread::yield();
1111 }
1112 }
1113 return true;
1114 #endif
1115 }
1116
1117
1118 /**
1119 * Truncate the file.
1120 */
truncate(int64_t size)1121 bool File::truncate(int64_t size) {
1122 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1123 _assert_(size >= 0 && size <= FILEMAXSIZ);
1124 FileCore* core = (FileCore*)opq_;
1125 if (core->tran && size < core->trmsiz) {
1126 if (!walwrite(core, size, core->trmsiz - size, core->trbase)) return false;
1127 core->trmsiz = size;
1128 }
1129 bool err = false;
1130 core->alock.lock();
1131 if (core->msiz > 0) {
1132 if (!::UnmapViewOfFile(core->map)) {
1133 seterrmsg(core, "UnmapViewOfFile failed");
1134 err = true;
1135 }
1136 if (!::CloseHandle(core->mh)) {
1137 seterrmsg(core, "CloseHandle failed");
1138 err = true;
1139 }
1140 }
1141 if (win_ftruncate(core->fh, size) != 0) {
1142 seterrmsg(core, "win_ftruncate failed");
1143 err = true;
1144 }
1145 if (core->msiz) {
1146 ::LARGE_INTEGER li;
1147 li.QuadPart = core->msiz;
1148 ::HANDLE mh = ::CreateFileMapping(core->fh, NULL, PAGE_READWRITE,
1149 li.HighPart, li.LowPart, NULL);
1150 if (mh && mh != INVALID_HANDLE_VALUE) {
1151 void* map = ::MapViewOfFile(mh, FILE_MAP_WRITE, 0, 0, 0);
1152 if (map) {
1153 core->mh = mh;
1154 core->map = (char*)map;
1155 } else {
1156 seterrmsg(core, "MapViewOfFile failed");
1157 ::CloseHandle(mh);
1158 core->mh = NULL;
1159 core->map = NULL;
1160 core->msiz = 0;
1161 err = true;
1162 }
1163 } else {
1164 seterrmsg(core, "CreateFileMapping failed");
1165 core->mh = NULL;
1166 core->map = NULL;
1167 core->msiz = 0;
1168 err = true;
1169 }
1170 }
1171 core->lsiz = size;
1172 core->psiz = size;
1173 core->alock.unlock();
1174 return !err;
1175 #else
1176 _assert_(size >= 0 && size <= FILEMAXSIZ);
1177 FileCore* core = (FileCore*)opq_;
1178 if (core->tran && size < core->trmsiz) {
1179 if (!walwrite(core, size, core->trmsiz - size, core->trbase)) return false;
1180 core->trmsiz = size;
1181 }
1182 bool err = false;
1183 core->alock.lock();
1184 if (::ftruncate(core->fd, size) != 0) {
1185 seterrmsg(core, "ftruncate failed");
1186 err = true;
1187 }
1188 core->lsiz = size;
1189 core->psiz = size;
1190 core->alock.unlock();
1191 return !err;
1192 #endif
1193 }
1194
1195
1196 /**
1197 * Synchronize updated contents with the file and the device.
1198 */
synchronize(bool hard)1199 bool File::synchronize(bool hard) {
1200 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1201 _assert_(true);
1202 FileCore* core = (FileCore*)opq_;
1203 bool err = false;
1204 core->alock.lock();
1205 if (hard && core->msiz > 0) {
1206 int64_t msiz = core->msiz;
1207 if (msiz > core->psiz) msiz = core->psiz;
1208 if (msiz > 0 && !::FlushViewOfFile(core->map, msiz)) {
1209 seterrmsg(core, "FlushViewOfFile failed");
1210 err = true;
1211 }
1212 }
1213 if (win_ftruncate(core->fh, core->lsiz) != 0) {
1214 seterrmsg(core, "win_ftruncate failed");
1215 err = true;
1216 }
1217 if (core->psiz > core->lsiz) core->psiz = core->lsiz;
1218 if (hard && !::FlushFileBuffers(core->fh)) {
1219 seterrmsg(core, "FlushFileBuffers failed");
1220 err = true;
1221 }
1222 core->alock.unlock();
1223 return !err;
1224 #else
1225 _assert_(true);
1226 FileCore* core = (FileCore*)opq_;
1227 bool err = false;
1228 core->alock.lock();
1229 if (hard && core->msiz > 0) {
1230 int64_t msiz = core->msiz;
1231 if (msiz > core->psiz) msiz = core->psiz;
1232 if (msiz > 0 && ::msync(core->map, msiz, MS_SYNC) != 0) {
1233 seterrmsg(core, "msync failed");
1234 err = true;
1235 }
1236 }
1237 if (::ftruncate(core->fd, core->lsiz) != 0) {
1238 seterrmsg(core, "ftruncate failed");
1239 err = true;
1240 }
1241 if (core->psiz > core->lsiz) core->psiz = core->lsiz;
1242 if (hard && ::fsync(core->fd) != 0) {
1243 seterrmsg(core, "fsync failed");
1244 err = true;
1245 }
1246 core->alock.unlock();
1247 return !err;
1248 #endif
1249 }
1250
1251
1252 /**
1253 * Refresh the internal state for update by others.
1254 */
refresh()1255 bool File::refresh() {
1256 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1257 _assert_(true);
1258 FileCore* core = (FileCore*)opq_;
1259 ::LARGE_INTEGER sbuf;
1260 if (!::GetFileSizeEx(core->fh, &sbuf)) {
1261 seterrmsg(core, "GetFileSizeEx failed");
1262 return false;
1263 }
1264 core->lsiz = sbuf.QuadPart;
1265 core->psiz = sbuf.QuadPart;
1266 return true;
1267 #else
1268 _assert_(true);
1269 FileCore* core = (FileCore*)opq_;
1270 struct ::stat sbuf;
1271 if (::fstat(core->fd, &sbuf) != 0) {
1272 seterrmsg(core, "fstat failed");
1273 return false;
1274 }
1275 core->lsiz = sbuf.st_size;
1276 core->psiz = sbuf.st_size;
1277 bool err = false;
1278 int64_t msiz = core->msiz;
1279 if (msiz > core->psiz) msiz = core->psiz;
1280 if (msiz > 0 && ::msync(core->map, msiz, MS_INVALIDATE) != 0) {
1281 seterrmsg(core, "msync failed");
1282 err = true;
1283 }
1284 return !err;
1285 #endif
1286 }
1287
1288
1289 /**
1290 * Begin transaction.
1291 */
begin_transaction(bool hard,int64_t off)1292 bool File::begin_transaction(bool hard, int64_t off) {
1293 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1294 _assert_(off >= 0 && off <= FILEMAXSIZ);
1295 FileCore* core = (FileCore*)opq_;
1296 core->alock.lock();
1297 if (!core->walfh) {
1298 const std::string& wpath = walpath(core->path);
1299 ::DWORD amode = GENERIC_READ | GENERIC_WRITE;
1300 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1301 ::HANDLE fh = ::CreateFile(wpath.c_str(), amode, smode, NULL, CREATE_ALWAYS,
1302 FILE_ATTRIBUTE_NORMAL, NULL);
1303 if (!fh || fh == INVALID_HANDLE_VALUE) {
1304 seterrmsg(core, "CreateFile failed");
1305 core->alock.unlock();
1306 return false;
1307 }
1308 if (hard && !::FlushFileBuffers(fh)) {
1309 seterrmsg(core, "FlushFileBuffers failed");
1310 ::CloseHandle(fh);
1311 core->alock.unlock();
1312 return false;
1313 }
1314 core->walfh = fh;
1315 }
1316 char wbuf[NUMBUFSIZ];
1317 char* wp = wbuf;
1318 std::memcpy(wp, WALMAGICDATA, sizeof(WALMAGICDATA));
1319 wp += sizeof(WALMAGICDATA);
1320 int64_t num = hton64(core->lsiz);
1321 std::memcpy(wp, &num, sizeof(num));
1322 wp += sizeof(num);
1323 int64_t wsiz = wp - wbuf;
1324 if (!mywrite(core->walfh, 0, wbuf, wsiz)) {
1325 seterrmsg(core, "mywrite failed");
1326 core->alock.unlock();
1327 return false;
1328 }
1329 core->walsiz = wsiz;
1330 core->tran = true;
1331 core->trhard = hard;
1332 core->trbase = off;
1333 core->trmsiz = core->lsiz;
1334 core->alock.unlock();
1335 return true;
1336 #else
1337 _assert_(off >= 0 && off <= FILEMAXSIZ);
1338 FileCore* core = (FileCore*)opq_;
1339 core->alock.lock();
1340 if (core->walfd < 0) {
1341 const std::string& wpath = walpath(core->path);
1342 int32_t fd = ::open(wpath.c_str(), O_RDWR | O_CREAT | O_TRUNC, FILEPERM);
1343 if (fd < 0) {
1344 switch (errno) {
1345 case EACCES: seterrmsg(core, "open failed (permission denied)"); break;
1346 case ENOENT: seterrmsg(core, "open failed (file not found)"); break;
1347 case ENOTDIR: seterrmsg(core, "open failed (invalid path)"); break;
1348 default: seterrmsg(core, "open failed"); break;
1349 }
1350 core->alock.unlock();
1351 return false;
1352 }
1353 core->walfd = fd;
1354 }
1355 char wbuf[NUMBUFSIZ];
1356 char* wp = wbuf;
1357 std::memcpy(wp, WALMAGICDATA, sizeof(WALMAGICDATA));
1358 wp += sizeof(WALMAGICDATA);
1359 int64_t num = hton64(core->lsiz);
1360 std::memcpy(wp, &num, sizeof(num));
1361 wp += sizeof(num);
1362 int64_t wsiz = wp - wbuf;
1363 if (!mywrite(core->walfd, 0, wbuf, wsiz)) {
1364 seterrmsg(core, "mywrite failed");
1365 core->alock.unlock();
1366 return false;
1367 }
1368 core->walsiz = wsiz;
1369 core->tran = true;
1370 core->trhard = hard;
1371 core->trbase = off;
1372 core->trmsiz = core->lsiz;
1373 core->alock.unlock();
1374 return true;
1375 #endif
1376 }
1377
1378
1379 /**
1380 * Commit transaction.
1381 */
end_transaction(bool commit)1382 bool File::end_transaction(bool commit) {
1383 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1384 _assert_(true);
1385 FileCore* core = (FileCore*)opq_;
1386 bool err = false;
1387 core->alock.lock();
1388 if (!commit && !walapply(core)) err = true;
1389 if (!err) {
1390 if (core->walsiz <= IOBUFSIZ) {
1391 char mbuf[IOBUFSIZ];
1392 std::memset(mbuf, 0, core->walsiz);
1393 if (!mywrite(core->walfh, 0, mbuf, core->walsiz)) {
1394 seterrmsg(core, "mywrite failed");
1395 err = true;
1396 }
1397 } else {
1398 if (win_ftruncate(core->walfh, 0) != 0) {
1399 seterrmsg(core, "win_ftruncate failed");
1400 err = true;
1401 }
1402 }
1403 }
1404 if (core->trhard) {
1405 int64_t msiz = core->msiz;
1406 if (msiz > core->psiz) msiz = core->psiz;
1407 if (msiz > 0 && !::FlushViewOfFile(core->map, msiz)) {
1408 seterrmsg(core, "FlushViewOfFile failed");
1409 err = true;
1410 }
1411 if (!::FlushFileBuffers(core->fh)) {
1412 seterrmsg(core, "FlushFileBuffers failed");
1413 err = true;
1414 }
1415 if (!::FlushFileBuffers(core->walfh)) {
1416 seterrmsg(core, "FlushFileBuffers failed");
1417 err = true;
1418 }
1419 }
1420 core->tran = false;
1421 core->alock.unlock();
1422 return !err;
1423 #else
1424 _assert_(true);
1425 FileCore* core = (FileCore*)opq_;
1426 bool err = false;
1427 core->alock.lock();
1428 if (!commit && !walapply(core)) err = true;
1429 if (!err) {
1430 if (core->walsiz <= IOBUFSIZ) {
1431 char mbuf[IOBUFSIZ];
1432 std::memset(mbuf, 0, core->walsiz);
1433 if (!mywrite(core->walfd, 0, mbuf, core->walsiz)) {
1434 seterrmsg(core, "mywrite failed");
1435 err = true;
1436 }
1437 } else {
1438 if (::ftruncate(core->walfd, 0) != 0) {
1439 seterrmsg(core, "ftruncate failed");
1440 err = true;
1441 }
1442 }
1443 }
1444 if (core->trhard) {
1445 int64_t msiz = core->msiz;
1446 if (msiz > core->psiz) msiz = core->psiz;
1447 if (msiz > 0 && ::msync(core->map, msiz, MS_SYNC) != 0) {
1448 seterrmsg(core, "msync failed");
1449 err = true;
1450 }
1451 if (::fsync(core->fd) != 0) {
1452 seterrmsg(core, "fsync failed");
1453 err = true;
1454 }
1455 if (::fsync(core->walfd) != 0) {
1456 seterrmsg(core, "fsync failed");
1457 err = true;
1458 }
1459 }
1460 core->tran = false;
1461 core->alock.unlock();
1462 return !err;
1463 #endif
1464 }
1465
1466
1467 /**
1468 * Write a WAL message of transaction explicitly.
1469 */
write_transaction(int64_t off,size_t size)1470 bool File::write_transaction(int64_t off, size_t size) {
1471 _assert_(off >= 0 && off <= FILEMAXSIZ && size <= MEMMAXSIZ);
1472 FileCore* core = (FileCore*)opq_;
1473 return walwrite(core, off, size, 0);
1474 }
1475
1476
1477 /**
1478 * Get the size of the file.
1479 */
size() const1480 int64_t File::size() const {
1481 _assert_(true);
1482 FileCore* core = (FileCore*)opq_;
1483 return core->lsiz;
1484 }
1485
1486
1487 /**
1488 * Get the path of the file.
1489 */
path() const1490 std::string File::path() const {
1491 _assert_(true);
1492 FileCore* core = (FileCore*)opq_;
1493 return core->path;
1494 }
1495
1496
1497 /**
1498 * Check whether the file was recovered or not.
1499 */
recovered() const1500 bool File::recovered() const {
1501 _assert_(true);
1502 FileCore* core = (FileCore*)opq_;
1503 return core->recov;
1504 }
1505
1506
1507 /**
1508 * Read the whole data from a file.
1509 */
read_file(const std::string & path,int64_t * sp,int64_t limit)1510 char* File::read_file(const std::string& path, int64_t* sp, int64_t limit) {
1511 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1512 _assert_(sp);
1513 if (limit < 0) limit = INT64MAX;
1514 ::DWORD amode = GENERIC_READ;
1515 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1516 ::DWORD cmode = OPEN_EXISTING;
1517 ::HANDLE fh = ::CreateFile(path.c_str(), amode, smode, NULL, cmode,
1518 FILE_ATTRIBUTE_NORMAL, NULL);
1519 if (!fh || fh == INVALID_HANDLE_VALUE) return NULL;
1520 ::LARGE_INTEGER sbuf;
1521 if (!::GetFileSizeEx(fh, &sbuf)) {
1522 ::CloseHandle(fh);
1523 return false;
1524 }
1525 if (limit > (int64_t)sbuf.QuadPart) limit = sbuf.QuadPart;
1526 char* buf = new char[limit+1];
1527 char* wp = buf;
1528 int64_t rsiz;
1529 while ((rsiz = win_read(fh, wp, limit - (wp - buf))) > 0) {
1530 wp += rsiz;
1531 }
1532 *wp = '\0';
1533 ::CloseHandle(fh);
1534 *sp = wp - buf;
1535 return buf;
1536 #else
1537 _assert_(sp);
1538 if (limit < 0) limit = INT64MAX;
1539 int32_t fd = ::open(path.c_str(), O_RDONLY, FILEPERM);
1540 if (fd < 0) return NULL;
1541 struct stat sbuf;
1542 if (::fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)) {
1543 ::close(fd);
1544 return NULL;
1545 }
1546 if (limit > (int64_t)sbuf.st_size) limit = sbuf.st_size;
1547 char* buf = new char[limit+1];
1548 char* wp = buf;
1549 ssize_t rsiz;
1550 while ((rsiz = ::read(fd, wp, limit - (wp - buf))) > 0) {
1551 wp += rsiz;
1552 }
1553 *wp = '\0';
1554 ::close(fd);
1555 *sp = wp - buf;
1556 return buf;
1557 #endif
1558 }
1559
1560
1561 /**
1562 * Write the whole data into a file.
1563 */
write_file(const std::string & path,const char * buf,int64_t size)1564 bool File::write_file(const std::string& path, const char* buf, int64_t size) {
1565 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1566 _assert_(buf && size >= 0 && size <= FILEMAXSIZ);
1567 ::DWORD amode = GENERIC_WRITE;
1568 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1569 ::DWORD cmode = CREATE_ALWAYS;
1570 double wsec = 1.0 / CLOCKTICK;
1571 ::HANDLE fh = INVALID_HANDLE_VALUE;
1572 for (int32_t i = 0; i < 10; i++) {
1573 fh = ::CreateFile(path.c_str(), amode, smode, NULL, cmode, FILE_ATTRIBUTE_NORMAL, NULL);
1574 if (fh && fh != INVALID_HANDLE_VALUE) break;
1575 if (::GetLastError() != ERROR_ACCESS_DENIED) return false;
1576 if (wsec > 1.0) wsec = 1.0;
1577 Thread::sleep(wsec);
1578 wsec *= 2;
1579 }
1580 bool err = false;
1581 const char* rp = buf;
1582 while (!err && size > 0) {
1583 int64_t wb = win_write(fh, rp, size);
1584 switch (wb) {
1585 case -1: {
1586 if (errno != EINTR) {
1587 err = true;
1588 break;
1589 }
1590 }
1591 case 0: {
1592 break;
1593 }
1594 default: {
1595 rp += wb;
1596 size -= wb;
1597 break;
1598 }
1599 }
1600 }
1601 if (!::CloseHandle(fh)) err = true;
1602 return !err;
1603 #else
1604 _assert_(buf && size >= 0 && size <= FILEMAXSIZ);
1605 int32_t fd = ::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, FILEPERM);
1606 if (fd < 0) return false;
1607 bool err = false;
1608 const char* rp = buf;
1609 while (!err && size > 0) {
1610 ssize_t wb = ::write(fd, rp, size);
1611 switch (wb) {
1612 case -1: {
1613 if (errno != EINTR) {
1614 err = true;
1615 break;
1616 }
1617 }
1618 case 0: {
1619 break;
1620 }
1621 default: {
1622 rp += wb;
1623 size -= wb;
1624 break;
1625 }
1626 }
1627 }
1628 if (::close(fd) != 0) err = true;
1629 return !err;
1630 #endif
1631 }
1632
1633
1634 /**
1635 * Get the status information of a file.
1636 */
status(const std::string & path,Status * buf)1637 bool File::status(const std::string& path, Status* buf) {
1638 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1639 _assert_(true);
1640 ::WIN32_FILE_ATTRIBUTE_DATA ibuf;
1641 if (!::GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &ibuf)) return false;
1642 if (buf) {
1643 buf->isdir = ibuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1644 ::LARGE_INTEGER li;
1645 li.LowPart = ibuf.nFileSizeLow;
1646 li.HighPart = ibuf.nFileSizeHigh;
1647 buf->size = li.QuadPart;
1648 li.LowPart = ibuf.ftLastWriteTime.dwLowDateTime;
1649 li.HighPart = ibuf.ftLastWriteTime.dwHighDateTime;
1650 buf->mtime = li.QuadPart;
1651 }
1652 return true;
1653 #else
1654 _assert_(true);
1655 struct ::stat sbuf;
1656 if (::lstat(path.c_str(), &sbuf) != 0) return false;
1657 if (buf) {
1658 buf->isdir = S_ISDIR(sbuf.st_mode);
1659 buf->size = sbuf.st_size;
1660 buf->mtime = sbuf.st_mtime;
1661 }
1662 return true;
1663 #endif
1664 }
1665
1666
1667 /**
1668 * Get the absolute path of a file.
1669 */
absolute_path(const std::string & path)1670 std::string File::absolute_path(const std::string& path) {
1671 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1672 _assert_(true);
1673 char buf[PATHBUFSIZ];
1674 ::DWORD size = ::GetFullPathName(path.c_str(), sizeof(buf), buf, NULL);
1675 if (size < 1) return "";
1676 if (size < sizeof(buf)) return std::string(buf);
1677 char* lbuf = new char[size];
1678 ::DWORD nsiz = ::GetFullPathName(path.c_str(), size, lbuf, NULL);
1679 if (nsiz < 1 || nsiz >= size) {
1680 delete[] lbuf;
1681 return "";
1682 }
1683 std::string rbuf(lbuf);
1684 delete[] lbuf;
1685 return rbuf;
1686 #else
1687 _assert_(true);
1688 char buf[PATHBUFSIZ];
1689 if (!realpath(path.c_str(), buf)) return "";
1690 return std::string(buf);
1691 #endif
1692 }
1693
1694
1695 /**
1696 * Remove a file.
1697 */
remove(const std::string & path)1698 bool File::remove(const std::string& path) {
1699 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1700 _assert_(true);
1701 double wsec = 1.0 / CLOCKTICK;
1702 for (int32_t i = 0; i < 10; i++) {
1703 if (::DeleteFile(path.c_str())) return true;
1704 if (::GetLastError() != ERROR_ACCESS_DENIED) return false;
1705 if (wsec > 1.0) wsec = 1.0;
1706 Thread::sleep(wsec);
1707 wsec *= 2;
1708 }
1709 std::string tmppath;
1710 strprintf(&tmppath, "%s%ctmp%c%llx", path.c_str(), EXTCHR, EXTCHR,
1711 ((unsigned long long)(time() * UINT16MAX)) % UINT32MAX);
1712 if (::MoveFileEx(path.c_str(), tmppath.c_str(), MOVEFILE_REPLACE_EXISTING)) {
1713 ::DeleteFile(tmppath.c_str());
1714 ::DWORD amode = GENERIC_READ | GENERIC_WRITE;
1715 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1716 ::HANDLE fh = ::CreateFile(tmppath.c_str(), amode, smode, NULL, OPEN_EXISTING,
1717 FILE_FLAG_DELETE_ON_CLOSE, NULL);
1718 if (fh && fh != INVALID_HANDLE_VALUE) ::CloseHandle(fh);
1719 return true;
1720 }
1721 return false;
1722 #else
1723 _assert_(true);
1724 return ::unlink(path.c_str()) == 0;
1725 #endif
1726 }
1727
1728
1729 /**
1730 * Change the name or location of a file.
1731 */
rename(const std::string & opath,const std::string & npath)1732 bool File::rename(const std::string& opath, const std::string& npath) {
1733 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1734 _assert_(true);
1735 double wsec = 1.0 / CLOCKTICK;
1736 for (int32_t i = 0; i < 10; i++) {
1737 if (::MoveFileEx(opath.c_str(), npath.c_str(), MOVEFILE_REPLACE_EXISTING)) return true;
1738 if (::GetLastError() != ERROR_ACCESS_DENIED) return false;
1739 if (wsec > 1.0) wsec = 1.0;
1740 Thread::sleep(wsec);
1741 wsec *= 2;
1742 }
1743 std::string tmppath;
1744 strprintf(&tmppath, "%s%ctmp%c%llx", npath.c_str(), EXTCHR, EXTCHR,
1745 ((unsigned long long)(time() * UINT16MAX)) % UINT32MAX);
1746 if (::MoveFileEx(npath.c_str(), tmppath.c_str(), MOVEFILE_REPLACE_EXISTING)) {
1747 if (::MoveFileEx(opath.c_str(), npath.c_str(), MOVEFILE_REPLACE_EXISTING)) {
1748 ::DeleteFile(tmppath.c_str());
1749 ::DWORD amode = GENERIC_READ | GENERIC_WRITE;
1750 ::DWORD smode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1751 ::HANDLE fh = ::CreateFile(tmppath.c_str(), amode, smode, NULL, OPEN_EXISTING,
1752 FILE_FLAG_DELETE_ON_CLOSE, NULL);
1753 if (fh && fh != INVALID_HANDLE_VALUE) ::CloseHandle(fh);
1754 return true;
1755 } else {
1756 wsec = 1.0 / CLOCKTICK;
1757 for (int32_t i = 0; i < 10; i++) {
1758 if (::MoveFileEx(tmppath.c_str(), npath.c_str(), MOVEFILE_REPLACE_EXISTING)) break;
1759 if (wsec > 1.0) wsec = 1.0;
1760 Thread::sleep(wsec);
1761 wsec *= 2;
1762 }
1763 }
1764 }
1765 return false;
1766 #else
1767 _assert_(true);
1768 return ::rename(opath.c_str(), npath.c_str()) == 0;
1769 #endif
1770 }
1771
1772
1773 /**
1774 * Read a directory.
1775 */
read_directory(const std::string & path,std::vector<std::string> * strvec)1776 bool File::read_directory(const std::string& path, std::vector<std::string>* strvec) {
1777 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1778 _assert_(strvec);
1779 std::string dpath = path;
1780 size_t plen = path.size();
1781 if (plen < 1 || path[plen-1] != PATHCHR) dpath.append(PATHSTR);
1782 dpath.append("*");
1783 ::WIN32_FIND_DATA fbuf;
1784 ::HANDLE dh = ::FindFirstFile(dpath.c_str(), &fbuf);
1785 if (!dh || dh == INVALID_HANDLE_VALUE) return false;
1786 if (std::strcmp(fbuf.cFileName, CDIRSTR) && std::strcmp(fbuf.cFileName, PDIRSTR))
1787 strvec->push_back(fbuf.cFileName);
1788 while (::FindNextFile(dh, &fbuf)) {
1789 if (std::strcmp(fbuf.cFileName, CDIRSTR) && std::strcmp(fbuf.cFileName, PDIRSTR))
1790 strvec->push_back(fbuf.cFileName);
1791 }
1792 if (!::FindClose(dh)) return false;
1793 return true;
1794 #else
1795 _assert_(strvec);
1796 ::DIR* dir = ::opendir(path.c_str());
1797 if (!dir) return false;
1798 struct ::dirent *dp;
1799 while ((dp = ::readdir(dir)) != NULL) {
1800 if (std::strcmp(dp->d_name, CDIRSTR) && std::strcmp(dp->d_name, PDIRSTR))
1801 strvec->push_back(dp->d_name);
1802 }
1803 if (::closedir(dir) != 0) return false;
1804 return true;
1805 #endif
1806 }
1807
1808
1809 /**
1810 * Make a directory.
1811 */
make_directory(const std::string & path)1812 bool File::make_directory(const std::string& path) {
1813 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1814 _assert_(true);
1815 double wsec = 1.0 / CLOCKTICK;
1816 for (int32_t i = 0; i < 10; i++) {
1817 if (::CreateDirectory(path.c_str(), NULL)) return true;
1818 if (::GetLastError() != ERROR_ACCESS_DENIED) return false;
1819 if (wsec > 1.0) wsec = 1.0;
1820 Thread::sleep(wsec);
1821 wsec *= 2;
1822 }
1823 return false;
1824 #else
1825 _assert_(true);
1826 return ::mkdir(path.c_str(), DIRPERM) == 0;
1827 #endif
1828 }
1829
1830
1831 /**
1832 * Remove a directory.
1833 */
remove_directory(const std::string & path)1834 bool File::remove_directory(const std::string& path) {
1835 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1836 _assert_(true);
1837 double wsec = 1.0 / CLOCKTICK;
1838 for (int32_t i = 0; i < 10; i++) {
1839 if (::RemoveDirectory(path.c_str())) return true;
1840 if (::GetLastError() != ERROR_ACCESS_DENIED) return false;
1841 if (wsec > 1.0) wsec = 1.0;
1842 Thread::sleep(wsec);
1843 wsec *= 2;
1844 }
1845 return false;
1846 #else
1847 _assert_(true);
1848 return ::rmdir(path.c_str()) == 0;
1849 #endif
1850 }
1851
1852
1853 /**
1854 * Remove a file or a directory recursively.
1855 */
remove_recursively(const std::string & path)1856 bool File::remove_recursively(const std::string& path) {
1857 bool err = false;
1858 std::vector<std::string> list;
1859 list.push_back(path);
1860 while (!list.empty()) {
1861 const std::string& cpath = list.back();
1862 Status sbuf;
1863 if (status(cpath, &sbuf)) {
1864 if (sbuf.isdir) {
1865 if (remove_directory(cpath)) {
1866 list.pop_back();
1867 } else {
1868 DirStream dir;
1869 if (dir.open(cpath)) {
1870 std::string ccname;
1871 while (dir.read(&ccname)) {
1872 const std::string& ccpath = cpath + MYPATHCHR + ccname;
1873 if (!remove(ccpath)) list.push_back(ccpath);
1874 }
1875 if (!dir.close()) err = true;
1876 } else {
1877 list.pop_back();
1878 err = true;
1879 }
1880 }
1881 } else {
1882 if (!remove(cpath)) err = true;
1883 list.pop_back();
1884 }
1885 } else {
1886 list.pop_back();
1887 err = true;
1888 }
1889 }
1890 return !err;
1891 }
1892
1893
1894 /**
1895 * Get the path of the current working directory.
1896 */
get_current_directory()1897 std::string File::get_current_directory() {
1898 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1899 _assert_(true);
1900 char buf[PATHBUFSIZ];
1901 ::DWORD size = ::GetCurrentDirectory(sizeof(buf), buf);
1902 if (size < 1) return "";
1903 if (size < sizeof(buf)) return std::string(buf);
1904 char* lbuf = new char[size];
1905 ::DWORD nsiz = ::GetCurrentDirectory(size, lbuf);
1906 if (nsiz < 1 || nsiz >= size) {
1907 delete[] lbuf;
1908 return "";
1909 }
1910 std::string rbuf(lbuf);
1911 delete[] lbuf;
1912 return rbuf;
1913 #else
1914 _assert_(true);
1915 char buf[PATHBUFSIZ];
1916 if (!::getcwd(buf, sizeof(buf))) return "";
1917 return std::string(buf);
1918 #endif
1919 }
1920
1921
1922 /**
1923 * Set the current working directory.
1924 */
set_current_directory(const std::string & path)1925 bool File::set_current_directory(const std::string& path) {
1926 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1927 _assert_(true);
1928 return ::SetCurrentDirectory(path.c_str());
1929 #else
1930 _assert_(true);
1931 return ::chdir(path.c_str()) == 0;
1932 #endif
1933 }
1934
1935
1936 /**
1937 * Synchronize the whole of the file system with the device.
1938 */
synchronize_whole()1939 bool File::synchronize_whole() {
1940 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1941 _assert_(true);
1942 return true;
1943 #else
1944 _assert_(true);
1945 ::sync();
1946 return true;
1947 #endif
1948 }
1949
1950
1951
1952 /**
1953 * Default constructor.
1954 */
DirStream()1955 DirStream::DirStream() : opq_(NULL) {
1956 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1957 _assert_(true);
1958 DirStreamCore* core = new DirStreamCore;
1959 core->dh = NULL;
1960 opq_ = core;
1961 #else
1962 _assert_(true);
1963 DirStreamCore* core = new DirStreamCore;
1964 core->dh = NULL;
1965 opq_ = core;
1966 #endif
1967 }
1968
1969
1970 /**
1971 * Destructor.
1972 */
~DirStream()1973 DirStream::~DirStream() {
1974 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1975 _assert_(true);
1976 DirStreamCore* core = (DirStreamCore*)opq_;
1977 if (core->dh) close();
1978 delete core;
1979 #else
1980 _assert_(true);
1981 DirStreamCore* core = (DirStreamCore*)opq_;
1982 if (core->dh) close();
1983 delete core;
1984 #endif
1985 }
1986
1987
1988 /**
1989 * Open a directory.
1990 */
open(const std::string & path)1991 bool DirStream::open(const std::string& path) {
1992 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1993 _assert_(true);
1994 DirStreamCore* core = (DirStreamCore*)opq_;
1995 ScopedMutex lock(&core->alock);
1996 if (core->dh) return false;
1997 std::string dpath = path;
1998 size_t plen = path.size();
1999 if (plen < 1 || path[plen-1] != File::PATHCHR) dpath.append(File::PATHSTR);
2000 dpath.append("*");
2001 ::WIN32_FIND_DATA fbuf;
2002 ::HANDLE dh = ::FindFirstFile(dpath.c_str(), &fbuf);
2003 if (!dh || dh == INVALID_HANDLE_VALUE) return false;
2004 core->dh = dh;
2005 core->cur = fbuf.cFileName;
2006 return true;
2007 #else
2008 _assert_(true);
2009 DirStreamCore* core = (DirStreamCore*)opq_;
2010 ScopedMutex lock(&core->alock);
2011 if (core->dh) return false;
2012 ::DIR* dh = ::opendir(path.c_str());
2013 if (!dh) return false;
2014 core->dh = dh;
2015 return true;
2016 #endif
2017 }
2018
2019
2020 /**
2021 * Close the file.
2022 */
close()2023 bool DirStream::close() {
2024 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2025 _assert_(true);
2026 DirStreamCore* core = (DirStreamCore*)opq_;
2027 ScopedMutex lock(&core->alock);
2028 if (!core->dh) return false;
2029 bool err = false;
2030 if (!::FindClose(core->dh)) err = true;
2031 core->dh = NULL;
2032 core->cur.clear();
2033 return !err;
2034 #else
2035 _assert_(true);
2036 DirStreamCore* core = (DirStreamCore*)opq_;
2037 ScopedMutex lock(&core->alock);
2038 if (!core->dh) return false;
2039 bool err = false;
2040 if (::closedir(core->dh) != 0) err = true;
2041 core->dh = NULL;
2042 return !err;
2043 #endif
2044 }
2045
2046
2047 /**
2048 * Read the next file in the directory.
2049 */
read(std::string * path)2050 bool DirStream::read(std::string* path) {
2051 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2052 _assert_(path);
2053 DirStreamCore* core = (DirStreamCore*)opq_;
2054 ScopedMutex lock(&core->alock);
2055 if (!core->dh) return false;
2056 while (core->cur == File::CDIRSTR || core->cur == File::PDIRSTR) {
2057 ::WIN32_FIND_DATA fbuf;
2058 if (::FindNextFile(core->dh, &fbuf)) {
2059 core->cur = fbuf.cFileName;
2060 } else {
2061 core->cur.clear();
2062 return false;
2063 }
2064 }
2065 if (core->cur.empty()) return false;
2066 path->clear();
2067 path->append(core->cur);
2068 ::WIN32_FIND_DATA fbuf;
2069 if (::FindNextFile(core->dh, &fbuf)) {
2070 core->cur = fbuf.cFileName;
2071 } else {
2072 core->cur.clear();
2073 }
2074 return true;
2075 #else
2076 _assert_(path);
2077 DirStreamCore* core = (DirStreamCore*)opq_;
2078 ScopedMutex lock(&core->alock);
2079 if (!core->dh) return false;
2080 struct ::dirent *dp;
2081 do {
2082 dp = ::readdir(core->dh);
2083 if (!dp) return false;
2084 } while (!std::strcmp(dp->d_name, File::CDIRSTR) || !std::strcmp(dp->d_name, File::PDIRSTR));
2085 path->clear();
2086 path->append(dp->d_name);
2087 return true;
2088 #endif
2089 }
2090
2091
2092 /**
2093 * Set the error message.
2094 */
seterrmsg(FileCore * core,const char * msg)2095 static void seterrmsg(FileCore* core, const char* msg) {
2096 _assert_(core && msg);
2097 core->errmsg.set((void*)msg);
2098 }
2099
2100
2101 /**
2102 * Get the path of the WAL file.
2103 */
walpath(const std::string & path)2104 static std::string walpath(const std::string& path) {
2105 _assert_(true);
2106 return path + File::EXTCHR + WALPATHEXT;
2107 }
2108
2109
2110 /**
2111 * Write a log message into the WAL file.
2112 */
walwrite(FileCore * core,int64_t off,size_t size,int64_t base)2113 static bool walwrite(FileCore *core, int64_t off, size_t size, int64_t base) {
2114 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2115 _assert_(core && off >= 0 && off <= FILEMAXSIZ && size <= MEMMAXSIZ && base >= 0);
2116 bool err = false;
2117 if (off < base) {
2118 int64_t diff = base - off;
2119 if (diff >= (int64_t)size) return true;
2120 off = base;
2121 size -= diff;
2122 }
2123 int64_t rem = core->trmsiz - off;
2124 if (rem < 1) return true;
2125 if (rem < (int64_t)size) size = rem;
2126 char stack[IOBUFSIZ];
2127 size_t rsiz = sizeof(int8_t) + sizeof(int64_t) * 2 + size;
2128 char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack;
2129 char* wp = rbuf;
2130 *(wp++) = WALMSGMAGIC;
2131 int64_t num = hton64(off);
2132 std::memcpy(wp, &num, sizeof(num));
2133 wp += sizeof(num);
2134 num = hton64(size);
2135 std::memcpy(wp, &num, sizeof(num));
2136 wp += sizeof(num);
2137 core->alock.lock();
2138 int64_t end = off + size;
2139 if (end <= core->msiz) {
2140 std::memcpy(wp, core->map + off, size);
2141 } else {
2142 if (off < core->msiz) {
2143 int64_t hsiz = core->msiz - off;
2144 std::memcpy(wp, core->map + off, hsiz);
2145 off += hsiz;
2146 wp += hsiz;
2147 size -= hsiz;
2148 }
2149 while (true) {
2150 int64_t rb = win_pread(core->fh, wp, size, off);
2151 if (rb >= (int64_t)size) {
2152 break;
2153 } else if (rb > 0) {
2154 wp += rb;
2155 size -= rb;
2156 off += rb;
2157 } else {
2158 err = true;
2159 break;
2160 }
2161 }
2162 if (err) {
2163 seterrmsg(core, "win_pread failed");
2164 std::memset(wp, 0, size);
2165 }
2166 }
2167 if (!mywrite(core->walfh, core->walsiz, rbuf, rsiz)) {
2168 seterrmsg(core, "mywrite failed");
2169 err = true;
2170 }
2171 if (core->trhard && !::FlushFileBuffers(core->walfh)) {
2172 seterrmsg(core, "FlushFileBuffers failed");
2173 err = true;
2174 }
2175 core->walsiz += rsiz;
2176 if (rbuf != stack) delete[] rbuf;
2177 core->alock.unlock();
2178 return !err;
2179 #else
2180 _assert_(core && off >= 0 && off <= FILEMAXSIZ && size <= MEMMAXSIZ && base >= 0);
2181 bool err = false;
2182 if (off < base) {
2183 int64_t diff = base - off;
2184 if (diff >= (int64_t)size) return true;
2185 off = base;
2186 size -= diff;
2187 }
2188 int64_t rem = core->trmsiz - off;
2189 if (rem < 1) return true;
2190 if (rem < (int64_t)size) size = rem;
2191 char stack[IOBUFSIZ];
2192 size_t rsiz = sizeof(int8_t) + sizeof(int64_t) * 2 + size;
2193 char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack;
2194 char* wp = rbuf;
2195 *(wp++) = WALMSGMAGIC;
2196 int64_t num = hton64(off);
2197 std::memcpy(wp, &num, sizeof(num));
2198 wp += sizeof(num);
2199 num = hton64(size);
2200 std::memcpy(wp, &num, sizeof(num));
2201 wp += sizeof(num);
2202 core->alock.lock();
2203 int64_t end = off + size;
2204 if (end <= core->msiz) {
2205 std::memcpy(wp, core->map + off, size);
2206 } else {
2207 if (off < core->msiz) {
2208 int64_t hsiz = core->msiz - off;
2209 std::memcpy(wp, core->map + off, hsiz);
2210 off += hsiz;
2211 wp += hsiz;
2212 size -= hsiz;
2213 }
2214 while (true) {
2215 ssize_t rb = ::pread(core->fd, wp, size, off);
2216 if (rb >= (ssize_t)size) {
2217 break;
2218 } else if (rb > 0) {
2219 wp += rb;
2220 size -= rb;
2221 off += rb;
2222 } else if (rb == -1) {
2223 if (errno != EINTR) {
2224 err = true;
2225 break;
2226 }
2227 } else {
2228 err = true;
2229 break;
2230 }
2231 }
2232 if (err) {
2233 seterrmsg(core, "pread failed");
2234 std::memset(wp, 0, size);
2235 }
2236 }
2237 if (!mywrite(core->walfd, core->walsiz, rbuf, rsiz)) {
2238 seterrmsg(core, "mywrite failed");
2239 err = true;
2240 }
2241 if (core->trhard && ::fsync(core->walfd) != 0) {
2242 seterrmsg(core, "fsync failed");
2243 err = true;
2244 }
2245 core->walsiz += rsiz;
2246 if (rbuf != stack) delete[] rbuf;
2247 core->alock.unlock();
2248 return !err;
2249 #endif
2250 }
2251
2252
2253 /**
2254 * Apply log messages in the WAL file.
2255 */
walapply(FileCore * core)2256 static bool walapply(FileCore* core) {
2257 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2258 _assert_(core);
2259 bool err = false;
2260 char buf[IOBUFSIZ];
2261 int64_t hsiz = sizeof(WALMAGICDATA) + sizeof(int64_t);
2262 ::LARGE_INTEGER li;
2263 if (!::GetFileSizeEx(core->walfh, &li)) {
2264 seterrmsg(core, "GetFileSizeEx failed");
2265 return false;
2266 }
2267 int64_t rem = li.QuadPart;
2268 if (rem < hsiz) {
2269 seterrmsg(core, "too short WAL file");
2270 return false;
2271 }
2272 li.QuadPart = 0;
2273 if (!::SetFilePointerEx(core->walfh, li, NULL, FILE_BEGIN)) {
2274 seterrmsg(core, "SetFilePointerEx failed");
2275 return false;
2276 }
2277 if (!myread(core->walfh, buf, hsiz)) {
2278 seterrmsg(core, "myread failed");
2279 return false;
2280 }
2281 if (*buf == 0) return true;
2282 if (std::memcmp(buf, WALMAGICDATA, sizeof(WALMAGICDATA))) {
2283 seterrmsg(core, "invalid magic data of WAL");
2284 return false;
2285 }
2286 int64_t osiz;
2287 std::memcpy(&osiz, buf + sizeof(WALMAGICDATA), sizeof(osiz));
2288 osiz = ntoh64(osiz);
2289 rem -= hsiz;
2290 hsiz = sizeof(uint8_t) + sizeof(int64_t) * 2;
2291 std::vector<WALMessage> msgs;
2292 int64_t end = 0;
2293 while (rem >= hsiz) {
2294 if (!myread(core->walfh, buf, hsiz)) {
2295 seterrmsg(core, "myread failed");
2296 err = true;
2297 break;
2298 }
2299 if (*buf == 0) {
2300 rem = 0;
2301 break;
2302 }
2303 rem -= hsiz;
2304 char* rp = buf;
2305 if (*(uint8_t*)(rp++) != WALMSGMAGIC) {
2306 seterrmsg(core, "invalid magic data of WAL message");
2307 err = true;
2308 break;
2309 }
2310 if (rem > 0) {
2311 int64_t off;
2312 std::memcpy(&off, rp, sizeof(off));
2313 off = ntoh64(off);
2314 rp += sizeof(off);
2315 int64_t size;
2316 std::memcpy(&size, rp, sizeof(size));
2317 size = ntoh64(size);
2318 rp += sizeof(size);
2319 if (off < 0 || size < 0) {
2320 seterrmsg(core, "invalid meta data of WAL message");
2321 err = true;
2322 break;
2323 }
2324 if (rem < size) {
2325 seterrmsg(core, "too short WAL message");
2326 err = true;
2327 break;
2328 }
2329 char* rbuf = size > (int64_t)sizeof(buf) ? new char[size] : buf;
2330 if (!myread(core->walfh, rbuf, size)) {
2331 seterrmsg(core, "myread failed");
2332 if (rbuf != buf) delete[] rbuf;
2333 err = true;
2334 break;
2335 }
2336 rem -= size;
2337 WALMessage msg = { off, std::string(rbuf, size) };
2338 msgs.push_back(msg);
2339 if (off + size > end) end = off + size;
2340 if (rbuf != buf) delete[] rbuf;
2341 }
2342 }
2343 if (rem != 0) {
2344 if (!myread(core->walfh, buf, 1)) {
2345 seterrmsg(core, "myread failed");
2346 err = true;
2347 } else if (*buf != 0) {
2348 seterrmsg(core, "too few messages of WAL");
2349 err = true;
2350 }
2351 }
2352 if (end > core->msiz) end = core->msiz;
2353 if (core->psiz < end && win_ftruncate(core->fh, end) != 0) {
2354 seterrmsg(core, "win_ftruncate failed");
2355 err = true;
2356 }
2357 for (int64_t i = (int64_t)msgs.size() - 1; i >= 0; i--) {
2358 const WALMessage& msg = msgs[i];
2359 int64_t off = msg.off;
2360 const char* rbuf = msg.body.c_str();
2361 size_t size = msg.body.size();
2362 int64_t end = off + size;
2363 if (end <= core->msiz) {
2364 std::memcpy(core->map + off, rbuf, size);
2365 } else {
2366 if (off < core->msiz) {
2367 size_t hsiz = core->msiz - off;
2368 std::memcpy(core->map + off, rbuf, hsiz);
2369 off += hsiz;
2370 rbuf += hsiz;
2371 size -= hsiz;
2372 }
2373 while (true) {
2374 int64_t wb = win_pwrite(core->fh, rbuf, size, off);
2375 if (wb >= (int64_t)size) {
2376 break;
2377 } else if (wb > 0) {
2378 rbuf += wb;
2379 size -= wb;
2380 off += wb;
2381 } else if (wb == -1) {
2382 seterrmsg(core, "win_pwrite failed");
2383 err = true;
2384 break;
2385 } else if (size > 0) {
2386 seterrmsg(core, "pwrite failed");
2387 err = true;
2388 break;
2389 }
2390 }
2391 }
2392 }
2393 if (win_ftruncate(core->fh, osiz) == 0) {
2394 core->lsiz = osiz;
2395 core->psiz = osiz;
2396 } else {
2397 seterrmsg(core, "win_ftruncate failed");
2398 err = true;
2399 }
2400 return !err;
2401 #else
2402 _assert_(core);
2403 bool err = false;
2404 char buf[IOBUFSIZ];
2405 int64_t hsiz = sizeof(WALMAGICDATA) + sizeof(int64_t);
2406 int64_t rem = ::lseek(core->walfd, 0, SEEK_END);
2407 if (rem < hsiz) {
2408 seterrmsg(core, "lseek failed");
2409 return false;
2410 }
2411 if (::lseek(core->walfd, 0, SEEK_SET) != 0) {
2412 seterrmsg(core, "lseek failed");
2413 return false;
2414 }
2415 if (!myread(core->walfd, buf, hsiz)) {
2416 seterrmsg(core, "myread failed");
2417 return false;
2418 }
2419 if (*buf == 0) return true;
2420 if (std::memcmp(buf, WALMAGICDATA, sizeof(WALMAGICDATA))) {
2421 seterrmsg(core, "invalid magic data of WAL");
2422 return false;
2423 }
2424 int64_t osiz;
2425 std::memcpy(&osiz, buf + sizeof(WALMAGICDATA), sizeof(osiz));
2426 osiz = ntoh64(osiz);
2427 rem -= hsiz;
2428 hsiz = sizeof(uint8_t) + sizeof(int64_t) * 2;
2429 std::vector<WALMessage> msgs;
2430 int64_t end = 0;
2431 while (rem >= hsiz) {
2432 if (!myread(core->walfd, buf, hsiz)) {
2433 seterrmsg(core, "myread failed");
2434 err = true;
2435 break;
2436 }
2437 if (*buf == 0) {
2438 rem = 0;
2439 break;
2440 }
2441 rem -= hsiz;
2442 char* rp = buf;
2443 if (*(uint8_t*)(rp++) != WALMSGMAGIC) {
2444 seterrmsg(core, "invalid magic data of WAL message");
2445 err = true;
2446 break;
2447 }
2448 if (rem > 0) {
2449 int64_t off;
2450 std::memcpy(&off, rp, sizeof(off));
2451 off = ntoh64(off);
2452 rp += sizeof(off);
2453 int64_t size;
2454 std::memcpy(&size, rp, sizeof(size));
2455 size = ntoh64(size);
2456 rp += sizeof(size);
2457 if (off < 0 || size < 0) {
2458 seterrmsg(core, "invalid meta data of WAL message");
2459 err = true;
2460 break;
2461 }
2462 if (rem < size) {
2463 seterrmsg(core, "too short WAL message");
2464 err = true;
2465 break;
2466 }
2467 char* rbuf = size > (int64_t)sizeof(buf) ? new char[size] : buf;
2468 if (!myread(core->walfd, rbuf, size)) {
2469 seterrmsg(core, "myread failed");
2470 if (rbuf != buf) delete[] rbuf;
2471 err = true;
2472 break;
2473 }
2474 rem -= size;
2475 WALMessage msg = { off, std::string(rbuf, size) };
2476 msgs.push_back(msg);
2477 if (off + size > end) end = off + size;
2478 if (rbuf != buf) delete[] rbuf;
2479 }
2480 }
2481 if (rem != 0) {
2482 if (!myread(core->walfd, buf, 1)) {
2483 seterrmsg(core, "myread failed");
2484 err = true;
2485 } else if (*buf != 0) {
2486 seterrmsg(core, "too few messages of WAL");
2487 err = true;
2488 }
2489 }
2490 if (end > core->msiz) end = core->msiz;
2491 if (core->psiz < end && ::ftruncate(core->fd, end) != 0) {
2492 seterrmsg(core, "ftruncate failed");
2493 err = true;
2494 }
2495 for (int64_t i = (int64_t)msgs.size() - 1; i >= 0; i--) {
2496 const WALMessage& msg = msgs[i];
2497 int64_t off = msg.off;
2498 const char* rbuf = msg.body.c_str();
2499 size_t size = msg.body.size();
2500 int64_t end = off + size;
2501 if (end <= core->msiz) {
2502 std::memcpy(core->map + off, rbuf, size);
2503 } else {
2504 if (off < core->msiz) {
2505 size_t hsiz = core->msiz - off;
2506 std::memcpy(core->map + off, rbuf, hsiz);
2507 off += hsiz;
2508 rbuf += hsiz;
2509 size -= hsiz;
2510 }
2511 while (true) {
2512 ssize_t wb = ::pwrite(core->fd, rbuf, size, off);
2513 if (wb >= (ssize_t)size) {
2514 break;
2515 } else if (wb > 0) {
2516 rbuf += wb;
2517 size -= wb;
2518 off += wb;
2519 } else if (wb == -1) {
2520 if (errno != EINTR) {
2521 seterrmsg(core, "pwrite failed");
2522 err = true;
2523 break;
2524 }
2525 } else if (size > 0) {
2526 seterrmsg(core, "pwrite failed");
2527 err = true;
2528 break;
2529 }
2530 }
2531 }
2532 }
2533 if (::ftruncate(core->fd, osiz) == 0) {
2534 core->lsiz = osiz;
2535 core->psiz = osiz;
2536 } else {
2537 seterrmsg(core, "ftruncate failed");
2538 err = true;
2539 }
2540 return !err;
2541 #endif
2542 }
2543
2544
2545 /**
2546 * Write data into a file.
2547 */
2548 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
mywrite(::HANDLE fh,int64_t off,const void * buf,size_t size)2549 static bool mywrite(::HANDLE fh, int64_t off, const void* buf, size_t size) {
2550 _assert_(off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
2551 while (true) {
2552 int64_t wb = win_pwrite(fh, buf, size, off);
2553 if (wb >= (int64_t)size) {
2554 return true;
2555 } else if (wb > 0) {
2556 buf = (char*)buf + wb;
2557 size -= wb;
2558 off += wb;
2559 } else if (wb == -1) {
2560 return false;
2561 } else if (size > 0) {
2562 return false;
2563 }
2564 }
2565 return true;
2566 }
2567 #else
mywrite(int32_t fd,int64_t off,const void * buf,size_t size)2568 static bool mywrite(int32_t fd, int64_t off, const void* buf, size_t size) {
2569 _assert_(fd >= 0 && off >= 0 && off <= FILEMAXSIZ && buf && size <= MEMMAXSIZ);
2570 while (true) {
2571 ssize_t wb = ::pwrite(fd, buf, size, off);
2572 if (wb >= (ssize_t)size) {
2573 return true;
2574 } else if (wb > 0) {
2575 buf = (char*)buf + wb;
2576 size -= wb;
2577 off += wb;
2578 } else if (wb == -1) {
2579 if (errno != EINTR) return false;
2580 } else if (size > 0) {
2581 return false;
2582 }
2583 }
2584 return true;
2585 }
2586 #endif
2587
2588
2589 /**
2590 * Read data from a file.
2591 */
2592 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
myread(::HANDLE fh,void * buf,size_t size)2593 static size_t myread(::HANDLE fh, void* buf, size_t size) {
2594 _assert_(buf && size <= MEMMAXSIZ);
2595 while (true) {
2596 int64_t rb = win_read(fh, buf, size);
2597 if (rb >= (int64_t)size) {
2598 break;
2599 } else if (rb > 0) {
2600 buf = (char*)buf + rb;
2601 size -= rb;
2602 } else if (rb == -1) {
2603 return false;
2604 } else if (size > 0) {
2605 return false;
2606 }
2607 }
2608 return true;
2609 }
2610 #else
myread(int32_t fd,void * buf,size_t size)2611 static size_t myread(int32_t fd, void* buf, size_t size) {
2612 _assert_(fd >= 0 && buf && size <= MEMMAXSIZ);
2613 while (true) {
2614 ssize_t rb = ::read(fd, buf, size);
2615 if (rb >= (ssize_t)size) {
2616 break;
2617 } else if (rb > 0) {
2618 buf = (char*)buf + rb;
2619 size -= rb;
2620 } else if (rb == -1) {
2621 if (errno != EINTR) return false;
2622 } else if (size > 0) {
2623 return false;
2624 }
2625 }
2626 return true;
2627 }
2628 #endif
2629
2630
2631 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2632 /**
2633 * Emulate the pwrite call
2634 */
win_pwrite(::HANDLE fh,const void * buf,size_t count,int64_t offset)2635 static int64_t win_pwrite(::HANDLE fh, const void* buf, size_t count, int64_t offset) {
2636 _assert_(buf && count <= MEMMAXSIZ && offset >= 0 && offset <= FILEMAXSIZ);
2637 ::DWORD wb;
2638 ::LARGE_INTEGER li;
2639 li.QuadPart = offset;
2640 ::OVERLAPPED ol;
2641 ol.Offset = li.LowPart;
2642 ol.OffsetHigh = li.HighPart;
2643 ol.hEvent = NULL;
2644 if (!::WriteFile(fh, buf, count, &wb, &ol)) return -1;
2645 return wb;
2646 }
2647 #endif
2648
2649
2650 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2651 /**
2652 * Emulate the pread call
2653 */
win_pread(::HANDLE fh,void * buf,size_t count,int64_t offset)2654 static int64_t win_pread(::HANDLE fh, void* buf, size_t count, int64_t offset) {
2655 _assert_(buf && count <= MEMMAXSIZ && offset >= 0 && offset <= FILEMAXSIZ);
2656 ::DWORD rb;
2657 ::LARGE_INTEGER li;
2658 li.QuadPart = offset;
2659 ::OVERLAPPED ol;
2660 ol.Offset = li.LowPart;
2661 ol.OffsetHigh = li.HighPart;
2662 ol.hEvent = NULL;
2663 if (!::ReadFile(fh, buf, count, &rb, &ol)) return -1;
2664 return rb;
2665 }
2666 #endif
2667
2668
2669 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2670 /**
2671 * Emulate the write call
2672 */
win_write(::HANDLE fh,const void * buf,size_t count)2673 static int64_t win_write(::HANDLE fh, const void* buf, size_t count) {
2674 _assert_(buf && count <= MEMMAXSIZ);
2675 ::DWORD wb;
2676 if (!::WriteFile(fh, buf, count, &wb, NULL)) return -1;
2677 return wb;
2678 }
2679 #endif
2680
2681
2682 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2683 /**
2684 * Emulate the read call
2685 */
win_read(::HANDLE fh,void * buf,size_t count)2686 static int64_t win_read(::HANDLE fh, void* buf, size_t count) {
2687 _assert_(buf && count <= MEMMAXSIZ);
2688 ::DWORD rb;
2689 if (!::ReadFile(fh, buf, count, &rb, NULL)) return -1;
2690 return rb;
2691 }
2692 #endif
2693
2694
2695 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2696 /**
2697 * Emulate the ftruncate call
2698 */
win_ftruncate(::HANDLE fh,int64_t length)2699 static int32_t win_ftruncate(::HANDLE fh, int64_t length) {
2700 _assert_(length >= 0 && length <= FILEMAXSIZ);
2701 ::LARGE_INTEGER li;
2702 li.QuadPart = length;
2703 if (!::SetFilePointerEx(fh, li, NULL, FILE_BEGIN)) return -1;
2704 if (!::SetEndOfFile(fh) && ::GetLastError() != 1224) return -1;
2705 return 0;
2706 }
2707 #endif
2708
2709
2710 } // common namespace
2711
2712 // END OF FILE
2713