summaryrefslogtreecommitdiff
path: root/src/vtestream-file.h
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2013-09-27 18:18:34 -0400
committerBehdad Esfahbod <behdad@behdad.org>2013-09-27 18:18:34 -0400
commita43839c166da7cc0a89bd7eb0b78b991bdff5471 (patch)
treea3dd889baf0569f8330143420e87dbd05c06a92c /src/vtestream-file.h
parentfae64189d5370681dccbe4f96c6f0a86153caa3f (diff)
downloadvte-a43839c166da7cc0a89bd7eb0b78b991bdff5471.tar.gz
[stream-file] Recover from a disk-full situation
Diffstat (limited to 'src/vtestream-file.h')
-rw-r--r--src/vtestream-file.h38
1 files changed, 25 insertions, 13 deletions
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index 6d2371ef..c11a3155 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -48,6 +48,19 @@ pwrite (int fd, char *data, gsize len, gsize offset)
}
#endif
+static void
+_xtruncate (gint fd, gsize offset)
+{
+ int ret;
+
+ if (G_UNLIKELY (!fd))
+ return;
+
+ do {
+ ret = ftruncate (fd, offset);
+ } while (ret == -1 && errno == EINTR);
+}
+
static gsize
_xpread (int fd, char *data, gsize len, gsize offset)
{
@@ -78,6 +91,7 @@ static void
_xpwrite (int fd, const char *data, gsize len, gsize offset)
{
gsize ret;
+ gboolean truncated = FALSE;
g_assert (fd || !len);
@@ -86,6 +100,17 @@ _xpwrite (int fd, const char *data, gsize len, gsize offset)
if (G_UNLIKELY (ret == (gsize) -1)) {
if (errno == EINTR)
continue;
+ else if (errno == EINVAL && !truncated)
+ {
+ /* Perhaps previous writes failed and now we are
+ * seeking past end of file. Try extending it
+ * and retry. This allows recovering from a
+ * "/tmp is full" error.
+ */
+ _xtruncate (fd, offset);
+ truncated = TRUE;
+ continue;
+ }
else
break;
}
@@ -97,19 +122,6 @@ _xpwrite (int fd, const char *data, gsize len, gsize offset)
}
}
-static void
-_xtruncate (gint fd, gsize offset)
-{
- int ret;
-
- if (G_UNLIKELY (!fd))
- return;
-
- do {
- ret = ftruncate (fd, offset);
- } while (ret == -1 && errno == EINTR);
-}
-
static gboolean
_xwrite_contents (gint fd, GOutputStream *output, GCancellable *cancellable, GError **error)
{