2 * anjuta-document-saver.c
3 * This file is part of anjuta
5 * Copyright (C) 2005 - Paolo Borelli and Paolo Maggi
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 * Modified by the anjuta Team, 2005. See the AUTHORS file for a
25 * list of people on the anjuta Team.
26 * See the ChangeLog files for a list of changes.
36 #include <sys/types.h>
42 #include <glib/gi18n.h>
43 #include <glib/gfileutils.h>
44 #include <libgnomevfs/gnome-vfs.h>
46 #include "anjuta-encodings.h"
47 #include "anjuta-document-saver.h"
48 #include "anjuta-marshal.h"
49 #include "anjuta-convert.h"
51 #define ANJUTA_DOCUMENT_SAVER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_DOCUMENT_SAVER, AnjutaDocumentSaverPrivate))
53 struct _AnjutaDocumentSaverPrivate
55 AnjutaDocument
*document
;
58 const AnjutaEncoding
*encoding
;
60 AnjutaDocumentSaveFlags flags
;
64 gboolean backups_in_curr_dir
;
67 gchar
*mime_type
; //CHECK use FileInfo instead?
69 GnomeVFSFileSize size
;
70 GnomeVFSFileSize bytes_written
;
72 /* temp data for local files */
76 /* temp data for remote files */
78 GnomeVFSAsyncHandle
*handle
;
79 GnomeVFSAsyncHandle
*info_handle
;
82 GnomeVFSFileInfo
*orig_info
; /* used to restore permissions */
87 G_DEFINE_TYPE(AnjutaDocumentSaver
, anjuta_document_saver
, G_TYPE_OBJECT
)
96 static guint signals
[LAST_SIGNAL
] = { 0 };
99 anjuta_document_saver_finalize (GObject
*object
)
101 AnjutaDocumentSaverPrivate
*priv
= ANJUTA_DOCUMENT_SAVER (object
)->priv
;
106 gnome_vfs_uri_unref (priv
->vfs_uri
);
108 g_free (priv
->backup_ext
);
110 g_free (priv
->local_path
);
111 g_free (priv
->mime_type
);
112 g_free (priv
->tmp_fname
);
115 gnome_vfs_file_info_unref (priv
->orig_info
);
118 g_error_free (priv
->error
);
120 G_OBJECT_CLASS (anjuta_document_saver_parent_class
)->finalize (object
);
124 anjuta_document_saver_class_init (AnjutaDocumentSaverClass
*klass
)
126 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
128 object_class
->finalize
= anjuta_document_saver_finalize
;
131 g_signal_new ("saving",
132 G_OBJECT_CLASS_TYPE (object_class
),
134 G_STRUCT_OFFSET (AnjutaDocumentSaverClass
, saving
),
136 anjuta_marshal_VOID__BOOLEAN_POINTER
,
142 g_type_class_add_private (object_class
, sizeof(AnjutaDocumentSaverPrivate
));
146 anjuta_document_saver_init (AnjutaDocumentSaver
*saver
)
148 saver
->priv
= ANJUTA_DOCUMENT_SAVER_GET_PRIVATE (saver
);
150 saver
->priv
->fd
= -1;
152 saver
->priv
->tmpfd
= -1;
154 saver
->priv
->error
= NULL
;
157 AnjutaDocumentSaver
*
158 anjuta_document_saver_new (AnjutaDocument
*doc
)
160 AnjutaDocumentSaver
*saver
;
162 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
164 saver
= ANJUTA_DOCUMENT_SAVER (g_object_new (ANJUTA_TYPE_DOCUMENT_SAVER
, NULL
));
166 saver
->priv
->document
= doc
;
172 * Write the document contents in fd.
175 write_document_contents (gint fd
,
177 const AnjutaEncoding
*encoding
,
180 GtkTextIter start_iter
;
181 GtkTextIter end_iter
;
188 gtk_text_buffer_get_bounds (doc
, &start_iter
, &end_iter
);
189 contents
= gtk_text_buffer_get_slice (doc
, &start_iter
, &end_iter
, TRUE
);
191 len
= strlen (contents
);
194 add_cr
= (*(contents
+ len
- 1) != '\n');
198 if (encoding
!= anjuta_encoding_get_utf8 ())
200 gchar
*converted_contents
;
203 converted_contents
= anjuta_convert_from_utf8 (contents
,
212 /* Conversion error */
217 contents
= converted_contents
;
222 /* make sure we are at the start */
223 res
= (lseek (fd
, 0, SEEK_SET
) != -1);
225 /* Truncate the file to 0, in case it was not empty */
227 res
= (ftruncate (fd
, 0) == 0);
229 /* Save the file content */
232 written
= write (fd
, contents
, len
);
233 res
= ((written
!= -1) && ((gsize
) written
== len
));
236 /* Add \n at the end if needed */
239 if (encoding
!= anjuta_encoding_get_utf8 ())
241 gchar
*converted_n
= NULL
;
244 converted_n
= anjuta_convert_from_utf8 ("\n",
250 if (converted_n
== NULL
)
252 /* we do not error out for this */
253 g_warning ("Cannot add '\\n' at the end of the file.");
257 written
= write (fd
, converted_n
, n_len
);
258 res
= ((written
!= -1) && ((gsize
) written
== n_len
));
259 g_free (converted_n
);
264 res
= (write (fd
, "\n", 1) == 1);
272 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
275 ANJUTA_DOCUMENT_ERROR
,
277 "%s", gnome_vfs_result_to_string (result
));
284 save_completed_or_failed (AnjutaDocumentSaver
*saver
)
286 /* the object will be unrefed in the callback of the saving
287 * signal, so we need to prevent finalization.
289 g_object_ref (saver
);
291 g_signal_emit (saver
,
294 TRUE
, /* completed */
297 g_object_unref (saver
);
301 get_backup_filename (AnjutaDocumentSaver
*saver
)
304 gchar
*bak_ext
= NULL
;
306 if ((saver
->priv
->backup_ext
!= NULL
) &&
307 (strlen (saver
->priv
->backup_ext
) > 0))
308 bak_ext
= saver
->priv
->backup_ext
;
310 bak_ext
= g_strdup("~");
312 fname
= g_strconcat (saver
->priv
->local_path
, bak_ext
, NULL
);
314 /* If we are not going to keep the backup file and fname
315 * already exists, try to use another name.
316 * Change one character, just before the extension.
318 if (!saver
->priv
->keep_backup
&&
319 g_file_test (fname
, G_FILE_TEST_EXISTS
))
323 wp
= fname
+ strlen (fname
) - 1 - strlen (bak_ext
);
324 g_return_val_if_fail (wp
> fname
, NULL
);
327 while ((*wp
> 'a') && g_file_test (fname
, G_FILE_TEST_EXISTS
))
330 /* They all exist??? Must be something wrong. */
341 /* like unlink, but doesn't fail if the file wasn't there at all */
343 remove_file (const gchar
*name
)
349 return (res
== 0) || ((res
== -1) && (errno
== ENOENT
));
352 #define BUFSIZE 8192 /* size of normal write buffer */
355 copy_file_data (gint sfd
,
362 const gchar
*write_buffer
;
364 ssize_t bytes_to_write
;
365 ssize_t bytes_written
;
367 buffer
= g_malloc (BUFSIZE
);
371 bytes_read
= read (sfd
, buffer
, BUFSIZE
);
372 if (bytes_read
== -1)
374 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
377 ANJUTA_DOCUMENT_ERROR
,
379 "%s", gnome_vfs_result_to_string (result
));
386 bytes_to_write
= bytes_read
;
387 write_buffer
= buffer
;
391 bytes_written
= write (dfd
, write_buffer
, bytes_to_write
);
392 if (bytes_written
== -1)
394 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
397 ANJUTA_DOCUMENT_ERROR
,
399 "%s", gnome_vfs_result_to_string (result
));
406 bytes_to_write
-= bytes_written
;
407 write_buffer
+= bytes_written
;
409 while (bytes_to_write
> 0);
411 } while ((bytes_read
!= 0) && (ret
== TRUE
));
419 /* FIXME: this is ugly for multple reasons: it refetches all the info,
420 * it doesn't use fd etc... we need something better, possibly in gnome-vfs
424 get_slow_mime_type (const char *text_uri
)
426 GnomeVFSFileInfo
*info
;
428 GnomeVFSResult result
;
430 info
= gnome_vfs_file_info_new ();
431 result
= gnome_vfs_get_file_info (text_uri
, info
,
432 GNOME_VFS_FILE_INFO_GET_MIME_TYPE
|
433 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE
|
434 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
435 if (info
->mime_type
== NULL
|| result
!= GNOME_VFS_OK
) {
438 mime_type
= g_strdup (info
->mime_type
);
440 gnome_vfs_file_info_unref (info
);
445 /* ----------- local files ----------- */
448 save_existing_local_file (AnjutaDocumentSaver
*saver
)
452 struct stat new_statbuf
;
453 gchar
*backup_filename
= NULL
;
454 gboolean backup_created
= FALSE
;
456 if (fstat (saver
->priv
->fd
, &statbuf
) != 0)
458 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
460 g_set_error (&saver
->priv
->error
,
461 ANJUTA_DOCUMENT_ERROR
,
463 "%s", gnome_vfs_result_to_string (result
));
468 /* not a regular file */
469 if (!S_ISREG (statbuf
.st_mode
))
471 if (S_ISDIR (statbuf
.st_mode
))
473 g_set_error (&saver
->priv
->error
,
474 ANJUTA_DOCUMENT_ERROR
,
475 GNOME_VFS_ERROR_IS_DIRECTORY
,
476 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_IS_DIRECTORY
));
480 g_set_error (&saver
->priv
->error
,
481 ANJUTA_DOCUMENT_ERROR
,
482 ANJUTA_DOCUMENT_ERROR_NOT_REGULAR_FILE
,
483 "Not a regular file");
489 /* check if the file is actually writable */
490 if ((statbuf
.st_mode
& 0222) == 0) //FIXME... check better what else vim does
492 g_set_error (&saver
->priv
->error
,
493 ANJUTA_DOCUMENT_ERROR
,
494 GNOME_VFS_ERROR_READ_ONLY
,
495 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_READ_ONLY
));
500 /* check if someone else modified the file externally,
501 * except when "saving as", when saving a new doc (mtime = 0)
502 * or when the mtime check is explicitely disabled
504 if (saver
->priv
->doc_mtime
> 0 &&
505 statbuf
.st_mtime
!= saver
->priv
->doc_mtime
&&
506 ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_MTIME
) == 0))
508 g_set_error (&saver
->priv
->error
,
509 ANJUTA_DOCUMENT_ERROR
,
510 ANJUTA_DOCUMENT_ERROR_EXTERNALLY_MODIFIED
,
511 "Externally modified");
516 /* prepare the backup name */
517 backup_filename
= get_backup_filename (saver
);
518 if (backup_filename
== NULL
)
520 /* bad bad luck... */
521 g_warning (_("Could not obtain backup filename"));
523 g_set_error (&saver
->priv
->error
,
524 ANJUTA_DOCUMENT_ERROR
,
525 GNOME_VFS_ERROR_GENERIC
,
526 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_GENERIC
));
531 /* We now use two backup strategies.
532 * The first one (which is faster) consist in saving to a
533 * tmp file then rename the original file to the backup and the
534 * tmp file to the original name. This is fast but doesn't work
535 * when the file is a link (hard or symbolic) or when we can't
536 * write to the current dir or can't set the permissions on the
537 * new file. We also do not use it when the backup is not in the
538 * current dir, since if it isn't on the same FS rename wont work.
539 * The second strategy consist simply in copying the old file
540 * to a backup file and rewrite the contents of the file.
543 if (saver
->priv
->backups_in_curr_dir
&&
544 !(statbuf
.st_nlink
> 1) &&
545 !g_file_test (saver
->priv
->local_path
, G_FILE_TEST_IS_SYMLINK
))
551 dirname
= g_path_get_dirname (saver
->priv
->local_path
);
552 tmp_filename
= g_build_filename (dirname
, ".anjuta-save-XXXXXX", NULL
);
555 /* We set the umask because some (buggy) implementations
556 * of mkstemp() use permissions 0666 and we want 0600.
558 saved_umask
= umask (0077);
559 tmpfd
= g_mkstemp (tmp_filename
);
564 g_free (tmp_filename
);
565 goto fallback_strategy
;
568 /* try to set permissions */
569 if (fchown (tmpfd
, statbuf
.st_uid
, statbuf
.st_gid
) == -1 ||
570 fchmod (tmpfd
, statbuf
.st_mode
) == -1)
573 unlink (tmp_filename
);
574 g_free (tmp_filename
);
575 goto fallback_strategy
;
578 if (!write_document_contents (tmpfd
,
579 GTK_TEXT_BUFFER (saver
->priv
->document
),
580 saver
->priv
->encoding
,
581 &saver
->priv
->error
))
584 unlink (tmp_filename
);
585 g_free (tmp_filename
);
589 /* original -> backup */
590 if (rename (saver
->priv
->local_path
, backup_filename
) != 0)
592 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
594 g_set_error (&saver
->priv
->error
,
595 ANJUTA_DOCUMENT_ERROR
,
597 "%s", gnome_vfs_result_to_string (result
));
600 unlink (tmp_filename
);
601 g_free (tmp_filename
);
605 /* tmp -> original */
606 if (rename (tmp_filename
, saver
->priv
->local_path
) != 0)
608 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
610 g_set_error (&saver
->priv
->error
,
611 ANJUTA_DOCUMENT_ERROR
,
613 "%s", gnome_vfs_result_to_string (result
));
615 /* try to restore... no error checking */
616 rename (backup_filename
, saver
->priv
->local_path
);
619 unlink (tmp_filename
);
620 g_free (tmp_filename
);
624 g_free (tmp_filename
);
626 /* restat and get the mime type */
627 if (fstat (tmpfd
, &new_statbuf
) != 0)
629 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
631 g_set_error (&saver
->priv
->error
,
632 ANJUTA_DOCUMENT_ERROR
,
634 "%s", gnome_vfs_result_to_string (result
));
640 saver
->priv
->doc_mtime
= new_statbuf
.st_mtime
;
642 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
644 if (!saver
->priv
->keep_backup
)
645 unlink (backup_filename
);
654 /* try to copy the old contents in a backup for safety
655 * unless we are explicetely told not to.
657 if ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_BACKUP
) == 0)
661 /* move away old backups */
662 if (!remove_file (backup_filename
))
664 /* we don't care about which was the problem, just
665 * that a backup was not possible.
667 g_set_error (&saver
->priv
->error
,
668 ANJUTA_DOCUMENT_ERROR
,
669 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
670 "No backup created");
675 bfd
= open (backup_filename
,
676 O_WRONLY
| O_CREAT
| O_EXCL
,
677 statbuf
.st_mode
& 0777);
681 g_set_error (&saver
->priv
->error
,
682 ANJUTA_DOCUMENT_ERROR
,
683 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
684 "No backup created");
689 /* Try to set the group of the backup same as the
690 * original file. If this fails, set the protection
691 * bits for the group same as the protection bits for
693 if (fchown (bfd
, (uid_t
) -1, statbuf
.st_gid
) != 0)
696 (statbuf
.st_mode
& 0707) |
697 ((statbuf
.st_mode
& 07) << 3)) != 0)
699 g_set_error (&saver
->priv
->error
,
700 ANJUTA_DOCUMENT_ERROR
,
701 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
702 "No backup created");
704 unlink (backup_filename
);
711 if (!copy_file_data (saver
->priv
->fd
, bfd
, NULL
))
713 g_set_error (&saver
->priv
->error
,
714 ANJUTA_DOCUMENT_ERROR
,
715 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
716 "No backup created");
718 unlink (backup_filename
);
724 backup_created
= TRUE
;
728 /* finally overwrite the original */
729 if (!write_document_contents (saver
->priv
->fd
,
730 GTK_TEXT_BUFFER (saver
->priv
->document
),
731 saver
->priv
->encoding
,
732 &saver
->priv
->error
))
737 /* remove the backup if we don't want to keep it */
738 if (backup_created
&& !saver
->priv
->keep_backup
)
740 unlink (backup_filename
);
743 /* re stat the file and refetch the mime type */
744 if (fstat (saver
->priv
->fd
, &new_statbuf
) != 0)
746 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
748 g_set_error (&saver
->priv
->error
,
749 ANJUTA_DOCUMENT_ERROR
,
751 "%s", gnome_vfs_result_to_string (result
));
756 saver
->priv
->doc_mtime
= new_statbuf
.st_mtime
;
758 g_free (saver
->priv
->mime_type
);
759 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
762 if (close (saver
->priv
->fd
))
763 g_warning ("File '%s' has not been correctly closed: %s",
766 saver
->priv
->fd
= -1;
768 g_free (backup_filename
);
770 save_completed_or_failed (saver
);
772 /* stop the timeout */
777 save_new_local_file (AnjutaDocumentSaver
*saver
)
781 if (!write_document_contents (saver
->priv
->fd
,
782 GTK_TEXT_BUFFER (saver
->priv
->document
),
783 saver
->priv
->encoding
,
784 &saver
->priv
->error
))
789 /* stat the file and fetch the mime type */
790 if (fstat (saver
->priv
->fd
, &statbuf
) != 0)
792 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
794 g_set_error (&saver
->priv
->error
,
795 ANJUTA_DOCUMENT_ERROR
,
797 "%s", gnome_vfs_result_to_string (result
));
802 saver
->priv
->doc_mtime
= statbuf
.st_mtime
;
804 g_free (saver
->priv
->mime_type
);
805 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
808 if (close (saver
->priv
->fd
))
809 g_warning ("File '%s' has not been correctly closed: %s",
813 saver
->priv
->fd
= -1;
815 save_completed_or_failed (saver
);
817 /* stop the timeout */
822 open_local_failed (AnjutaDocumentSaver
*saver
)
824 save_completed_or_failed (saver
);
826 /* stop the timeout */
831 save_local_file (AnjutaDocumentSaver
*saver
)
833 GSourceFunc next_phase
;
834 GnomeVFSResult result
;
837 g_signal_emit (saver
,
843 /* the file doesn't exist, create it */
844 saver
->priv
->fd
= open (saver
->priv
->local_path
,
845 O_CREAT
| O_EXCL
| O_WRONLY
,
847 if (saver
->priv
->fd
!= -1)
849 next_phase
= (GSourceFunc
) save_new_local_file
;
853 /* the file already exist */
854 else if (errno
== EEXIST
)
856 saver
->priv
->fd
= open (saver
->priv
->local_path
, O_RDWR
);
857 if (saver
->priv
->fd
!= -1)
859 next_phase
= (GSourceFunc
) save_existing_local_file
;
865 result
= gnome_vfs_result_from_errno (); //may it happen that no errno?
867 g_set_error (&saver
->priv
->error
,
868 ANJUTA_DOCUMENT_ERROR
,
870 "%s", gnome_vfs_result_to_string (result
));
872 next_phase
= (GSourceFunc
) open_local_failed
;
875 g_timeout_add_full (G_PRIORITY_HIGH
,
882 /* ----------- remote files ----------- */
885 remote_save_completed_or_failed (AnjutaDocumentSaver
*saver
)
887 /* we can now close and unlink the tmp file */
888 close (saver
->priv
->tmpfd
);
889 unlink (saver
->priv
->tmp_fname
);
891 save_completed_or_failed (saver
);
895 remote_get_info_cb (GnomeVFSAsyncHandle
*handle
,
899 AnjutaDocumentSaver
*saver
= ANJUTA_DOCUMENT_SAVER (data
);
900 GnomeVFSGetFileInfoResult
*info_result
;
902 /* assert that the list has one and only one item */
903 g_return_if_fail (results
!= NULL
&& results
->next
== NULL
);
905 info_result
= (GnomeVFSGetFileInfoResult
*) results
->data
;
906 g_return_if_fail (info_result
!= NULL
);
908 if (info_result
->result
!= GNOME_VFS_OK
)
910 g_set_error (&saver
->priv
->error
,
911 ANJUTA_DOCUMENT_ERROR
,
913 "%s", gnome_vfs_result_to_string (info_result
->result
));
915 remote_save_completed_or_failed (saver
);
920 if (info_result
->file_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
921 saver
->priv
->doc_mtime
= info_result
->file_info
->mtime
;
923 if (info_result
->file_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
)
925 g_free (saver
->priv
->mime_type
);
926 saver
->priv
->mime_type
= g_strdup (info_result
->file_info
->mime_type
);
929 remote_save_completed_or_failed (saver
);
933 async_xfer_ok (GnomeVFSXferProgressInfo
*progress_info
,
934 AnjutaDocumentSaver
*saver
)
936 switch (progress_info
->phase
)
938 case GNOME_VFS_XFER_PHASE_INITIAL
:
940 case GNOME_VFS_XFER_CHECKING_DESTINATION
:
942 GnomeVFSFileInfo
*orig_info
;
945 /* we need to retrieve info ourselves too, since xfer
946 * doesn't allow to access it :(
947 * If that was not enough we need to do it sync or we are going
948 * to mess everything up
950 orig_info
= gnome_vfs_file_info_new ();
951 res
= gnome_vfs_get_file_info_uri (saver
->priv
->vfs_uri
,
953 GNOME_VFS_FILE_INFO_DEFAULT
|
954 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
956 if (res
== GNOME_VFS_ERROR_NOT_FOUND
)
958 /* ok, we are not overwriting, go on with the xfer */
962 if (res
!= GNOME_VFS_OK
)
964 // CHECK: do we want to ignore the error and try to go on anyway?
965 g_set_error (&saver
->priv
->error
,
966 ANJUTA_DOCUMENT_ERROR
,
968 "%s", gnome_vfs_result_to_string (res
));
975 /* check if someone else modified the file externally,
976 * except when "saving as", when saving a new doc (mtime = 0)
977 * or when the mtime check is explicitely disabled
979 if (orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
981 if (saver
->priv
->doc_mtime
> 0 &&
982 orig_info
->mtime
!= saver
->priv
->doc_mtime
&&
983 ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_MTIME
) == 0))
985 g_set_error (&saver
->priv
->error
,
986 ANJUTA_DOCUMENT_ERROR
,
987 ANJUTA_DOCUMENT_ERROR_EXTERNALLY_MODIFIED
,
988 "Externally modified");
995 /* store the original file info, so that we can restore permissions */
996 // FIXME: what about the case where we are usin "Save as" but overwriting a file... we don't want to restore perms
997 if (orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS
)
998 saver
->priv
->orig_info
= orig_info
;
1001 case GNOME_VFS_XFER_PHASE_COLLECTING
:
1002 case GNOME_VFS_XFER_PHASE_DELETESOURCE
: // why do we get this phase??
1004 case GNOME_VFS_XFER_PHASE_READYTOGO
:
1005 saver
->priv
->size
= progress_info
->bytes_total
;
1007 case GNOME_VFS_XFER_PHASE_OPENSOURCE
:
1008 case GNOME_VFS_XFER_PHASE_OPENTARGET
:
1009 case GNOME_VFS_XFER_PHASE_COPYING
:
1010 case GNOME_VFS_XFER_PHASE_WRITETARGET
:
1011 case GNOME_VFS_XFER_PHASE_CLOSETARGET
:
1012 if (progress_info
->bytes_copied
> 0)
1013 saver
->priv
->bytes_written
= MIN (progress_info
->total_bytes_copied
,
1014 progress_info
->bytes_total
);
1016 case GNOME_VFS_XFER_PHASE_FILECOMPLETED
:
1017 case GNOME_VFS_XFER_PHASE_CLEANUP
:
1019 case GNOME_VFS_XFER_PHASE_COMPLETED
:
1021 * Restore the permissions if needed and then refetch
1022 * info on our newly written file to get the mime etc */
1024 GList
*uri_list
= NULL
;
1026 /* Try is not as paranoid as the local version (GID)... it would take
1027 * yet another stat to do it...
1029 if (saver
->priv
->orig_info
!= NULL
&&
1030 (saver
->priv
->orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS
))
1032 gnome_vfs_set_file_info_uri (saver
->priv
->vfs_uri
,
1033 saver
->priv
->orig_info
,
1034 GNOME_VFS_SET_FILE_INFO_PERMISSIONS
);
1036 // FIXME: for now is a blind try... do we want to error check?
1039 uri_list
= g_list_prepend (uri_list
, saver
->priv
->vfs_uri
);
1041 gnome_vfs_async_get_file_info (&saver
->priv
->info_handle
,
1043 GNOME_VFS_FILE_INFO_DEFAULT
|
1044 GNOME_VFS_FILE_INFO_GET_MIME_TYPE
|
1045 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE
|
1046 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
,
1047 GNOME_VFS_PRIORITY_MAX
,
1050 g_list_free (uri_list
);
1053 /* Phases we don't expect to see */
1054 case GNOME_VFS_XFER_PHASE_SETATTRIBUTES
:
1055 case GNOME_VFS_XFER_PHASE_CLOSESOURCE
:
1056 case GNOME_VFS_XFER_PHASE_MOVING
:
1057 case GNOME_VFS_XFER_PHASE_READSOURCE
:
1059 g_return_val_if_reached (0);
1062 /* signal the progress */
1063 g_signal_emit (saver
,
1073 async_xfer_error (GnomeVFSXferProgressInfo
*progress_info
,
1074 AnjutaDocumentSaver
*saver
)
1076 g_set_error (&saver
->priv
->error
,
1077 ANJUTA_DOCUMENT_ERROR
,
1078 progress_info
->vfs_status
,
1079 "%s", gnome_vfs_result_to_string (progress_info
->vfs_status
));
1081 remote_save_completed_or_failed (saver
);
1083 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1087 async_xfer_progress (GnomeVFSAsyncHandle
*handle
,
1088 GnomeVFSXferProgressInfo
*progress_info
,
1091 AnjutaDocumentSaver
*saver
= ANJUTA_DOCUMENT_SAVER (data
);
1093 switch (progress_info
->status
)
1095 case GNOME_VFS_XFER_PROGRESS_STATUS_OK
:
1096 return async_xfer_ok (progress_info
, saver
);
1097 case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR
:
1098 return async_xfer_error (progress_info
, saver
);
1100 /* we should never go in these */
1101 case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE
:
1102 case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE
:
1104 g_return_val_if_reached (0);
1109 save_remote_file_real (AnjutaDocumentSaver
*saver
)
1113 GnomeVFSURI
*tmp_vfs_uri
;
1114 GList
*source_uri_list
= NULL
;
1115 GList
*dest_uri_list
= NULL
;
1116 GnomeVFSResult result
;
1118 /* For remote files we use the following strategy:
1119 * we save to a local temp file and then transfer it
1120 * over to the requested location asyncronously.
1121 * There is no backup of the original remote file.
1124 /* We set the umask because some (buggy) implementations
1125 * of mkstemp() use permissions 0666 and we want 0600.
1127 saved_umask
= umask (0077);
1128 saver
->priv
->tmpfd
= g_file_open_tmp (".anjuta-save-XXXXXX",
1129 &saver
->priv
->tmp_fname
,
1130 &saver
->priv
->error
);
1131 umask (saved_umask
);
1133 if (saver
->priv
->tmpfd
== -1)
1135 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
1137 g_set_error (&saver
->priv
->error
,
1138 ANJUTA_DOCUMENT_ERROR
,
1140 "%s", gnome_vfs_result_to_string (result
));
1142 /* in this case no need to close the tmp file */
1143 save_completed_or_failed (saver
);
1148 tmp_uri
= g_filename_to_uri (saver
->priv
->tmp_fname
,
1150 &saver
->priv
->error
);
1151 if (tmp_uri
== NULL
)
1156 tmp_vfs_uri
= gnome_vfs_uri_new (tmp_uri
);
1157 //needs error checking?
1161 source_uri_list
= g_list_prepend (source_uri_list
, tmp_vfs_uri
);
1162 dest_uri_list
= g_list_prepend (dest_uri_list
, saver
->priv
->vfs_uri
);
1164 if (!write_document_contents (saver
->priv
->tmpfd
,
1165 GTK_TEXT_BUFFER (saver
->priv
->document
),
1166 saver
->priv
->encoding
,
1167 &saver
->priv
->error
))
1172 result
= gnome_vfs_async_xfer (&saver
->priv
->handle
,
1175 GNOME_VFS_XFER_DEFAULT
| GNOME_VFS_XFER_TARGET_DEFAULT_PERMS
, // CHECK needs more thinking, follow symlinks etc... options are undocumented :(
1176 GNOME_VFS_XFER_ERROR_MODE_ABORT
, /* keep it simple, abort on any error */
1177 GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
, /* We have already asked confirm (even if it is racy) */
1178 GNOME_VFS_PRIORITY_DEFAULT
,
1179 async_xfer_progress
, saver
,
1182 gnome_vfs_uri_unref (tmp_vfs_uri
);
1183 g_list_free (source_uri_list
);
1184 g_list_free (dest_uri_list
);
1186 if (result
!= GNOME_VFS_OK
)
1188 g_set_error (&saver
->priv
->error
,
1189 ANJUTA_DOCUMENT_ERROR
,
1191 "%s", gnome_vfs_result_to_string (result
));
1196 /* No errors: stop the timeout */
1200 remote_save_completed_or_failed (saver
);
1202 /* stop the timeout */
1207 save_remote_file (AnjutaDocumentSaver
*saver
)
1210 g_signal_emit (saver
,
1216 g_timeout_add_full (G_PRIORITY_HIGH
,
1218 (GSourceFunc
) save_remote_file_real
,
1223 /* ---------- public api ---------- */
1226 anjuta_document_saver_save (AnjutaDocumentSaver
*saver
,
1228 const AnjutaEncoding
*encoding
,
1230 AnjutaDocumentSaveFlags flags
)
1234 g_return_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
));
1235 g_return_if_fail ((uri
!= NULL
) && (strlen (uri
) > 0));
1238 // - sanity check a max len for the uri?
1239 // report async (in an idle handler) or sync (bool ret)
1240 // async is extra work here, sync is special casing in the caller
1242 saver
->priv
->uri
= g_strdup (uri
);
1244 /* fetch saving options */
1245 saver
->priv
->backup_ext
= g_strdup("~");
1247 /* never keep backup of autosaves */
1248 if ((flags
& ANJUTA_DOCUMENT_SAVE_PRESERVE_BACKUP
) != 0)
1249 saver
->priv
->keep_backup
= FALSE
;
1251 /* FIXME: This should be configurable */
1252 saver
->priv
->keep_backup
=TRUE
;
1254 /* TODO: add support for configurable backup dir */
1255 saver
->priv
->backups_in_curr_dir
= TRUE
;
1257 if (encoding
!= NULL
)
1258 saver
->priv
->encoding
= encoding
;
1260 saver
->priv
->encoding
= anjuta_encoding_get_utf8 ();
1262 saver
->priv
->doc_mtime
= oldmtime
;
1264 saver
->priv
->flags
= flags
;
1266 local_path
= gnome_vfs_get_local_path_from_uri (uri
);
1267 if (local_path
!= NULL
)
1269 saver
->priv
->local_path
= local_path
;
1270 save_local_file (saver
);
1274 saver
->priv
->vfs_uri
= gnome_vfs_uri_new (uri
);
1275 save_remote_file (saver
);
1280 anjuta_document_saver_get_uri (AnjutaDocumentSaver
*saver
)
1282 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), NULL
);
1284 return saver
->priv
->uri
;
1288 anjuta_document_saver_get_mime_type (AnjutaDocumentSaver
*saver
)
1290 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), NULL
);
1292 return saver
->priv
->mime_type
;
1296 anjuta_document_saver_get_mtime (AnjutaDocumentSaver
*saver
)
1298 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1300 return saver
->priv
->doc_mtime
;
1303 /* Returns 0 if file size is unknown */
1305 anjuta_document_saver_get_file_size (AnjutaDocumentSaver
*saver
)
1307 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1309 return saver
->priv
->size
;
1313 anjuta_document_saver_get_bytes_written (AnjutaDocumentSaver
*saver
)
1315 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1317 return saver
->priv
->bytes_written
;