static void gsf_output_stdio_init (GObject *obj) { GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (obj); stdio->file = NULL; stdio->create_backup_copy = FALSE; stdio->keep_open = FALSE; }
static void gsf_output_stdio_finalize (GObject *obj) { GsfOutput *output = (GsfOutput *)obj; GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output); if (!gsf_output_is_closed (output)) gsf_output_close (output); g_free (stdio->real_filename); stdio->real_filename = NULL; g_free (stdio->temp_filename); stdio->temp_filename = NULL; parent_class->finalize (obj); }
static gboolean gsf_output_stdio_seek (GsfOutput *output, gsf_off_t offset, GSeekType whence) { GsfOutputStdio const *stdio = GSF_OUTPUT_STDIO (output); int stdio_whence = 0; /* make compiler shut up */ #ifndef HAVE_FSEEKO long loffset; #else off_t loffset; #endif g_return_val_if_fail (stdio->file != NULL, gsf_output_set_error (output, 0, "missing file")); loffset = offset; if ((gsf_off_t) loffset != offset) { /* Check for overflow */ #ifdef HAVE_FSEEKO g_warning ("offset too large for fseeko"); return gsf_output_set_error (output, 0, "offset too large for fseeko"); #else g_warning ("offset too large for fseek"); return gsf_output_set_error (output, 0, "offset too large for fseek"); #endif } switch (whence) { default : ; /*checked in GsfOutput wrapper */ case G_SEEK_SET : stdio_whence = SEEK_SET; break; case G_SEEK_CUR : stdio_whence = SEEK_CUR; break; case G_SEEK_END : stdio_whence = SEEK_END; break; } errno = 0; #ifdef HAVE_FSEEKO if (0 == fseeko (stdio->file, loffset, stdio_whence)) return TRUE; #else if (0 == fseek (stdio->file, loffset, stdio_whence)) return TRUE; #endif return gsf_output_set_error (output, errno, "%s", g_strerror (errno)); }
static gboolean gsf_output_stdio_write (GsfOutput *output, size_t num_bytes, guint8 const *buffer) { GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output); size_t written, remaining; g_return_val_if_fail (stdio != NULL, FALSE); g_return_val_if_fail (stdio->file != NULL, FALSE); remaining = num_bytes; while (remaining > 0) { written = fwrite (buffer + (num_bytes - remaining), 1, remaining, stdio->file); if ((written < remaining) && ferror (stdio->file) != 0) return gsf_output_set_error (output, errno, "%s", g_strerror (errno)); remaining -= written; } return TRUE; }
static gboolean gsf_output_stdio_close (GsfOutput *output) { GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output); gboolean res; char *backup_filename = NULL; GDateTime *modtime; if (stdio->file == NULL) return FALSE; if (gsf_output_error (output)) { res = TRUE; if (!stdio->keep_open && !close_file_helper (stdio, FALSE)) res = FALSE; if (!unlink_file_helper (stdio)) res = FALSE; return res; } if (stdio->keep_open) { gboolean res = (0 == fflush (stdio->file)); if (!res) gsf_output_set_error (output, errno, "Failed to flush."); stdio->file = NULL; return res; } res = close_file_helper (stdio, TRUE); /* short circuit our when dealing with raw FILE */ if (!stdio->real_filename) return res; if (!res) { unlink_file_helper (stdio); return FALSE; } /* Move the original file to a backup */ if (stdio->create_backup_copy) { gint result; backup_filename = g_strconcat (stdio->real_filename, ".bak", NULL); result = rename_wrapper (stdio->real_filename, backup_filename); if (result != 0) { char *utf8name = g_filename_display_name (backup_filename); gsf_output_set_error (output, errno, "Could not backup the original as %s.", utf8name); g_free (utf8name); g_unlink (stdio->temp_filename); res = FALSE; goto out; } } /* Move the temp file to the original file */ if (rename_wrapper (stdio->temp_filename, stdio->real_filename) != 0) { gint saved_errno = errno; if (backup_filename != NULL && rename_wrapper (backup_filename, stdio->real_filename) != 0) saved_errno = errno; res = gsf_output_set_error (output, saved_errno, "%s", g_strerror (saved_errno)); goto out; } modtime = gsf_output_get_modtime (output); if (modtime) { #ifdef UTIME_AVAILABLE struct utimbuf ut; ut.actime = time (NULL); ut.modtime = g_date_time_to_unix (modtime); /* Ignore errors */ /* utimes() provides better accuracy, but doesn't have gstdio version. gio seems to provide access. */ (void)utime (stdio->real_filename, &ut); #endif } /* Restore permissions. There is not much error checking we * can do here, I'm afraid. The final data is saved anyways. * Note the order: mode, uid+gid, gid, uid, mode. */ g_chmod (stdio->real_filename, stdio->st.st_mode); #ifdef HAVE_CHOWN if (chown_wrapper (stdio->real_filename, stdio->st.st_uid, stdio->st.st_gid)) { /* We cannot set both. Maybe we can set one. */ chown_wrapper (stdio->real_filename, -1, stdio->st.st_gid); chown_wrapper (stdio->real_filename, stdio->st.st_uid, -1); } g_chmod (stdio->real_filename, stdio->st.st_mode); #endif out: g_free (backup_filename); return res; }
static gboolean gsf_output_stdio_close (GsfOutput *output) { GsfOutputStdio *stdio = GSF_OUTPUT_STDIO (output); gboolean res; char *backup_filename = NULL; if (stdio->file == NULL) return FALSE; if (gsf_output_error (output)) { res = TRUE; if (!stdio->keep_open && !close_file_helper (stdio, FALSE)) res = FALSE; if (!unlink_file_helper (stdio)) res = FALSE; return res; } if (stdio->keep_open) { gboolean res = (0 == fflush (stdio->file)); if (!res) gsf_output_set_error (output, errno, "Failed to flush."); stdio->file = NULL; return res; } res = close_file_helper (stdio, TRUE); /* short circuit our when dealing with raw FILE */ if (!stdio->real_filename) return res; if (!res) { unlink_file_helper (stdio); return FALSE; } /* Move the original file to a backup */ if (stdio->create_backup_copy) { gint result; backup_filename = g_strconcat (stdio->real_filename, ".bak", NULL); result = rename_wrapper (stdio->real_filename, backup_filename); if (result != 0) { char *utf8name = g_filename_display_name (backup_filename); gsf_output_set_error (output, errno, "Could not backup the original as %s.", utf8name); g_free (utf8name); g_free (backup_filename); g_unlink (stdio->temp_filename); return FALSE; } } /* Move the temp file to the original file */ if (rename_wrapper (stdio->temp_filename, stdio->real_filename) != 0) { gint saved_errno = errno; if (backup_filename != NULL && rename_wrapper (backup_filename, stdio->real_filename) != 0) saved_errno = errno; res = gsf_output_set_error (output, saved_errno, "%s", g_strerror (saved_errno)); } else { /* Restore permissions. There is not much error checking we * can do here, I'm afraid. The final data is saved anyways. * Note the order: mode, uid+gid, gid, uid, mode. */ chmod_wrapper (stdio->real_filename, stdio->st.st_mode); #ifdef HAVE_CHOWN if (chown (stdio->real_filename, stdio->st.st_uid, stdio->st.st_gid)) { /* We cannot set both. Maybe we can set one. */ chown (stdio->real_filename, -1, stdio->st.st_gid); chown (stdio->real_filename, stdio->st.st_uid, -1); } chmod_wrapper (stdio->real_filename, stdio->st.st_mode); #endif } g_free (backup_filename); return res; }