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