1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2010 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 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <stdint.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "filemgr.h"
27 #include "filemgr_ops.h"
28 
29 #if defined(WIN32) || defined(_WIN32)
30 #include <windows.h>
31 #include <io.h>
32 
handle_to_win(int fd)33 static inline HANDLE handle_to_win(int fd)
34 {
35     return (HANDLE)_get_osfhandle(fd);
36 }
37 
_filemgr_win_open(const char *pathname, int flags, mode_t mode)38 int _filemgr_win_open(const char *pathname, int flags, mode_t mode)
39 {
40 #ifdef _MSC_VER
41     int fd = _open(pathname, flags, mode);
42     if (fd < 0) {
43         errno_t err;
44         _get_errno(&err);
45         return (int) convert_errno_to_fdb_status(err, FDB_RESULT_OPEN_FAIL);
46     }
47     return fd;
48 #else
49     int fd;
50     do {
51         fd = open(pathname, flags | O_LARGEFILE, mode);
52     } while (fd == -1 && errno == EINTR);
53 
54     if (fd < 0) {
55         return (int) convert_errno_to_fdb_status(errno, FDB_RESULT_OPEN_FAIL)
56     }
57     return fd;
58 #endif
59 }
60 
_filemgr_win_pwrite(int fd, void *buf, size_t count, cs_off_t offset)61 ssize_t _filemgr_win_pwrite(int fd, void *buf, size_t count, cs_off_t offset)
62 {
63     HANDLE file = handle_to_win(fd);
64     BOOL rv;
65     DWORD byteswritten;
66     OVERLAPPED winoffs;
67     memset(&winoffs, 0, sizeof(winoffs));
68     winoffs.Offset = offset & 0xFFFFFFFF;
69     winoffs.OffsetHigh = ((uint64_t)offset >> 32) & 0x7FFFFFFF;
70     rv = WriteFile(file, buf, count, &byteswritten, &winoffs);
71     if(!rv) {
72 #ifdef _MSC_VER
73         errno_t err;
74         _get_errno(&err);
75         return (ssize_t) convert_errno_to_fdb_status(err, FDB_RESULT_WRITE_FAIL);
76 #else
77         return (sszie_t) convert_errno_to_fdb_status(errno, FDB_RESULT_WRITE_FAIL);
78 #endif
79     }
80     return (ssize_t) byteswritten;
81 }
82 
_filemgr_win_pread(int fd, void *buf, size_t count, cs_off_t offset)83 ssize_t _filemgr_win_pread(int fd, void *buf, size_t count, cs_off_t offset)
84 {
85     HANDLE file = handle_to_win(fd);
86     BOOL rv;
87     DWORD bytesread;
88     OVERLAPPED winoffs;
89     memset(&winoffs, 0, sizeof(winoffs));
90     winoffs.Offset = offset & 0xFFFFFFFF;
91     winoffs.OffsetHigh = ((uint64_t)offset >> 32) & 0x7FFFFFFF;
92     rv = ReadFile(file, buf, count, &bytesread, &winoffs);
93     if(!rv) {
94 #ifdef _MSC_VER
95         errno_t err;
96         _get_errno(&err);
97         return (ssize_t) convert_errno_to_fdb_status(err, FDB_RESULT_READ_FAIL);
98 #else
99         return (ssize_t) convert_errno_to_fdb_status(errno, FDB_RESULT_READ_FAIL);
100 #endif
101     }
102     return (ssize_t) bytesread;
103 }
104 
_filemgr_win_close(int fd)105 int _filemgr_win_close(int fd)
106 {
107 #ifdef _MSC_VER
108     int rv = 0;
109     if (fd != -1) {
110         rv = _close(fd);
111     }
112 
113     if (rv < 0) {
114         errno_t err;
115         _get_errno(&err);
116         return (int) convert_errno_to_fdb_status(err, FDB_RESULT_CLOSE_FAIL);
117     }
118     return FDB_RESULT_SUCCESS;
119 #else
120     int rv = 0;
121     if (fd != -1) {
122         do {
123             rv = close(fd);
124         } while (rv == -1 && errno == EINTR);
125     }
126 
127     if (rv < 0) {
128         return (int) convert_errno_to_fdb_status(errno, FDB_RESULT_CLOSE_FAIL);
129     }
130     return FDB_RESULT_SUCCESS;
131 #endif
132 }
133 
_filemgr_win_goto_eof(int fd)134 cs_off_t _filemgr_win_goto_eof(int fd)
135 {
136 #ifdef _MSC_VER
137     cs_off_t rv = _lseeki64(fd, 0, SEEK_END);
138     if (rv < 0) {
139         errno_t err;
140         _get_errno(&err);
141         return (cs_off_t) convert_errno_to_fdb_status(err, FDB_RESULT_SEEK_FAIL);
142     }
143     return rv;
144 #else
145     cs_off_t rv = lseek(fd, 0, SEEK_END);
146     if (rv < 0) {
147         return (cs_off_t) convert_errno_to_fdb_status(errno, FDB_RESULT_SEEK_FAIL);
148     }
149     return rv;
150 #endif
151 }
152 
_filemgr_win_file_size(const char *filename)153 cs_off_t _filemgr_win_file_size(const char *filename)
154 {
155 #ifdef _MSC_VER
156     struct _stat st;
157     if (_stat(filename, &st) == -1) {
158         errno_t err;
159         _get_errno(&err);
160         return (cs_off_t) convert_errno_to_fdb_status(err, FDB_RESULT_READ_FAIL);
161     }
162     return st.st_size;
163 #else
164     struct stat st;
165     if (stat(filename, &st) == -1) {
166         return (cs_off_t) convert_errno_to_fdb_status(errno, FDB_RESULT_READ_FAIL);
167     }
168     return st.st_size;
169 #endif
170 }
171 
_filemgr_win_fsync(int fd)172 int _filemgr_win_fsync(int fd)
173 {
174     HANDLE file = handle_to_win(fd);
175 
176     if (!FlushFileBuffers(file)) {
177 #ifdef _MSC_VER
178         errno_t err;
179         _get_errno(&err);
180         return (int) convert_errno_to_fdb_status(err, FDB_RESULT_FSYNC_FAIL);
181 #else
182         return (int) convert_errno_to_fdb_status(errno, FDB_RESULT_FSYNC_FAIL);
183 #endif
184     }
185     return FDB_RESULT_SUCCESS;
186 }
187 
_filemgr_win_fdatasync(int fd)188 int _filemgr_win_fdatasync(int fd)
189 {
190     return _filemgr_win_fsync(fd);
191 }
192 
_filemgr_win_get_errno_str(char *buf, size_t size)193 void _filemgr_win_get_errno_str(char *buf, size_t size)
194 {
195     if (!buf) {
196         return;
197     }
198 
199     char* win_msg = NULL;
200     DWORD err = GetLastError();
201     FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
202                    FORMAT_MESSAGE_FROM_SYSTEM |
203                    FORMAT_MESSAGE_IGNORE_INSERTS,
204                    NULL, err,
205                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
206                    (LPTSTR) &win_msg,
207                    0, NULL);
208     _snprintf(buf, size, "errno = %d: '%s'", err, win_msg);
209     LocalFree(win_msg);
210 }
211 
_filemgr_aio_init(struct async_io_handle *aio_handle)212 int _filemgr_aio_init(struct async_io_handle *aio_handle)
213 {
214     return FDB_RESULT_AIO_NOT_SUPPORTED;
215 }
216 
_filemgr_aio_prep_read(struct async_io_handle *aio_handle, size_t aio_idx, size_t read_size, uint64_t offset)217 int _filemgr_aio_prep_read(struct async_io_handle *aio_handle, size_t aio_idx,
218                             size_t read_size, uint64_t offset)
219 {
220     return FDB_RESULT_AIO_NOT_SUPPORTED;
221 }
222 
_filemgr_aio_submit(struct async_io_handle *aio_handle, int num_subs)223 int _filemgr_aio_submit(struct async_io_handle *aio_handle, int num_subs)
224 {
225     return FDB_RESULT_AIO_NOT_SUPPORTED;
226 }
227 
_filemgr_aio_getevents(struct async_io_handle *aio_handle, int min, int max, unsigned int timeout)228 int _filemgr_aio_getevents(struct async_io_handle *aio_handle, int min,
229                            int max, unsigned int timeout)
230 {
231     return FDB_RESULT_AIO_NOT_SUPPORTED;
232 }
233 
_filemgr_aio_destroy(struct async_io_handle *aio_handle)234 int _filemgr_aio_destroy(struct async_io_handle *aio_handle)
235 {
236     return FDB_RESULT_AIO_NOT_SUPPORTED;
237 }
238 
_filemgr_win_get_fs_type(int src_fd)239 int _filemgr_win_get_fs_type(int src_fd)
240 {
241     return FILEMGR_FS_NO_COW;
242 }
243 
_filemgr_win_copy_file_range(int fstype, int src_fd, int dst_fd, uint64_t src_off, uint64_t dst_off, uint64_t len)244 int _filemgr_win_copy_file_range(int fstype, int src_fd, int dst_fd,
245                                  uint64_t src_off, uint64_t dst_off,
246                                  uint64_t len)
247 {
248     return FDB_RESULT_INVALID_ARGS;
249 }
250 
251 struct filemgr_ops win_ops = {
252     _filemgr_win_open,
253     _filemgr_win_pwrite,
254     _filemgr_win_pread,
255     _filemgr_win_close,
256     _filemgr_win_goto_eof,
257     _filemgr_win_file_size,
258     _filemgr_win_fdatasync,
259     _filemgr_win_fsync,
260     _filemgr_win_get_errno_str,
261     // Async I/O operations
262     _filemgr_aio_init,
263     _filemgr_aio_prep_read,
264     _filemgr_aio_submit,
265     _filemgr_aio_getevents,
266     _filemgr_aio_destroy,
267     _filemgr_win_get_fs_type,
268     _filemgr_win_copy_file_range
269 };
270 
get_win_filemgr_ops()271 struct filemgr_ops * get_win_filemgr_ops()
272 {
273     return &win_ops;
274 }
275 
276 #endif
277