qemu/io/channel-file.c
<<
>>
Prefs
   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 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-watch.h"
  24#include "qapi/error.h"
  25#include "qemu/sockets.h"
  26#include "trace.h"
  27
  28QIOChannelFile *
  29qio_channel_file_new_fd(int fd)
  30{
  31    QIOChannelFile *ioc;
  32
  33    ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
  34
  35    ioc->fd = fd;
  36
  37    trace_qio_channel_file_new_fd(ioc, fd);
  38
  39    return ioc;
  40}
  41
  42
  43QIOChannelFile *
  44qio_channel_file_new_path(const char *path,
  45                          int flags,
  46                          mode_t mode,
  47                          Error **errp)
  48{
  49    QIOChannelFile *ioc;
  50
  51    ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
  52
  53    if (flags & O_WRONLY) {
  54        ioc->fd = open(path, flags, mode);
  55    } else {
  56        ioc->fd = open(path, flags);
  57    }
  58    if (ioc->fd < 0) {
  59        object_unref(OBJECT(ioc));
  60        error_setg_errno(errp, errno,
  61                         "Unable to open %s", path);
  62        return NULL;
  63    }
  64
  65    trace_qio_channel_file_new_path(ioc, path, flags, mode, ioc->fd);
  66
  67    return ioc;
  68}
  69
  70
  71static void qio_channel_file_init(Object *obj)
  72{
  73    QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
  74    ioc->fd = -1;
  75}
  76
  77static void qio_channel_file_finalize(Object *obj)
  78{
  79    QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
  80    if (ioc->fd != -1) {
  81        close(ioc->fd);
  82        ioc->fd = -1;
  83    }
  84}
  85
  86
  87static ssize_t qio_channel_file_readv(QIOChannel *ioc,
  88                                      const struct iovec *iov,
  89                                      size_t niov,
  90                                      int **fds,
  91                                      size_t *nfds,
  92                                      Error **errp)
  93{
  94    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
  95    ssize_t ret;
  96
  97 retry:
  98    ret = readv(fioc->fd, iov, niov);
  99    if (ret < 0) {
 100        if (errno == EAGAIN) {
 101            return QIO_CHANNEL_ERR_BLOCK;
 102        }
 103        if (errno == EINTR) {
 104            goto retry;
 105        }
 106
 107        error_setg_errno(errp, errno,
 108                         "Unable to read from file");
 109        return -1;
 110    }
 111
 112    return ret;
 113}
 114
 115static ssize_t qio_channel_file_writev(QIOChannel *ioc,
 116                                       const struct iovec *iov,
 117                                       size_t niov,
 118                                       int *fds,
 119                                       size_t nfds,
 120                                       Error **errp)
 121{
 122    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 123    ssize_t ret;
 124
 125 retry:
 126    ret = writev(fioc->fd, iov, niov);
 127    if (ret <= 0) {
 128        if (errno == EAGAIN) {
 129            return QIO_CHANNEL_ERR_BLOCK;
 130        }
 131        if (errno == EINTR) {
 132            goto retry;
 133        }
 134        error_setg_errno(errp, errno,
 135                         "Unable to write to file");
 136        return -1;
 137    }
 138    return ret;
 139}
 140
 141static int qio_channel_file_set_blocking(QIOChannel *ioc,
 142                                         bool enabled,
 143                                         Error **errp)
 144{
 145    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 146
 147    if (enabled) {
 148        qemu_set_block(fioc->fd);
 149    } else {
 150        qemu_set_nonblock(fioc->fd);
 151    }
 152    return 0;
 153}
 154
 155
 156static off_t qio_channel_file_seek(QIOChannel *ioc,
 157                                   off_t offset,
 158                                   int whence,
 159                                   Error **errp)
 160{
 161    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 162    off_t ret;
 163
 164    ret = lseek(fioc->fd, offset, whence);
 165    if (ret == (off_t)-1) {
 166        error_setg_errno(errp, errno,
 167                         "Unable to seek to offset %lld whence %d in file",
 168                         (long long int)offset, whence);
 169        return -1;
 170    }
 171    return ret;
 172}
 173
 174
 175static int qio_channel_file_close(QIOChannel *ioc,
 176                                  Error **errp)
 177{
 178    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 179
 180    if (close(fioc->fd) < 0) {
 181        error_setg_errno(errp, errno,
 182                         "Unable to close file");
 183        return -1;
 184    }
 185    return 0;
 186}
 187
 188
 189static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
 190                                              GIOCondition condition)
 191{
 192    QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 193    return qio_channel_create_fd_watch(ioc,
 194                                       fioc->fd,
 195                                       condition);
 196}
 197
 198static void qio_channel_file_class_init(ObjectClass *klass,
 199                                        void *class_data G_GNUC_UNUSED)
 200{
 201    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
 202
 203    ioc_klass->io_writev = qio_channel_file_writev;
 204    ioc_klass->io_readv = qio_channel_file_readv;
 205    ioc_klass->io_set_blocking = qio_channel_file_set_blocking;
 206    ioc_klass->io_seek = qio_channel_file_seek;
 207    ioc_klass->io_close = qio_channel_file_close;
 208    ioc_klass->io_create_watch = qio_channel_file_create_watch;
 209}
 210
 211static const TypeInfo qio_channel_file_info = {
 212    .parent = TYPE_QIO_CHANNEL,
 213    .name = TYPE_QIO_CHANNEL_FILE,
 214    .instance_size = sizeof(QIOChannelFile),
 215    .instance_init = qio_channel_file_init,
 216    .instance_finalize = qio_channel_file_finalize,
 217    .class_init = qio_channel_file_class_init,
 218};
 219
 220static void qio_channel_file_register_types(void)
 221{
 222    type_register_static(&qio_channel_file_info);
 223}
 224
 225type_init(qio_channel_file_register_types);
 226