"Fossies" - the Fresh Open Source Software Archive

Member "genius-1.0.24/vte/src/vtestream-file.h" (16 Aug 2011, 6873 Bytes) of package /linux/misc/genius-1.0.24.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vtestream-file.h" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) 2009,2010 Red Hat, Inc.
    3  *
    4  * This is free software; you can redistribute it and/or modify it under
    5  * the terms of the GNU Library General Public License as published by
    6  * the Free Software Foundation; either version 2 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful, but
   10  * WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12  * General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU Library General Public
   15  * License along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   17  *
   18  * Red Hat Author(s): Behdad Esfahbod
   19  */
   20 
   21 #include <string.h>
   22 #include <unistd.h>
   23 #include <errno.h>
   24 
   25 #include <gio/gunixinputstream.h>
   26 
   27 static gsize
   28 _xread (int fd, char *data, gsize len)
   29 {
   30     gsize ret, total = 0;
   31 
   32     if (G_UNLIKELY (len && !fd))
   33         return 0;
   34 
   35     while (len) {
   36         ret = read (fd, data, len);
   37         if (G_UNLIKELY (ret == (gsize) -1)) {
   38             if (errno == EINTR)
   39                 continue;
   40             else
   41                 break;
   42         }
   43         if (G_UNLIKELY (ret == 0))
   44             break;
   45         data += ret;
   46         len -= ret;
   47         total += ret;
   48     }
   49     return total;
   50 }
   51 
   52 static void
   53 _xwrite (int fd, const char *data, gsize len)
   54 {
   55     gsize ret;
   56 
   57     g_assert (fd || !len);
   58 
   59     while (len) {
   60         ret = write (fd, data, len);
   61         if (G_UNLIKELY (ret == (gsize) -1)) {
   62             if (errno == EINTR)
   63                 continue;
   64             else
   65                 break;
   66         }
   67         if (G_UNLIKELY (ret == 0))
   68             break;
   69         data += ret;
   70         len -= ret;
   71     }
   72 }
   73 
   74 static void
   75 _xtruncate (gint fd, gsize offset)
   76 {
   77     int ret;
   78 
   79     if (G_UNLIKELY (!fd))
   80         return;
   81 
   82     do {
   83         ret = ftruncate (fd, offset);
   84     } while (ret == -1 && errno == EINTR);
   85 }
   86 
   87 static gboolean
   88 _xwrite_contents (gint fd, GOutputStream *output, GCancellable *cancellable, GError **error)
   89 {
   90     gboolean ret;
   91     GInputStream *input;
   92 
   93     if (G_UNLIKELY (!fd))
   94         return TRUE;
   95 
   96     input = g_unix_input_stream_new (fd, FALSE);
   97     ret = -1 != g_output_stream_splice (output, input, G_OUTPUT_STREAM_SPLICE_NONE, cancellable, error);
   98     g_object_unref (input);
   99 
  100     return ret;
  101 }
  102 
  103 
  104 /*
  105  * VteFileStream: A POSIX file-based stream
  106  */
  107 
  108 typedef struct _VteFileStream {
  109     VteStream parent;
  110 
  111     /* The first fd/offset is for the write head, second is for last page */
  112     gint fd[2];
  113     gsize offset[2];
  114 } VteFileStream;
  115 
  116 typedef VteStreamClass VteFileStreamClass;
  117 
  118 static GType _vte_file_stream_get_type (void);
  119 #define VTE_TYPE_FILE_STREAM _vte_file_stream_get_type ()
  120 
  121 G_DEFINE_TYPE (VteFileStream, _vte_file_stream, VTE_TYPE_STREAM)
  122 
  123 static void
  124 _vte_file_stream_init (VteFileStream *stream G_GNUC_UNUSED)
  125 {
  126 }
  127 
  128 VteStream *
  129 _vte_file_stream_new (void)
  130 {
  131     return (VteStream *) g_object_new (VTE_TYPE_FILE_STREAM, NULL);
  132 }
  133 
  134 static void
  135 _vte_file_stream_finalize (GObject *object)
  136 {
  137     VteFileStream *stream = (VteFileStream *) object;
  138 
  139     if (stream->fd[0]) close (stream->fd[0]);
  140     if (stream->fd[1]) close (stream->fd[1]);
  141 
  142     G_OBJECT_CLASS (_vte_file_stream_parent_class)->finalize(object);
  143 }
  144 
  145 static inline void
  146 _vte_file_stream_ensure_fd0 (VteFileStream *stream)
  147 {
  148     gint fd;
  149     gchar *file_name;
  150     if (G_LIKELY (stream->fd[0]))
  151         return;
  152 
  153     fd = g_file_open_tmp ("vteXXXXXX", &file_name, NULL);
  154     if (fd != -1) {
  155         unlink (file_name);
  156         g_free (file_name);
  157     }
  158 
  159     stream->fd[0] = dup (fd); /* we do the dup to make sure ->fd[0] is not 0 */
  160 
  161     close (fd);
  162 }
  163 
  164 static void
  165 _vte_file_stream_reset (VteStream *astream, gsize offset)
  166 {
  167     VteFileStream *stream = (VteFileStream *) astream;
  168 
  169     if (stream->fd[0]) _xtruncate (stream->fd[0], 0);
  170     if (stream->fd[1]) _xtruncate (stream->fd[1], 0);
  171 
  172     stream->offset[0] = stream->offset[1] = offset;
  173 }
  174 
  175 static gsize
  176 _vte_file_stream_append (VteStream *astream, const char *data, gsize len)
  177 {
  178     VteFileStream *stream = (VteFileStream *) astream;
  179     gsize ret;
  180 
  181     _vte_file_stream_ensure_fd0 (stream);
  182 
  183     ret = lseek (stream->fd[0], 0, SEEK_END);
  184     _xwrite (stream->fd[0], data, len);
  185 
  186     return stream->offset[0] + ret;
  187 }
  188 
  189 static gboolean
  190 _vte_file_stream_read (VteStream *astream, gsize offset, char *data, gsize len)
  191 {
  192     VteFileStream *stream = (VteFileStream *) astream;
  193     gsize l;
  194 
  195     if (G_UNLIKELY (offset < stream->offset[1]))
  196         return FALSE;
  197 
  198     if (offset < stream->offset[0]) {
  199         lseek (stream->fd[1], offset - stream->offset[1], SEEK_SET);
  200         l = _xread (stream->fd[1], data, len);
  201         offset += l; data += l; len -= l; if (!len) return TRUE;
  202     }
  203 
  204     lseek (stream->fd[0], offset - stream->offset[0], SEEK_SET);
  205     l = _xread (stream->fd[0], data, len);
  206     offset += l; data += l; len -= l; if (!len) return TRUE;
  207 
  208     return FALSE;
  209 }
  210 
  211 static void
  212 _vte_file_stream_swap_fds (VteFileStream *stream)
  213 {
  214     gint fd;
  215 
  216     fd = stream->fd[0]; stream->fd[0] = stream->fd[1]; stream->fd[1] = fd;
  217 }
  218 
  219 static void
  220 _vte_file_stream_truncate (VteStream *astream, gsize offset)
  221 {
  222     VteFileStream *stream = (VteFileStream *) astream;
  223 
  224     if (G_UNLIKELY (offset < stream->offset[1])) {
  225         _xtruncate (stream->fd[1], 0);
  226         stream->offset[1] = offset;
  227     }
  228 
  229     if (G_UNLIKELY (offset < stream->offset[0])) {
  230         _xtruncate (stream->fd[0], 0);
  231         stream->offset[0] = stream->offset[1];
  232         _vte_file_stream_swap_fds (stream);
  233     } else {
  234         _xtruncate (stream->fd[0], offset - stream->offset[0]);
  235     }
  236 }
  237 
  238 static void
  239 _vte_file_stream_new_page (VteStream *astream)
  240 {
  241     VteFileStream *stream = (VteFileStream *) astream;
  242 
  243     stream->offset[1] = stream->offset[0];
  244     if (stream->fd[0])
  245         stream->offset[0] += lseek (stream->fd[0], 0, SEEK_END);
  246     _vte_file_stream_swap_fds (stream);
  247     _xtruncate (stream->fd[0], 0);
  248 }
  249 
  250 static gsize
  251 _vte_file_stream_head (VteStream *astream)
  252 {
  253     VteFileStream *stream = (VteFileStream *) astream;
  254 
  255     if (stream->fd[0])
  256         return stream->offset[0] + lseek (stream->fd[0], 0, SEEK_END);
  257     else
  258         return stream->offset[0];
  259 }
  260 
  261 static gboolean
  262 _vte_file_stream_write_contents (VteStream *astream, GOutputStream *output,
  263                  gsize offset,
  264                  GCancellable *cancellable, GError **error)
  265 {
  266     VteFileStream *stream = (VteFileStream *) astream;
  267 
  268     if (G_UNLIKELY (offset < stream->offset[1]))
  269         return FALSE;
  270 
  271     if (offset < stream->offset[0]) {
  272         lseek (stream->fd[1], offset - stream->offset[1], SEEK_SET);
  273         if (!_xwrite_contents (stream->fd[1], output, cancellable, error))
  274             return FALSE;
  275         offset = stream->offset[0];
  276     }
  277 
  278     lseek (stream->fd[0], offset - stream->offset[0], SEEK_SET);
  279     return _xwrite_contents (stream->fd[0], output, cancellable, error);
  280 }
  281 
  282 static void
  283 _vte_file_stream_class_init (VteFileStreamClass *klass)
  284 {
  285     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  286 
  287     gobject_class->finalize = _vte_file_stream_finalize;
  288 
  289     klass->reset = _vte_file_stream_reset;
  290     klass->append = _vte_file_stream_append;
  291     klass->read = _vte_file_stream_read;
  292     klass->truncate = _vte_file_stream_truncate;
  293     klass->new_page = _vte_file_stream_new_page;
  294     klass->head = _vte_file_stream_head;
  295     klass->write_contents = _vte_file_stream_write_contents;
  296 }