xref: /qemu/io/channel-file.c (revision 401e311f)
1 /*
2  * QEMU I/O channels files driver
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "io/channel-file.h"
23 #include "io/channel-util.h"
24 #include "io/channel-watch.h"
25 #include "qapi/error.h"
26 #include "qemu/module.h"
27 #include "qemu/sockets.h"
28 #include "trace.h"
29 
30 QIOChannelFile *
31 qio_channel_file_new_fd(int fd)
32 {
33     QIOChannelFile *ioc;
34 
35     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
36 
37     ioc->fd = fd;
38 
39     if (lseek(fd, 0, SEEK_CUR) != (off_t)-1) {
40         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
41     }
42 
43     trace_qio_channel_file_new_fd(ioc, fd);
44 
45     return ioc;
46 }
47 
48 
49 QIOChannelFile *
50 qio_channel_file_new_path(const char *path,
51                           int flags,
52                           mode_t mode,
53                           Error **errp)
54 {
55     QIOChannelFile *ioc;
56 
57     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
58 
59     ioc->fd = qemu_open_old(path, flags, mode);
60     if (ioc->fd < 0) {
61         object_unref(OBJECT(ioc));
62         error_setg_errno(errp, errno,
63                          "Unable to open %s", path);
64         return NULL;
65     }
66 
67     if (lseek(ioc->fd, 0, SEEK_CUR) != (off_t)-1) {
68         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
69     }
70 
71     trace_qio_channel_file_new_path(ioc, path, flags, mode, ioc->fd);
72 
73     return ioc;
74 }
75 
76 
77 static void qio_channel_file_init(Object *obj)
78 {
79     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
80     ioc->fd = -1;
81 }
82 
83 static void qio_channel_file_finalize(Object *obj)
84 {
85     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
86     if (ioc->fd != -1) {
87         qemu_close(ioc->fd);
88         ioc->fd = -1;
89     }
90 }
91 
92 
93 static ssize_t qio_channel_file_readv(QIOChannel *ioc,
94                                       const struct iovec *iov,
95                                       size_t niov,
96                                       int **fds,
97                                       size_t *nfds,
98                                       int flags,
99                                       Error **errp)
100 {
101     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
102     ssize_t ret;
103 
104  retry:
105     ret = readv(fioc->fd, iov, niov);
106     if (ret < 0) {
107         if (errno == EAGAIN) {
108             return QIO_CHANNEL_ERR_BLOCK;
109         }
110         if (errno == EINTR) {
111             goto retry;
112         }
113 
114         error_setg_errno(errp, errno,
115                          "Unable to read from file");
116         return -1;
117     }
118 
119     return ret;
120 }
121 
122 static ssize_t qio_channel_file_writev(QIOChannel *ioc,
123                                        const struct iovec *iov,
124                                        size_t niov,
125                                        int *fds,
126                                        size_t nfds,
127                                        int flags,
128                                        Error **errp)
129 {
130     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
131     ssize_t ret;
132 
133  retry:
134     ret = writev(fioc->fd, iov, niov);
135     if (ret <= 0) {
136         if (errno == EAGAIN) {
137             return QIO_CHANNEL_ERR_BLOCK;
138         }
139         if (errno == EINTR) {
140             goto retry;
141         }
142         error_setg_errno(errp, errno,
143                          "Unable to write to file");
144         return -1;
145     }
146     return ret;
147 }
148 
149 static int qio_channel_file_set_blocking(QIOChannel *ioc,
150                                          bool enabled,
151                                          Error **errp)
152 {
153 #ifdef WIN32
154     /* not implemented */
155     error_setg_errno(errp, errno, "Failed to set FD nonblocking");
156     return -1;
157 #else
158     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
159 
160     if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
161         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
162         return -1;
163     }
164     return 0;
165 #endif
166 }
167 
168 
169 static off_t qio_channel_file_seek(QIOChannel *ioc,
170                                    off_t offset,
171                                    int whence,
172                                    Error **errp)
173 {
174     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
175     off_t ret;
176 
177     ret = lseek(fioc->fd, offset, whence);
178     if (ret == (off_t)-1) {
179         error_setg_errno(errp, errno,
180                          "Unable to seek to offset %lld whence %d in file",
181                          (long long int)offset, whence);
182         return -1;
183     }
184     return ret;
185 }
186 
187 
188 static int qio_channel_file_close(QIOChannel *ioc,
189                                   Error **errp)
190 {
191     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
192 
193     if (qemu_close(fioc->fd) < 0) {
194         error_setg_errno(errp, errno,
195                          "Unable to close file");
196         return -1;
197     }
198     fioc->fd = -1;
199     return 0;
200 }
201 
202 
203 static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
204                                                 AioContext *read_ctx,
205                                                 IOHandler *io_read,
206                                                 AioContext *write_ctx,
207                                                 IOHandler *io_write,
208                                                 void *opaque)
209 {
210     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
211 
212     qio_channel_util_set_aio_fd_handler(fioc->fd, read_ctx, io_read,
213                                         fioc->fd, write_ctx, io_write,
214                                         opaque);
215 }
216 
217 static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
218                                               GIOCondition condition)
219 {
220     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
221     return qio_channel_create_fd_watch(ioc,
222                                        fioc->fd,
223                                        condition);
224 }
225 
226 static void qio_channel_file_class_init(ObjectClass *klass,
227                                         void *class_data G_GNUC_UNUSED)
228 {
229     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
230 
231     ioc_klass->io_writev = qio_channel_file_writev;
232     ioc_klass->io_readv = qio_channel_file_readv;
233     ioc_klass->io_set_blocking = qio_channel_file_set_blocking;
234     ioc_klass->io_seek = qio_channel_file_seek;
235     ioc_klass->io_close = qio_channel_file_close;
236     ioc_klass->io_create_watch = qio_channel_file_create_watch;
237     ioc_klass->io_set_aio_fd_handler = qio_channel_file_set_aio_fd_handler;
238 }
239 
240 static const TypeInfo qio_channel_file_info = {
241     .parent = TYPE_QIO_CHANNEL,
242     .name = TYPE_QIO_CHANNEL_FILE,
243     .instance_size = sizeof(QIOChannelFile),
244     .instance_init = qio_channel_file_init,
245     .instance_finalize = qio_channel_file_finalize,
246     .class_init = qio_channel_file_class_init,
247 };
248 
249 static void qio_channel_file_register_types(void)
250 {
251     type_register_static(&qio_channel_file_info);
252 }
253 
254 type_init(qio_channel_file_register_types);
255