xref: /4.0.0/couchstore/src/os.c (revision f93a380c)
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
15static void save_errno(couchstore_error_info_t *errinfo) {
16    if (errinfo) {
17        errinfo->error = errno;
18    }
19}
20
21static int handle_to_fd(couch_file_handle handle)
22{
23    return (int)(intptr_t)handle;
24}
25
26static couch_file_handle fd_to_handle(int fd)
27{
28    return (couch_file_handle)(intptr_t)fd;
29}
30
31static ssize_t couch_pread(couchstore_error_info_t *errinfo,
32                           couch_file_handle handle,
33                           void *buf,
34                           size_t nbyte,
35                           cs_off_t offset)
36{
37#ifdef LOG_IO
38    fprintf(stderr, "PREAD  %8llx -- %8llx  (%6.1f kbytes)\n", offset, offset+nbyte, nbyte/1024.0);
39#endif
40    int fd = handle_to_fd(handle);
41    ssize_t rv;
42    do {
43        rv = pread(fd, buf, nbyte, offset);
44    } while (rv == -1 && errno == EINTR);
45
46    if (rv < 0) {
47        save_errno(errinfo);
48        return (ssize_t) COUCHSTORE_ERROR_READ;
49    }
50    return rv;
51}
52
53static ssize_t couch_pwrite(couchstore_error_info_t *errinfo,
54                            couch_file_handle handle,
55                            const void *buf,
56                            size_t nbyte,
57                            cs_off_t offset)
58{
59#ifdef LOG_IO
60    fprintf(stderr, "PWRITE %8llx -- %8llx  (%6.1f kbytes)\n", offset, offset+nbyte, nbyte/1024.0);
61#endif
62    int fd = handle_to_fd(handle);
63    ssize_t rv;
64    do {
65        rv = pwrite(fd, buf, nbyte, offset);
66    } while (rv == -1 && errno == EINTR);
67
68    if (rv < 0) {
69        save_errno(errinfo);
70        return (ssize_t) COUCHSTORE_ERROR_WRITE;
71    }
72    return rv;
73}
74
75static couchstore_error_t couch_open(couchstore_error_info_t *errinfo,
76                                     couch_file_handle* handle,
77                                     const char *path,
78                                     int oflag)
79{
80    int fd;
81    do {
82        fd = open(path, oflag | O_LARGEFILE, 0666);
83    } while (fd == -1 && errno == EINTR);
84
85    if (fd < 0) {
86        save_errno(errinfo);
87        if (errno == ENOENT) {
88            return COUCHSTORE_ERROR_NO_SUCH_FILE;
89        } else {
90            return COUCHSTORE_ERROR_OPEN_FILE;
91        }
92    }
93    /* Tell the caller about the new handle (file descriptor) */
94    *handle = fd_to_handle(fd);
95    return COUCHSTORE_SUCCESS;
96}
97
98static void couch_close(couchstore_error_info_t *errinfo,
99                        couch_file_handle handle)
100{
101    int fd = handle_to_fd(handle);
102    int rv = 0;
103
104    if (fd != -1) {
105        do {
106            assert(fd >= 3);
107            rv = close(fd);
108        } while (rv == -1 && errno == EINTR);
109    }
110    if (rv < 0) {
111        save_errno(errinfo);
112    }
113}
114
115static cs_off_t couch_goto_eof(couchstore_error_info_t *errinfo,
116                               couch_file_handle handle)
117{
118    int fd = handle_to_fd(handle);
119    cs_off_t rv = lseek(fd, 0, SEEK_END);
120    if (rv < 0) {
121        save_errno(errinfo);
122    }
123    return rv;
124}
125
126
127static couchstore_error_t couch_sync(couchstore_error_info_t *errinfo,
128                                     couch_file_handle handle)
129{
130    int fd = handle_to_fd(handle);
131    int rv;
132    do {
133#ifdef __FreeBSD__
134        rv = fsync(fd);
135#else
136        rv = fdatasync(fd);
137#endif
138    } while (rv == -1 && errno == EINTR);
139
140    if (rv == -1) {
141        save_errno(errinfo);
142        return COUCHSTORE_ERROR_WRITE;
143    }
144
145    return COUCHSTORE_SUCCESS;
146}
147
148static couch_file_handle couch_constructor(couchstore_error_info_t *errinfo,
149                                           void* cookie)
150{
151    (void) cookie;
152    (void)errinfo;
153    /*
154    ** We don't have a file descriptor till couch_open runs, so return
155    ** an invalid value for now.
156    */
157    return fd_to_handle(-1);
158}
159
160static void couch_destructor(couchstore_error_info_t *errinfo,
161                             couch_file_handle handle)
162{
163    /* nothing to do here */
164    (void)handle;
165    (void)errinfo;
166}
167
168static couchstore_error_t couch_advise(couchstore_error_info_t *errinfo,
169                                       couch_file_handle handle,
170                                       cs_off_t offset,
171                                       cs_off_t len,
172                                       couchstore_file_advice_t advice)
173{
174#ifdef POSIX_FADV_NORMAL
175    int fd = handle_to_fd(handle);
176    int error = posix_fadvise(fd, offset, len, (int) advice);
177    if (error != 0) {
178        save_errno(errinfo);
179    }
180    switch(error) {
181        case EINVAL:
182        case ESPIPE:
183            return COUCHSTORE_ERROR_INVALID_ARGUMENTS;
184            break;
185        case EBADF:
186            return COUCHSTORE_ERROR_OPEN_FILE;
187            break;
188    }
189#else
190    (void) handle; (void)offset; (void)len; (void)advice;
191    (void)errinfo;
192#endif
193    return COUCHSTORE_SUCCESS;
194}
195
196static const couch_file_ops default_file_ops = {
197    (uint64_t)5,
198    couch_constructor,
199    couch_open,
200    couch_close,
201    couch_pread,
202    couch_pwrite,
203    couch_goto_eof,
204    couch_sync,
205    couch_advise,
206    couch_destructor,
207    NULL
208};
209
210LIBCOUCHSTORE_API
211const couch_file_ops *couchstore_get_default_file_ops(void)
212{
213    return &default_file_ops;
214}
215