/** * gsf_output_close: * @output: #GsfOutput * * Close a stream. * * Returns: %FALSE on error **/ gboolean gsf_output_close (GsfOutput *output) { gboolean res; g_return_val_if_fail (GSF_IS_OUTPUT (output), gsf_output_set_error (output, 0, "<internal>")); g_return_val_if_fail (!output->is_closed, gsf_output_set_error (output, 0, "<internal>")); /* The implementation will log any errors, but we can never try to * close multiple times even on failure. */ res = GET_CLASS (output)->Close (output); output->is_closed = TRUE; return res; }
static inline gboolean gsf_output_inc_cur_offset (GsfOutput *output, gsf_off_t num_bytes) { output->cur_offset += num_bytes; if (output->cur_offset < num_bytes) return gsf_output_set_error (output, 0, "Output size overflow."); if (output->cur_size < output->cur_offset) output->cur_size = output->cur_offset; return TRUE; }
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 close_file_helper (GsfOutputStdio *stdio, gboolean seterr) { gboolean res = (0 == fclose (stdio->file)); stdio->file = NULL; if (!res && seterr) gsf_output_set_error (GSF_OUTPUT (stdio), errno, "Failed to close file: %s", g_strerror (errno)); return res; }
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 void go_plugin_file_saver_save (GOFileSaver const *fs, GOIOContext *io_context, GoView const *view, GsfOutput *output) { GOPluginFileSaver *pfs = GO_PLUGIN_FILE_SAVER (fs); GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (pfs->service); GOErrorInfo *error = NULL; g_return_if_fail (GSF_IS_OUTPUT (output)); go_plugin_service_load (pfs->service, &error); if (error != NULL) { go_io_error_info_set (io_context, error); go_io_error_push (io_context, go_error_info_new_str ( _("Error while loading plugin for saving."))); if (!gsf_output_error (output)) gsf_output_set_error (output, 0, _("Failed to load plugin for saving")); return; } g_return_if_fail (service_file_saver->cbs.plugin_func_file_save != NULL); service_file_saver->cbs.plugin_func_file_save (fs, pfs->service, io_context, view, output); }
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; }