static void photos_glib_file_copy_splice (GObject *source_object, GAsyncResult *res, gpointer user_data) { GOutputStream *ostream = G_OUTPUT_STREAM (source_object); g_autoptr (GTask) task = G_TASK (user_data); PhotosGLibFileCopyData *data; data = (PhotosGLibFileCopyData *) g_task_get_task_data (task); g_assert_true (G_IS_FILE_OUTPUT_STREAM (ostream)); g_assert_true (G_FILE_OUTPUT_STREAM (ostream) == data->ostream); { g_autoptr (GError) error = NULL; g_output_stream_splice_finish (ostream, res, &error); if (error != NULL) { g_task_return_error (task, g_steal_pointer (&error)); goto out; } } g_task_return_pointer (task, g_object_ref (data->unique_file), g_object_unref); out: return; }
GFileOutputStream * _g_local_file_output_stream_new (int fd) { GLocalFileOutputStream *stream; stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; return G_FILE_OUTPUT_STREAM (stream); }
GFileOutputStream * _g_local_file_output_stream_create (const char *filename, gboolean readable, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { GLocalFileOutputStream *stream; int mode; int fd; int open_flags; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; if (flags & G_FILE_CREATE_PRIVATE) mode = 0600; else mode = 0666; open_flags = O_CREAT | O_EXCL | O_BINARY; if (readable) open_flags |= O_RDWR; else open_flags |= O_WRONLY; fd = g_open (filename, open_flags, mode); if (fd == -1) { int errsv = errno; if (errsv == EINVAL) /* This must be an invalid filename, on e.g. FAT */ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, _("Invalid filename")); else { char *display_name = g_filename_display_name (filename); g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error opening file '%s': %s"), display_name, g_strerror (errsv)); g_free (display_name); } return NULL; } stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; return G_FILE_OUTPUT_STREAM (stream); }
static GFileOutputStream * output_stream_open (const char *filename, gint open_flags, guint mode, GCancellable *cancellable, GError **error) { GLocalFileOutputStream *stream; gint fd; fd = g_open (filename, open_flags, mode); if (fd == -1) { set_error_from_open_errno (filename, error); return NULL; } stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; return G_FILE_OUTPUT_STREAM (stream); }
GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, const char *etag, gboolean create_backup, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { GLocalFileOutputStream *stream; int mode; int fd; char *temp_file; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; temp_file = NULL; if (flags & G_FILE_CREATE_PRIVATE) mode = 0600; else mode = 0666; /* If the file doesn't exist, create it */ fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode); if (fd == -1 && errno == EEXIST) { /* The file already exists */ fd = handle_overwrite_open (filename, etag, create_backup, &temp_file, cancellable, error); if (fd == -1) return NULL; } else if (fd == -1) { int errsv = errno; if (errsv == EINVAL) /* This must be an invalid filename, on e.g. FAT */ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, _("Invalid filename")); else { char *display_name = g_filename_display_name (filename); g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error opening file '%s': %s"), display_name, g_strerror (errsv)); g_free (display_name); } return NULL; } stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; stream->priv->tmp_filename = temp_file; if (create_backup) stream->priv->backup_filename = create_backup_filename (filename); stream->priv->original_filename = g_strdup (filename); return G_FILE_OUTPUT_STREAM (stream); }
/* * Write Flac tag, using the level 2 flac interface */ gboolean flac_tag_write_file_tag (const ET_File *ETFile, GError **error) { const File_Tag *FileTag; GFile *file; GFileIOStream *iostream; EtFlacWriteState state; FLAC__IOCallbacks callbacks = { et_flac_read_func, et_flac_write_func, et_flac_seek_func, et_flac_tell_func, et_flac_eof_func, et_flac_write_close_func }; const gchar *filename; const gchar *filename_utf8; const gchar *flac_error_msg; FLAC__Metadata_Chain *chain; FLAC__Metadata_Iterator *iter; FLAC__StreamMetadata_VorbisComment_Entry vce_field_vendor_string; // To save vendor string gboolean vce_field_vendor_string_found = FALSE; g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); FileTag = (File_Tag *)ETFile->FileTag->data; filename = ((File_Name *)ETFile->FileNameCur->data)->value; filename_utf8 = ((File_Name *)ETFile->FileNameCur->data)->value_utf8; /* libFLAC is able to detect (and skip) ID3v2 tags by itself */ /* Create a new chain instance to get all blocks in one time. */ chain = FLAC__metadata_chain_new (); if (chain == NULL) { flac_error_msg = FLAC__Metadata_ChainStatusString[FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR]; g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error while opening file ‘%s’ as FLAC: %s"), filename_utf8, flac_error_msg); return FALSE; } file = g_file_new_for_path (filename); state.file = file; state.error = NULL; /* TODO: Fallback to an in-memory copy of the file for non-local files, * where creation of the GFileIOStream may fail. */ iostream = g_file_open_readwrite (file, NULL, &state.error); if (iostream == NULL) { FLAC__metadata_chain_delete (chain); g_propagate_error (error, state.error); g_object_unref (file); return FALSE; } state.istream = G_FILE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (iostream))); state.ostream = G_FILE_OUTPUT_STREAM (g_io_stream_get_output_stream (G_IO_STREAM (iostream))); state.seekable = G_SEEKABLE (iostream); state.iostream = iostream; if (!FLAC__metadata_chain_read_with_callbacks (chain, &state, callbacks)) { const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status (chain); flac_error_msg = FLAC__Metadata_ChainStatusString[status]; FLAC__metadata_chain_delete (chain); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error while opening file ‘%s’ as FLAC: %s"), filename_utf8, flac_error_msg); et_flac_write_close_func (&state); return FALSE; } /* Create a new iterator instance for the chain. */ iter = FLAC__metadata_iterator_new (); if (iter == NULL) { flac_error_msg = FLAC__Metadata_ChainStatusString[FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR]; g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Error while opening file ‘%s’ as FLAC: %s"), filename_utf8, flac_error_msg); FLAC__metadata_chain_delete (chain); et_flac_write_close_func (&state); return FALSE; } FLAC__metadata_iterator_init (iter, chain); while (FLAC__metadata_iterator_next (iter)) { const FLAC__MetadataType block_type = FLAC__metadata_iterator_get_block_type (iter); /* TODO: Modify the blocks directly, rather than deleting and * recreating. */ if (block_type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { // Delete the VORBIS_COMMENT block and convert to padding. But before, save the original vendor string. /* Get block data. */ FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(iter); FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment; if (vc->vendor_string.entry != NULL) { // Get initial vendor string, to don't alterate it by FLAC__VENDOR_STRING when saving file vce_field_vendor_string.entry = (FLAC__byte *)g_strdup ((gchar *)vc->vendor_string.entry); vce_field_vendor_string.length = strlen ((gchar *)vce_field_vendor_string.entry); vce_field_vendor_string_found = TRUE; } /* Free block data. */ FLAC__metadata_iterator_delete_block (iter, true); } else if (block_type == FLAC__METADATA_TYPE_PICTURE) { /* Delete all the PICTURE blocks, and convert to padding. */ FLAC__metadata_iterator_delete_block (iter, true); } } // // Create and insert a new VORBISCOMMENT block // { FLAC__StreamMetadata *vc_block; // For vorbis comments GList *l; // Allocate a block for Vorbis comments vc_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); // Set the original vendor string, else will be use the version of library if (vce_field_vendor_string_found) { // must set 'copy' param to false, because the API will reuse the pointer of an empty // string (yet still return 'true', indicating it was copied); the string is free'd during // metadata_chain_delete routine FLAC__metadata_object_vorbiscomment_set_vendor_string(vc_block, vce_field_vendor_string, /*copy=*/false); } /********* * Title * *********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_TITLE, FileTag->title, g_settings_get_boolean (MainSettings, "ogg-split-title")); /********** * Artist * **********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_ARTIST, FileTag->artist, g_settings_get_boolean (MainSettings, "ogg-split-artist")); /**************** * Album Artist * ****************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_ALBUM_ARTIST, FileTag->album_artist, g_settings_get_boolean (MainSettings, "ogg-split-artist")); /********* * Album * *********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_ALBUM, FileTag->album, g_settings_get_boolean (MainSettings, "ogg-split-album")); /****************************** * Disc Number and Disc Total * ******************************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_DISC_NUMBER, FileTag->disc_number, FALSE); vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_DISC_TOTAL, FileTag->disc_total, FALSE); /******** * Year * ********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_DATE, FileTag->year, FALSE); /************************* * Track and Total Track * *************************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_TRACK_NUMBER, FileTag->track, FALSE); vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_TRACK_TOTAL, FileTag->track_total, FALSE); /********* * Genre * *********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_GENRE, FileTag->genre, g_settings_get_boolean (MainSettings, "ogg-split-genre")); /*********** * Comment * ***********/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_DESCRIPTION, FileTag->comment, g_settings_get_boolean (MainSettings, "ogg-split-comment")); /************ * Composer * ************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_COMPOSER, FileTag->composer, g_settings_get_boolean (MainSettings, "ogg-split-composer")); /******************* * Original artist * *******************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_PERFORMER, FileTag->orig_artist, g_settings_get_boolean (MainSettings, "ogg-split-original-artist")); /************* * Copyright * *************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_COPYRIGHT, FileTag->copyright, FALSE); /******* * URL * *******/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_CONTACT, FileTag->url, FALSE); /************** * Encoded by * **************/ vc_block_append_tag (vc_block, ET_VORBIS_COMMENT_FIELD_ENCODED_BY, FileTag->encoded_by, FALSE); /************************** * Set unsupported fields * **************************/ for (l = FileTag->other; l != NULL; l = g_list_next (l)) { vc_block_append_other_tag (vc_block, (gchar *)l->data); } // Add the block to the the chain (so we don't need to free the block) FLAC__metadata_iterator_insert_block_after(iter, vc_block); } // // Create and insert PICTURE blocks // /*********** * Picture * ***********/ { EtPicture *pic = FileTag->picture; while (pic) { /* TODO: Can this ever be NULL? */ if (pic->bytes) { const gchar *violation; FLAC__StreamMetadata *picture_block; // For picture data Picture_Format format; gconstpointer data; gsize data_size; // Allocate block for picture data picture_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE); // Type picture_block->data.picture.type = pic->type; // Mime type format = Picture_Format_From_Data(pic); /* Safe to pass a const string, according to the FLAC API * reference. */ FLAC__metadata_object_picture_set_mime_type(picture_block, (gchar *)Picture_Mime_Type_String(format), TRUE); // Description if (pic->description) { FLAC__metadata_object_picture_set_description(picture_block, (FLAC__byte *)pic->description, TRUE); } // Resolution picture_block->data.picture.width = pic->width; picture_block->data.picture.height = pic->height; picture_block->data.picture.depth = 0; /* Picture data. */ data = g_bytes_get_data (pic->bytes, &data_size); /* Safe to pass const data, if the last argument (copy) is * TRUE, according the the FLAC API reference. */ FLAC__metadata_object_picture_set_data (picture_block, (FLAC__byte *)data, (FLAC__uint32)data_size, true); if (!FLAC__metadata_object_picture_is_legal (picture_block, &violation)) { g_critical ("Created an invalid picture block: ‘%s’", violation); FLAC__metadata_object_delete (picture_block); } else { // Add the block to the the chain (so we don't need to free the block) FLAC__metadata_iterator_insert_block_after(iter, picture_block); } } pic = pic->next; } } FLAC__metadata_iterator_delete (iter); // // Prepare for writing tag // FLAC__metadata_chain_sort_padding (chain); /* Write tag. */ if (FLAC__metadata_chain_check_if_tempfile_needed (chain, true)) { EtFlacWriteState temp_state; GFile *temp_file; GFileIOStream *temp_iostream; GError *temp_error = NULL; temp_file = g_file_new_tmp ("easytag-XXXXXX", &temp_iostream, &temp_error); if (temp_file == NULL) { FLAC__metadata_chain_delete (chain); g_propagate_error (error, temp_error); et_flac_write_close_func (&state); return FALSE; } temp_state.file = temp_file; temp_state.error = NULL; temp_state.istream = G_FILE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (temp_iostream))); temp_state.ostream = G_FILE_OUTPUT_STREAM (g_io_stream_get_output_stream (G_IO_STREAM (temp_iostream))); temp_state.seekable = G_SEEKABLE (temp_iostream); temp_state.iostream = temp_iostream; if (!FLAC__metadata_chain_write_with_callbacks_and_tempfile (chain, true, &state, callbacks, &temp_state, callbacks)) { const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status (chain); flac_error_msg = FLAC__Metadata_ChainStatusString[status]; FLAC__metadata_chain_delete (chain); et_flac_write_close_func (&temp_state); et_flac_write_close_func (&state); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to write comments to file ‘%s’: %s"), filename_utf8, flac_error_msg); return FALSE; } if (!g_file_move (temp_file, file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &state.error)) { FLAC__metadata_chain_delete (chain); et_flac_write_close_func (&temp_state); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to write comments to file ‘%s’: %s"), filename_utf8, state.error->message); et_flac_write_close_func (&state); return FALSE; } et_flac_write_close_func (&temp_state); } else { if (!FLAC__metadata_chain_write_with_callbacks (chain, true, &state, callbacks)) { const FLAC__Metadata_ChainStatus status = FLAC__metadata_chain_status (chain); flac_error_msg = FLAC__Metadata_ChainStatusString[status]; FLAC__metadata_chain_delete (chain); et_flac_write_close_func (&state); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, _("Failed to write comments to file ‘%s’: %s"), filename_utf8, flac_error_msg); return FALSE; } } FLAC__metadata_chain_delete (chain); et_flac_write_close_func (&state); #ifdef ENABLE_MP3 { // Delete the ID3 tags (create a dummy ETFile for the Id3tag_... function) ET_File *ETFile_tmp = ET_File_Item_New(); File_Name *FileName_tmp = et_file_name_new (); File_Tag *FileTag_tmp = et_file_tag_new (); // Same file... FileName_tmp->value = g_strdup(filename); FileName_tmp->value_utf8 = g_strdup(filename_utf8); // Not necessary to fill 'value_ck' ETFile_tmp->FileNameList = g_list_append(NULL,FileName_tmp); ETFile_tmp->FileNameCur = ETFile_tmp->FileNameList; // With empty tag... ETFile_tmp->FileTagList = g_list_append(NULL,FileTag_tmp); ETFile_tmp->FileTag = ETFile_tmp->FileTagList; id3tag_write_file_tag (ETFile_tmp, NULL); ET_Free_File_List_Item(ETFile_tmp); } #endif return TRUE; }
GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, gboolean readable, const char *etag, gboolean create_backup, GFileCreateFlags flags, GFileInfo *reference_info, GCancellable *cancellable, GError **error) { GLocalFileOutputStream *stream; int mode; int fd; char *temp_file; gboolean sync_on_close; int open_flags; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; temp_file = NULL; mode = mode_from_flags_or_info (flags, reference_info); sync_on_close = FALSE; /* If the file doesn't exist, create it */ open_flags = O_CREAT | O_EXCL | O_BINARY; if (readable) open_flags |= O_RDWR; else open_flags |= O_WRONLY; fd = g_open (filename, open_flags, mode); if (fd == -1 && errno == EEXIST) { /* The file already exists */ fd = handle_overwrite_open (filename, readable, etag, create_backup, &temp_file, flags, reference_info, cancellable, error); if (fd == -1) return NULL; /* If the final destination exists, we want to sync the newly written * file to ensure the data is on disk when we rename over the destination. * otherwise if we get a system crash we can lose both the new and the * old file on some filesystems. (I.E. those that don't guarantee the * data is written to the disk before the metadata.) */ sync_on_close = TRUE; } else if (fd == -1) { set_error_from_open_errno (filename, error); return NULL; } stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; stream->priv->sync_on_close = sync_on_close; stream->priv->tmp_filename = temp_file; if (create_backup) stream->priv->backup_filename = create_backup_filename (filename); stream->priv->original_filename = g_strdup (filename); return G_FILE_OUTPUT_STREAM (stream); }
gboolean wavpack_tag_write_file_tag (const ET_File *ETFile, GError **error) { WavpackStreamReader writer = { wavpack_read_bytes, wavpack_get_pos, wavpack_set_pos_abs, wavpack_set_pos_rel, wavpack_push_back_byte, wavpack_get_length, wavpack_can_seek, wavpack_write_bytes }; GFile *file; EtWavpackWriteState state; const gchar *filename; const File_Tag *FileTag; WavpackContext *wpc; gchar message[80]; gchar *buffer; g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); filename = ((File_Name *)((GList *)ETFile->FileNameCur)->data)->value; FileTag = (File_Tag *)ETFile->FileTag->data; file = g_file_new_for_path (filename); state.error = NULL; state.iostream = g_file_open_readwrite (file, NULL, &state.error); g_object_unref (file); if (!state.iostream) { g_propagate_error (error, state.error); return FALSE; } state.istream = G_FILE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (state.iostream))); state.ostream = G_FILE_OUTPUT_STREAM (g_io_stream_get_output_stream (G_IO_STREAM (state.iostream))); state.seekable = G_SEEKABLE (state.iostream); /* NULL for the WavPack correction file. */ wpc = WavpackOpenFileInputEx (&writer, &state, NULL, message, OPEN_EDIT_TAGS, 0); if (wpc == NULL) { if (state.error) { g_propagate_error (error, state.error); } else { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", message); } g_object_unref (state.iostream); return FALSE; } /* Title. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "title", FileTag->title)) { goto err; } /* Artist. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "artist", FileTag->artist)) { goto err; } /* Album artist. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "album artist", FileTag->album_artist)) { goto err; } /* Album. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "album", FileTag->album)) { goto err; } /* Discnumber. */ if (FileTag->disc_number && FileTag->disc_total) { buffer = g_strdup_printf ("%s/%s", FileTag->disc_number, FileTag->disc_total); if (!et_wavpack_append_or_delete_tag_item (wpc, "part", buffer)) { g_free (buffer); goto err; } else { g_free (buffer); } } else { if (!et_wavpack_append_or_delete_tag_item (wpc, "part", FileTag->disc_number)) { goto err; } } /* Year. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "year", FileTag->year)) { goto err; } /* Tracknumber + tracktotal. */ if (FileTag->track_total) { buffer = g_strdup_printf ("%s/%s", FileTag->track, FileTag->track_total); if (!et_wavpack_append_or_delete_tag_item (wpc, "track", buffer)) { g_free (buffer); goto err; } else { g_free (buffer); } } else { if (!et_wavpack_append_or_delete_tag_item (wpc, "track", FileTag->track)) { goto err; } } /* Genre. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "genre", FileTag->genre)) { goto err; } /* Comment. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "comment", FileTag->comment)) { goto err; } /* Composer. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "composer", FileTag->composer)) { goto err; } /* Original artist. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "original artist", FileTag->orig_artist)) { goto err; } /* Copyright. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "copyright", FileTag->copyright)) { goto err; } /* URL. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "copyright url", FileTag->url)) { goto err; } /* Encoded by. */ if (!et_wavpack_append_or_delete_tag_item (wpc, "encoded by", FileTag->encoded_by)) { goto err; } if (WavpackWriteTag (wpc) == 0) { goto err; } WavpackCloseFile (wpc); g_object_unref (state.iostream); return TRUE; err: g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", WavpackGetErrorMessage (wpc)); WavpackCloseFile (wpc); return FALSE; }
static gboolean save (GFile *file) { GOutputStream *out; GFileCreateFlags flags; char buffer[1025]; char *p; gssize res; gboolean close_res; GError *error; gboolean save_res; error = NULL; flags = priv ? G_FILE_CREATE_PRIVATE : G_FILE_CREATE_NONE; flags |= replace_dest ? G_FILE_CREATE_REPLACE_DESTINATION : 0; if (create) out = (GOutputStream *)g_file_create (file, flags, NULL, &error); else if (append) out = (GOutputStream *)g_file_append_to (file, flags, NULL, &error); else out = (GOutputStream *)g_file_replace (file, etag, backup, flags, NULL, &error); if (out == NULL) { g_printerr (_("Error opening file: %s\n"), error->message); g_error_free (error); return FALSE; } save_res = TRUE; while (1) { res = read (STDIN_FILENO, buffer, 1024); if (res > 0) { ssize_t written; p = buffer; while (res > 0) { error = NULL; written = g_output_stream_write (out, p, res, NULL, &error); if (written == -1) { save_res = FALSE; g_printerr ("Error writing to stream: %s", error->message); g_error_free (error); goto out; } res -= written; p += written; } } else if (res < 0) { save_res = FALSE; perror (_("Error reading stdin")); break; } else if (res == 0) break; } out: close_res = g_output_stream_close (out, NULL, &error); if (!close_res) { save_res = FALSE; g_printerr (_("Error closing: %s\n"), error->message); g_error_free (error); } if (close_res && print_etag) { char *etag; etag = g_file_output_stream_get_etag (G_FILE_OUTPUT_STREAM (out)); if (etag) g_print ("Etag: %s\n", etag); else /* Translators: The "etag" is a token allowing to verify whether a file has been modified */ g_print (_("Etag not available\n")); g_free (etag); } g_object_unref (out); return save_res; }
GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, gboolean readable, const char *etag, gboolean create_backup, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { GLocalFileOutputStream *stream; int mode; int fd; char *temp_file; gboolean sync_on_close; int open_flags; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; temp_file = NULL; if (flags & G_FILE_CREATE_PRIVATE) mode = 0600; else mode = 0666; sync_on_close = FALSE; /* If the file doesn't exist, create it */ open_flags = O_CREAT | O_EXCL | O_BINARY; if (readable) open_flags |= O_RDWR; else open_flags |= O_WRONLY; fd = g_open (filename, open_flags, mode); if (fd == -1 && errno == EEXIST) { /* The file already exists */ fd = handle_overwrite_open (filename, readable, etag, create_backup, &temp_file, flags, cancellable, error); if (fd == -1) return NULL; /* If the final destination exists, we want to sync the newly written * file to ensure the data is on disk when we rename over the destination. * otherwise if we get a system crash we can lose both the new and the * old file on some filesystems. (I.E. those that don't guarantee the * data is written to the disk before the metadata.) */ sync_on_close = TRUE; } else if (fd == -1) { int errsv = errno; if (errsv == EINVAL) /* This must be an invalid filename, on e.g. FAT */ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, _("Invalid filename")); else { char *display_name = g_filename_display_name (filename); g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), _("Error opening file '%s': %s"), display_name, g_strerror (errsv)); g_free (display_name); } return NULL; } stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); stream->priv->fd = fd; stream->priv->sync_on_close = sync_on_close; stream->priv->tmp_filename = temp_file; if (create_backup) stream->priv->backup_filename = create_backup_filename (filename); stream->priv->original_filename = g_strdup (filename); return G_FILE_OUTPUT_STREAM (stream); }