1
Description: use memory-based circular buffer "stream" for the non-infinite
2
scrollback state. This delays stream initialization so that the true size
3
of the desired scrollback state can be discovered. This also means that
4
changing the scrollback size in the middle of using a stream means you
5
won't change the backend stream type.
6
Author: Kees Cook <kees@ubuntu.com>
7
Ubuntu-Bug: https://bugs.launchpad.net/ubuntu/+source/vte/+bug/778872
8
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=664611
10
Index: vte-0.28.2/src/vtestream-mem.h
11
===================================================================
12
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
13
+++ vte-0.28.2/src/vtestream-mem.h 2012-03-07 14:47:42.822382527 -0800
16
+ * Copyright (C) 2009,2010 Red Hat, Inc.
17
+ * Copyright (C) 2012 Kees Cook
19
+ * This is free software; you can redistribute it and/or modify it under
20
+ * the terms of the GNU Library General Public License as published by
21
+ * the Free Software Foundation; either version 2 of the License, or
22
+ * (at your option) any later version.
24
+ * This program is distributed in the hope that it will be useful, but
25
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27
+ * General Public License for more details.
29
+ * You should have received a copy of the GNU Library General Public
30
+ * License along with this program; if not, write to the Free Software
31
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33
+ * Red Hat Author(s): Behdad Esfahbod
34
+ * Ubuntu Authors(s): Kees Cook <kees@ubuntu.com>
41
+#include <gio/gunixinputstream.h>
44
+ * VteMemStream: A memory-based stream
49
+ gsize allocated; /* How much memory exists in the region. */
50
+ gsize length; /* Current length of valid written data in the region. */
51
+ gsize seekpos; /* Where in the region we are positioned from seeking. */
54
+typedef struct _VteMemStream {
57
+ /* The first is for the write head, second is for last page */
58
+ struct mem_region page[2];
59
+ gsize offset[2]; /* Offset into... ? */
62
+typedef VteStreamClass VteMemStreamClass;
64
+static GType _vte_mem_stream_get_type (void);
65
+#define VTE_TYPE_MEM_STREAM _vte_mem_stream_get_type ()
67
+G_DEFINE_TYPE (VteMemStream, _vte_mem_stream, VTE_TYPE_STREAM)
70
+_vte_mem_stream_init (VteMemStream *stream G_GNUC_UNUSED)
75
+_vte_mem_stream_new (void)
77
+ return (VteStream *) g_object_new (VTE_TYPE_MEM_STREAM, NULL);
81
+_vte_mem_stream_finalize (GObject *object)
83
+ VteMemStream *stream = (VteMemStream *) object;
86
+ for (i = 0; i < 2; i ++) {
87
+ if (stream->page[i].region) g_free (stream->page[i].region);
88
+ memset(&stream->page[i], 0, sizeof (stream->page[i]));
89
+ stream->offset[i] = 0;
92
+ G_OBJECT_CLASS (_vte_mem_stream_parent_class)->finalize(object);
96
+_mem_xseek (VteMemStream *stream, gint id, gsize pos, int whence)
98
+ g_assert (id == 0 || id == 1);
102
+ if (pos > stream->page[id].length)
103
+ pos = stream->page[id].length;
104
+ stream->page[id].seekpos = pos;
107
+ stream->page[id].seekpos = stream->page[id].length;
110
+ return stream->page[id].seekpos;
114
+_mem_xread (VteMemStream *stream, gint id, char *data, gsize len)
116
+ g_assert (id == 0 || id == 1);
118
+ if (G_UNLIKELY (len && !stream->page[id].region))
121
+ if (len > stream->page[id].length - stream->page[id].seekpos)
122
+ len = stream->page[id].length - stream->page[id].seekpos;
124
+ g_memmove (data, stream->page[id].region + stream->page[id].seekpos, len);
125
+ stream->page[id].seekpos += len;
131
+_mem_xwrite (VteMemStream *stream, gint id, const char *data, gsize len)
133
+ g_assert (id == 0 || id == 1);
135
+ if (G_UNLIKELY (!stream->page[id].region))
138
+ while (stream->page[id].seekpos + len > stream->page[id].allocated) {
139
+ gsize want = stream->page[id].allocated * 2;
140
+ stream->page[id].region = g_realloc (stream->page[id].region, want);
141
+ /* TODO: handle alloc failure. */
142
+ stream->page[id].allocated = want;
145
+ g_memmove (stream->page[id].region + stream->page[id].seekpos, data, len);
146
+ stream->page[id].seekpos += len;
147
+ if (stream->page[id].seekpos > stream->page[id].length)
148
+ stream->page[id].length = stream->page[id].seekpos;
152
+_mem_xtruncate (VteMemStream *stream, gint id, gsize size)
154
+ g_assert (id == 0 || id == 1);
156
+ if (G_UNLIKELY (!stream->page[id].region))
159
+ /* This only expects the region to be reduced in size. */
160
+ g_assert (size <= stream->page[id].length);
162
+ stream->page[id].region = g_realloc(stream->page[id].region, size);
163
+ /* TODO: handle alloc failure. */
164
+ stream->page[id].length = stream->page[id].allocated = size;
165
+ if (stream->page[id].seekpos > size)
166
+ stream->page[id].seekpos = size;
170
+_mem_xwrite_contents (VteMemStream *stream, gint id, GOutputStream *output,
171
+ GCancellable *cancellable, GError **error)
176
+ g_assert (id == 0 || id == 1);
178
+ if (G_UNLIKELY (!stream->page[id].region))
181
+ ret = g_output_stream_write_all (output,
182
+ stream->page[id].region + stream->page[id].seekpos,
183
+ stream->page[id].length - stream->page[id].seekpos,
184
+ &written, cancellable, error);
185
+ stream->page[id].seekpos = stream->page[id].length;
191
+_vte_mem_stream_reset (VteStream *astream, gsize offset)
193
+ VteMemStream *stream = (VteMemStream *) astream;
195
+ if (stream->page[0].region) _mem_xtruncate (stream, 0, 0);
196
+ if (stream->page[1].region) _mem_xtruncate (stream, 1, 0);
198
+ stream->offset[0] = stream->offset[1] = offset;
202
+_vte_mem_stream_ensure_region0 (VteMemStream *stream)
204
+ if (G_LIKELY (stream->page[0].region))
207
+ stream->page[0].allocated = 4096; /* Arbitrary initial size. */
208
+ stream->page[0].region = g_malloc(stream->page[0].allocated);
209
+ /* TODO: how to handle malloc failure? */
213
+_vte_mem_stream_append (VteStream *astream, const char *data, gsize len)
215
+ VteMemStream *stream = (VteMemStream *) astream;
218
+ _vte_mem_stream_ensure_region0 (stream);
220
+ ret = _mem_xseek (stream, 0, 0, SEEK_END);
221
+ _mem_xwrite (stream, 0, data, len);
223
+ return stream->offset[0] + ret;
227
+_vte_mem_stream_read (VteStream *astream, gsize offset, char *data, gsize len)
229
+ VteMemStream *stream = (VteMemStream *) astream;
232
+ if (G_UNLIKELY (offset < stream->offset[1]))
235
+ if (offset < stream->offset[0]) {
236
+ _mem_xseek (stream, 1, offset - stream->offset[1], SEEK_SET);
237
+ l = _mem_xread (stream, 1, data, len);
238
+ offset += l; data += l; len -= l; if (!len) return TRUE;
241
+ _mem_xseek (stream, 0, offset - stream->offset[0], SEEK_SET);
242
+ l = _mem_xread (stream, 0, data, len);
243
+ offset += l; data += l; len -= l; if (!len) return TRUE;
249
+_vte_mem_stream_swap_regions (VteMemStream *stream)
251
+ struct mem_region temp;
253
+ temp = stream->page[0];
254
+ stream->page[0] = stream->page[1];
255
+ stream->page[1] = temp;
259
+_vte_mem_stream_truncate (VteStream *astream, gsize offset)
261
+ VteMemStream *stream = (VteMemStream *) astream;
263
+ if (G_UNLIKELY (offset < stream->offset[1])) {
264
+ _mem_xtruncate (stream, 1, 0);
265
+ stream->offset[1] = offset;
268
+ if (G_UNLIKELY (offset < stream->offset[0])) {
269
+ _mem_xtruncate (stream, 0, 0);
270
+ stream->offset[0] = stream->offset[1];
271
+ _vte_mem_stream_swap_regions (stream);
273
+ _mem_xtruncate (stream, 0, offset - stream->offset[0]);
278
+_vte_mem_stream_new_page (VteStream *astream)
280
+ VteMemStream *stream = (VteMemStream *) astream;
282
+ stream->offset[1] = stream->offset[0];
283
+ if (stream->page[0].region)
284
+ stream->offset[0] += _mem_xseek (stream, 0, 0, SEEK_END);
285
+ _vte_mem_stream_swap_regions (stream);
286
+ _mem_xtruncate (stream, 0, 0);
290
+_vte_mem_stream_head (VteStream *astream)
292
+ VteMemStream *stream = (VteMemStream *) astream;
294
+ if (stream->page[0].region)
295
+ return stream->offset[0] + _mem_xseek (stream, 0, 0, SEEK_END);
297
+ return stream->offset[0];
301
+_vte_mem_stream_write_contents (VteStream *astream, GOutputStream *output,
303
+ GCancellable *cancellable, GError **error)
305
+ VteMemStream *stream = (VteMemStream *) astream;
307
+ if (G_UNLIKELY (offset < stream->offset[1]))
310
+ if (offset < stream->offset[0]) {
311
+ _mem_xseek (stream, 1, offset - stream->offset[1], SEEK_SET);
312
+ if (!_mem_xwrite_contents (stream, 1, output, cancellable, error))
314
+ offset = stream->offset[0];
317
+ _mem_xseek (stream, 0, offset - stream->offset[0], SEEK_SET);
318
+ return _mem_xwrite_contents (stream, 0, output, cancellable, error);
322
+_vte_mem_stream_class_init (VteMemStreamClass *klass)
324
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
326
+ gobject_class->finalize = _vte_mem_stream_finalize;
328
+ klass->reset = _vte_mem_stream_reset;
329
+ klass->append = _vte_mem_stream_append;
330
+ klass->read = _vte_mem_stream_read;
331
+ klass->truncate = _vte_mem_stream_truncate;
332
+ klass->new_page = _vte_mem_stream_new_page;
333
+ klass->head = _vte_mem_stream_head;
334
+ klass->write_contents = _vte_mem_stream_write_contents;
336
Index: vte-0.28.2/src/vtestream.h
337
===================================================================
338
--- vte-0.28.2.orig/src/vtestream.h 2012-03-07 10:23:14.998517196 -0800
339
+++ vte-0.28.2/src/vtestream.h 2012-03-07 10:23:52.055018606 -0800
343
_vte_file_stream_new (void);
345
+_vte_mem_stream_new (void);
349
Index: vte-0.28.2/src/ring.c
350
===================================================================
351
--- vte-0.28.2.orig/src/ring.c 2012-03-07 11:17:05.896949593 -0800
352
+++ vte-0.28.2/src/ring.c 2012-03-07 14:42:35.626333589 -0800
354
#define _vte_ring_validate(ring) G_STMT_START {} G_STMT_END
358
+_vte_ring_ensure_stream (VteRing *ring)
360
+ if (G_LIKELY(ring->attr_stream))
363
+ if (ring->max >= G_MAXLONG) {
364
+ /* "Infinite" scroll-back buffer limit, file-backed. */
365
+ ring->attr_stream = _vte_file_stream_new ();
366
+ ring->text_stream = _vte_file_stream_new ();
367
+ ring->row_stream = _vte_file_stream_new ();
369
+ /* Predefined scroll-back buffer limit, memory-backed. */
370
+ ring->attr_stream = _vte_mem_stream_new ();
371
+ ring->text_stream = _vte_mem_stream_new ();
372
+ ring->row_stream = _vte_mem_stream_new ();
378
_vte_ring_init (VteRing *ring, gulong max_rows)
381
ring->array = g_malloc0 (sizeof (ring->array[0]) * (ring->mask + 1));
383
- ring->attr_stream = _vte_file_stream_new ();
384
- ring->text_stream = _vte_file_stream_new ();
385
- ring->row_stream = _vte_file_stream_new ();
387
ring->last_attr.text_offset = 0;
388
ring->last_attr.attr.i = basic_cell.i.attr;
389
ring->utf8_buffer = g_string_sized_new (128);
394
+ _vte_ring_ensure_stream (ring);
396
for (i = 0; i <= ring->mask; i++)
397
_vte_row_data_fini (&ring->array[i]);
399
@@ -103,12 +120,14 @@
401
_vte_ring_read_row_record (VteRing *ring, VteRowRecord *record, gulong position)
403
+ _vte_ring_ensure_stream (ring);
404
return _vte_stream_read (ring->row_stream, position * sizeof (*record), (char *) record, sizeof (*record));
408
_vte_ring_append_row_record (VteRing *ring, const VteRowRecord *record, gulong position)
410
+ _vte_ring_ensure_stream (ring);
411
_vte_stream_append (ring->row_stream, (const char *) record, sizeof (*record));
417
_vte_debug_print (VTE_DEBUG_RING, "Freezing row %lu.\n", position);
418
+ _vte_ring_ensure_stream (ring);
420
record.text_offset = _vte_stream_head (ring->text_stream);
421
record.attr_offset = _vte_stream_head (ring->attr_stream);
423
GString *buffer = ring->utf8_buffer;
425
_vte_debug_print (VTE_DEBUG_RING, "Thawing row %lu.\n", position);
426
+ _vte_ring_ensure_stream (ring);
428
_vte_row_data_clear (row);
431
_vte_ring_reset_streams (VteRing *ring, gulong position)
433
_vte_debug_print (VTE_DEBUG_RING, "Reseting streams to %lu.\n", position);
434
+ _vte_ring_ensure_stream (ring);
436
_vte_stream_reset (ring->row_stream, position * sizeof (VteRowRecord));
437
_vte_stream_reset (ring->text_stream, 0);
439
_vte_ring_new_page (VteRing *ring)
441
_vte_debug_print (VTE_DEBUG_RING, "Starting new stream page at %lu.\n", ring->writable);
442
+ _vte_ring_ensure_stream (ring);
444
_vte_stream_new_page (ring->attr_stream);
445
_vte_stream_new_page (ring->text_stream);
449
_vte_debug_print(VTE_DEBUG_RING, "Writing contents to GOutputStream.\n");
450
+ _vte_ring_ensure_stream (ring);
452
if (ring->start < ring->writable) {
454
Index: vte-0.28.2/src/vtestream.c
455
===================================================================
456
--- vte-0.28.2.orig/src/vtestream.c 2012-03-07 11:41:24.427419860 -0800
457
+++ vte-0.28.2/src/vtestream.c 2012-03-07 12:55:14.227826250 -0800
460
#include "vtestream-base.h"
461
#include "vtestream-file.h"
462
+#include "vtestream-mem.h"
463
Index: vte-0.28.2/src/Makefile.am
464
===================================================================
465
--- vte-0.28.2.orig/src/Makefile.am 2012-03-07 12:55:40.912155853 -0800
466
+++ vte-0.28.2/src/Makefile.am 2012-03-07 12:55:49.460261440 -0800