xref: /4.0.0/couchstore/src/os_win.c (revision ddaf89e7)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#include "config.h"
3#include <assert.h>
4#include <sys/types.h>
5#include <fcntl.h>
6#include <errno.h>
7
8#include "internal.h"
9
10#undef LOG_IO
11#ifdef LOG_IO
12#include <stdio.h>
13#endif
14
15#include <io.h>
16#include <share.h>
17#include <assert.h>
18
19static DWORD save_windows_error(couchstore_error_info_t *errinfo) {
20    DWORD err = GetLastError();
21    if (errinfo) {
22        errinfo->error = err;
23    }
24
25    return err;
26}
27
28static HANDLE handle_to_win(couch_file_handle handle)
29{
30    return (HANDLE)(intptr_t)handle;
31}
32
33static couch_file_handle win_to_handle(HANDLE hdl)
34{
35    return (couch_file_handle)(intptr_t)hdl;
36}
37
38static ssize_t couch_pread(couchstore_error_info_t *errinfo,
39                           couch_file_handle handle,
40                           void *buf,
41                           size_t nbyte,
42                           cs_off_t offset)
43{
44#ifdef LOG_IO
45    fprintf(stderr, "PREAD  %8llx -- %8llx  (%6.1f kbytes)\n", offset, offset+nbyte, nbyte/1024.0);
46#endif
47    HANDLE file = handle_to_win(handle);
48    BOOL rv;
49    DWORD bytesread;
50    OVERLAPPED winoffs;
51    memset(&winoffs, 0, sizeof(winoffs));
52    winoffs.Offset = offset & 0xFFFFFFFF;
53    winoffs.OffsetHigh = (offset >> 32) & 0x7FFFFFFF;
54    rv = ReadFile(file, buf, nbyte, &bytesread, &winoffs);
55    if(!rv) {
56        save_windows_error(errinfo);
57        return (ssize_t) COUCHSTORE_ERROR_READ;
58    }
59    return bytesread;
60}
61
62static ssize_t couch_pwrite(couchstore_error_info_t *errinfo,
63                            couch_file_handle handle,
64                            const void *buf,
65                            size_t nbyte,
66                            cs_off_t offset)
67{
68#ifdef LOG_IO
69    fprintf(stderr, "PWRITE %8llx -- %8llx  (%6.1f kbytes)\n", offset, offset+nbyte, nbyte/1024.0);
70#endif
71    HANDLE file = handle_to_win(handle);
72    BOOL rv;
73    DWORD byteswritten;
74    OVERLAPPED winoffs;
75    memset(&winoffs, 0, sizeof(winoffs));
76    winoffs.Offset = offset & 0xFFFFFFFF;
77    winoffs.OffsetHigh = (offset >> 32) & 0x7FFFFFFF;
78    rv = WriteFile(file, buf, nbyte, &byteswritten, &winoffs);
79    if(!rv) {
80        save_windows_error(errinfo);
81        return (ssize_t) COUCHSTORE_ERROR_WRITE;
82    }
83    return byteswritten;
84}
85
86static couchstore_error_t couch_open(couchstore_error_info_t *errinfo,
87                                     couch_file_handle* handle,
88                                     const char *path,
89                                     int oflag)
90{
91    int creationflag = OPEN_EXISTING;
92    if(oflag & O_CREAT) {
93        creationflag = OPEN_ALWAYS;
94    }
95
96    HANDLE os_handle = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
97                                   FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ,
98                                   NULL, creationflag, 0, NULL);
99
100    if(os_handle == INVALID_HANDLE_VALUE) {
101        DWORD last_error = save_windows_error(errinfo);
102        if(last_error == ERROR_FILE_NOT_FOUND ||
103                last_error == ERROR_SUCCESS) {
104            return (ssize_t) COUCHSTORE_ERROR_NO_SUCH_FILE;
105        };
106        return COUCHSTORE_ERROR_OPEN_FILE;
107    }
108    /* Tell the caller about the new handle (file descriptor) */
109    *handle = win_to_handle(os_handle);
110    return COUCHSTORE_SUCCESS;
111}
112
113static void couch_close(couchstore_error_info_t *errinfo,
114                        couch_file_handle handle)
115{
116    HANDLE file = handle_to_win(handle);
117    CloseHandle(handle);
118}
119
120static cs_off_t couch_goto_eof(couchstore_error_info_t *errinfo,
121                               couch_file_handle handle)
122{
123    HANDLE file = handle_to_win(handle);
124    LARGE_INTEGER size;
125    if(!GetFileSizeEx(file, &size)) {
126        save_windows_error(errinfo);
127        return (cs_off_t) COUCHSTORE_ERROR_READ;
128    }
129    return size.QuadPart;
130}
131
132
133static couchstore_error_t couch_sync(couchstore_error_info_t *errinfo,
134                                     couch_file_handle handle)
135{
136    HANDLE file = handle_to_win(handle);
137
138    if (!FlushFileBuffers(file)) {
139        save_windows_error(errinfo);
140        return COUCHSTORE_ERROR_WRITE;
141    }
142
143    return COUCHSTORE_SUCCESS;
144}
145
146static couch_file_handle couch_constructor(couchstore_error_info_t *errinfo,
147                                           void* cookie)
148{
149    (void) cookie;
150    /*  We don't have a file descriptor till couch_open runs,
151        so return an invalid value for now. */
152    return handle_to_win(INVALID_HANDLE_VALUE);
153}
154
155static void couch_destructor(couchstore_error_info_t *errinfo,
156                             couch_file_handle handle)
157{
158    /* nothing to do here */
159    (void)handle;
160}
161
162static couchstore_error_t couch_advise(couchstore_error_info_t *errinfo,
163                                       couch_file_handle handle,
164                                       cs_off_t offset,
165                                       cs_off_t len,
166                                       couchstore_file_advice_t advice) {
167    return COUCHSTORE_SUCCESS;
168}
169
170static const couch_file_ops default_file_ops = {
171    (uint64_t)5,
172    couch_constructor,
173    couch_open,
174    couch_close,
175    couch_pread,
176    couch_pwrite,
177    couch_goto_eof,
178    couch_sync,
179    couch_advise,
180    couch_destructor,
181    NULL
182};
183
184LIBCOUCHSTORE_API
185const couch_file_ops *couchstore_get_default_file_ops(void)
186{
187    return &default_file_ops;
188}
189