xref: /5.5.2/couchstore/src/os_win.cc (revision b7f883ef)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17#include "config.h"
18#include <assert.h>
19#include <sys/types.h>
20#include <fcntl.h>
21#include <errno.h>
22
23#include "internal.h"
24
25#undef LOG_IO
26#ifdef LOG_IO
27#include <stdio.h>
28#endif
29
30#include <io.h>
31#include <share.h>
32#include <assert.h>
33
34static DWORD save_windows_error(couchstore_error_info_t *errinfo) {
35    DWORD err = GetLastError();
36    if (errinfo) {
37        errinfo->error = err;
38    }
39
40    return err;
41}
42
43static HANDLE handle_to_win(couch_file_handle handle)
44{
45    return (HANDLE)(intptr_t)handle;
46}
47
48static couch_file_handle win_to_handle(HANDLE hdl)
49{
50    return (couch_file_handle)(intptr_t)hdl;
51}
52
53class WindowsFileOps : public FileOpsInterface {
54public:
55    WindowsFileOps() {}
56
57    couch_file_handle constructor(couchstore_error_info_t* errinfo) override ;
58    couchstore_error_t open(couchstore_error_info_t* errinfo,
59                            couch_file_handle* handle, const char* path,
60                            int oflag) override;
61    couchstore_error_t close(couchstore_error_info_t* errinfo,
62                             couch_file_handle handle) override;
63    ssize_t pread(couchstore_error_info_t* errinfo,
64                  couch_file_handle handle, void* buf, size_t nbytes,
65                  cs_off_t offset) override;
66    ssize_t pwrite(couchstore_error_info_t* errinfo,
67                   couch_file_handle handle, const void* buf,
68                   size_t nbytes, cs_off_t offset) override;
69    cs_off_t goto_eof(couchstore_error_info_t* errinfo,
70                      couch_file_handle handle) override;
71    couchstore_error_t sync(couchstore_error_info_t* errinfo,
72                            couch_file_handle handle) override;
73    couchstore_error_t advise(couchstore_error_info_t* errinfo,
74                              couch_file_handle handle, cs_off_t offset,
75                              cs_off_t len,
76                              couchstore_file_advice_t advice) override;
77    void destructor(couch_file_handle handle) override;
78
79private:
80    // State of a single file handle, as returned by open().
81    struct File {
82        File(HANDLE fh = INVALID_HANDLE_VALUE) : fh(fh) {
83        }
84
85        /// File handle to operate on.
86        HANDLE fh;
87    };
88
89    static File* to_file(couch_file_handle handle)
90    {
91        return reinterpret_cast<File*>(handle);
92    }
93};
94
95ssize_t WindowsFileOps::pread(couchstore_error_info_t* errinfo,
96                              couch_file_handle handle,
97                              void* buf,
98                              size_t nbyte,
99                              cs_off_t offset)
100{
101#ifdef LOG_IO
102    fprintf(stderr, "PREAD  %8llx -- %8llx  (%6.1f kbytes)\n", offset,
103            offset+nbyte, nbyte/1024.0);
104#endif
105    auto* file = to_file(handle);
106    BOOL rv;
107    DWORD bytesread;
108    OVERLAPPED winoffs;
109    memset(&winoffs, 0, sizeof(winoffs));
110    winoffs.Offset = offset & 0xFFFFFFFF;
111    winoffs.OffsetHigh = (offset >> 32) & 0x7FFFFFFF;
112    rv = ReadFile(file->fh, buf, nbyte, &bytesread, &winoffs);
113    if(!rv) {
114        save_windows_error(errinfo);
115        return (ssize_t) COUCHSTORE_ERROR_READ;
116    }
117    return bytesread;
118}
119
120ssize_t WindowsFileOps::pwrite(couchstore_error_info_t *errinfo,
121                               couch_file_handle handle,
122                               const void *buf,
123                               size_t nbyte,
124                               cs_off_t offset)
125{
126#ifdef LOG_IO
127    fprintf(stderr, "PWRITE %8llx -- %8llx  (%6.1f kbytes)\n", offset,
128            offset+nbyte, nbyte/1024.0);
129#endif
130    auto* file = to_file(handle);
131    BOOL rv;
132    DWORD byteswritten;
133    OVERLAPPED winoffs;
134    memset(&winoffs, 0, sizeof(winoffs));
135    winoffs.Offset = offset & 0xFFFFFFFF;
136    winoffs.OffsetHigh = (offset >> 32) & 0x7FFFFFFF;
137    rv = WriteFile(file->fh, buf, nbyte, &byteswritten, &winoffs);
138    if(!rv) {
139        save_windows_error(errinfo);
140        return (ssize_t) COUCHSTORE_ERROR_WRITE;
141    }
142    return byteswritten;
143}
144
145couchstore_error_t WindowsFileOps::open(couchstore_error_info_t *errinfo,
146                                        couch_file_handle* handle,
147                                        const char* path,
148                                        int oflag)
149{
150    auto* file = to_file(*handle);
151    if (file) {
152        cb_assert(file->fh == INVALID_HANDLE_VALUE);
153        delete file;
154        *handle = nullptr;
155    }
156
157    int creationflag = OPEN_EXISTING;
158    if(oflag & O_CREAT) {
159        creationflag = OPEN_ALWAYS;
160    }
161
162    HANDLE os_handle = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
163                                   FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ,
164                                   NULL, creationflag, 0, NULL);
165
166    if(os_handle == INVALID_HANDLE_VALUE) {
167        DWORD last_error = save_windows_error(errinfo);
168        if(last_error == ERROR_FILE_NOT_FOUND ||
169                last_error == ERROR_SUCCESS) {
170            return COUCHSTORE_ERROR_NO_SUCH_FILE;
171        };
172        return COUCHSTORE_ERROR_OPEN_FILE;
173    }
174    /* Tell the caller about the new handle (file descriptor) */
175    file = new File(os_handle);
176    *handle = reinterpret_cast<couch_file_handle>(file);
177    return COUCHSTORE_SUCCESS;
178}
179
180couchstore_error_t WindowsFileOps::close(couchstore_error_info_t* errinfo,
181                                         couch_file_handle handle)
182{
183    auto* file = to_file(handle);
184    if(!CloseHandle(file->fh)) {
185        save_windows_error(errinfo);
186        return COUCHSTORE_ERROR_FILE_CLOSE;
187    }
188    return COUCHSTORE_SUCCESS;
189}
190
191cs_off_t WindowsFileOps::goto_eof(couchstore_error_info_t* errinfo,
192                                  couch_file_handle handle)
193{
194    auto* file = to_file(handle);
195    LARGE_INTEGER size;
196    if(!GetFileSizeEx(file->fh, &size)) {
197        save_windows_error(errinfo);
198        return (cs_off_t) COUCHSTORE_ERROR_READ;
199    }
200    return size.QuadPart;
201}
202
203
204couchstore_error_t WindowsFileOps::sync(couchstore_error_info_t* errinfo,
205                                        couch_file_handle handle)
206{
207    auto* file = to_file(handle);
208
209    if (!FlushFileBuffers(file->fh)) {
210        save_windows_error(errinfo);
211        return COUCHSTORE_ERROR_WRITE;
212    }
213
214    return COUCHSTORE_SUCCESS;
215}
216
217couch_file_handle WindowsFileOps::constructor(couchstore_error_info_t* errinfo)
218{
219
220    /*  We don't have a file descriptor till couch_open runs,
221        so return an invalid value for now. */
222    return reinterpret_cast<couch_file_handle>(new File());
223}
224
225void WindowsFileOps::destructor(couch_file_handle handle)
226{
227    auto* file = to_file(handle);
228    delete file;
229}
230
231couchstore_error_t WindowsFileOps::advise(couchstore_error_info_t* errinfo,
232                                          couch_file_handle handle,
233                                          cs_off_t offset,
234                                          cs_off_t len,
235                                          couchstore_file_advice_t advice)
236{
237    return COUCHSTORE_SUCCESS;
238}
239
240WindowsFileOps default_file_ops;
241
242LIBCOUCHSTORE_API
243FileOpsInterface* couchstore_get_default_file_ops(void)
244{
245    return &default_file_ops;
246}
247
248LIBCOUCHSTORE_API
249FileOpsInterface* create_default_file_ops(void)
250{
251    return new WindowsFileOps();
252}
253