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 <libanjuta/anjuta-encodings.h>
47 #include <libanjuta/anjuta-convert.h>
49 #include "anjuta-document-saver.h"
50 #include "anjuta-marshal.h"
52 #define ANJUTA_DOCUMENT_SAVER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_DOCUMENT_SAVER, AnjutaDocumentSaverPrivate))
54 struct _AnjutaDocumentSaverPrivate
56 AnjutaDocument
*document
;
59 const AnjutaEncoding
*encoding
;
61 AnjutaDocumentSaveFlags flags
;
65 gboolean backups_in_curr_dir
;
68 gchar
*mime_type
; //CHECK use FileInfo instead?
70 GnomeVFSFileSize size
;
71 GnomeVFSFileSize bytes_written
;
73 /* temp data for local files */
77 /* temp data for remote files */
79 GnomeVFSAsyncHandle
*handle
;
80 GnomeVFSAsyncHandle
*info_handle
;
83 GnomeVFSFileInfo
*orig_info
; /* used to restore permissions */
88 G_DEFINE_TYPE(AnjutaDocumentSaver
, anjuta_document_saver
, G_TYPE_OBJECT
)
97 static guint signals
[LAST_SIGNAL
] = { 0 };
100 anjuta_document_saver_finalize (GObject
*object
)
102 AnjutaDocumentSaverPrivate
*priv
= ANJUTA_DOCUMENT_SAVER (object
)->priv
;
107 gnome_vfs_uri_unref (priv
->vfs_uri
);
109 g_free (priv
->backup_ext
);
111 g_free (priv
->local_path
);
112 g_free (priv
->mime_type
);
113 g_free (priv
->tmp_fname
);
116 gnome_vfs_file_info_unref (priv
->orig_info
);
119 g_error_free (priv
->error
);
121 G_OBJECT_CLASS (anjuta_document_saver_parent_class
)->finalize (object
);
125 anjuta_document_saver_class_init (AnjutaDocumentSaverClass
*klass
)
127 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
129 object_class
->finalize
= anjuta_document_saver_finalize
;
132 g_signal_new ("saving",
133 G_OBJECT_CLASS_TYPE (object_class
),
135 G_STRUCT_OFFSET (AnjutaDocumentSaverClass
, saving
),
137 anjuta_marshal_VOID__BOOLEAN_POINTER
,
143 g_type_class_add_private (object_class
, sizeof(AnjutaDocumentSaverPrivate
));
147 anjuta_document_saver_init (AnjutaDocumentSaver
*saver
)
149 saver
->priv
= ANJUTA_DOCUMENT_SAVER_GET_PRIVATE (saver
);
151 saver
->priv
->fd
= -1;
153 saver
->priv
->tmpfd
= -1;
155 saver
->priv
->error
= NULL
;
158 AnjutaDocumentSaver
*
159 anjuta_document_saver_new (AnjutaDocument
*doc
)
161 AnjutaDocumentSaver
*saver
;
163 g_return_val_if_fail (ANJUTA_IS_DOCUMENT (doc
), NULL
);
165 saver
= ANJUTA_DOCUMENT_SAVER (g_object_new (ANJUTA_TYPE_DOCUMENT_SAVER
, NULL
));
167 saver
->priv
->document
= doc
;
173 * Write the document contents in fd.
176 write_document_contents (gint fd
,
178 const AnjutaEncoding
*encoding
,
181 GtkTextIter start_iter
;
182 GtkTextIter end_iter
;
189 gtk_text_buffer_get_bounds (doc
, &start_iter
, &end_iter
);
190 contents
= gtk_text_buffer_get_slice (doc
, &start_iter
, &end_iter
, TRUE
);
192 len
= strlen (contents
);
195 add_cr
= (*(contents
+ len
- 1) != '\n');
199 if (encoding
!= anjuta_encoding_get_utf8 ())
201 gchar
*converted_contents
;
204 converted_contents
= anjuta_convert_from_utf8 (contents
,
213 /* Conversion error */
218 contents
= converted_contents
;
223 /* make sure we are at the start */
224 res
= (lseek (fd
, 0, SEEK_SET
) != -1);
226 /* Truncate the file to 0, in case it was not empty */
228 res
= (ftruncate (fd
, 0) == 0);
230 /* Save the file content */
233 written
= write (fd
, contents
, len
);
234 res
= ((written
!= -1) && ((gsize
) written
== len
));
237 /* Add \n at the end if needed */
240 if (encoding
!= anjuta_encoding_get_utf8 ())
242 gchar
*converted_n
= NULL
;
245 converted_n
= anjuta_convert_from_utf8 ("\n",
251 if (converted_n
== NULL
)
253 /* we do not error out for this */
254 g_warning ("Cannot add '\\n' at the end of the file.");
258 written
= write (fd
, converted_n
, n_len
);
259 res
= ((written
!= -1) && ((gsize
) written
== n_len
));
260 g_free (converted_n
);
265 res
= (write (fd
, "\n", 1) == 1);
273 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
276 ANJUTA_DOCUMENT_ERROR
,
278 "%s", gnome_vfs_result_to_string (result
));
285 save_completed_or_failed (AnjutaDocumentSaver
*saver
)
287 /* the object will be unrefed in the callback of the saving
288 * signal, so we need to prevent finalization.
290 g_object_ref (saver
);
292 g_signal_emit (saver
,
295 TRUE
, /* completed */
298 g_object_unref (saver
);
302 get_backup_filename (AnjutaDocumentSaver
*saver
)
305 gchar
*bak_ext
= NULL
;
307 if ((saver
->priv
->backup_ext
!= NULL
) &&
308 (strlen (saver
->priv
->backup_ext
) > 0))
309 bak_ext
= saver
->priv
->backup_ext
;
311 bak_ext
= g_strdup("~");
313 fname
= g_strconcat (saver
->priv
->local_path
, bak_ext
, NULL
);
315 /* If we are not going to keep the backup file and fname
316 * already exists, try to use another name.
317 * Change one character, just before the extension.
319 if (!saver
->priv
->keep_backup
&&
320 g_file_test (fname
, G_FILE_TEST_EXISTS
))
324 wp
= fname
+ strlen (fname
) - 1 - strlen (bak_ext
);
325 g_return_val_if_fail (wp
> fname
, NULL
);
328 while ((*wp
> 'a') && g_file_test (fname
, G_FILE_TEST_EXISTS
))
331 /* They all exist??? Must be something wrong. */
342 /* like unlink, but doesn't fail if the file wasn't there at all */
344 remove_file (const gchar
*name
)
350 return (res
== 0) || ((res
== -1) && (errno
== ENOENT
));
353 #define BUFSIZE 8192 /* size of normal write buffer */
356 copy_file_data (gint sfd
,
363 const gchar
*write_buffer
;
365 ssize_t bytes_to_write
;
366 ssize_t bytes_written
;
368 buffer
= g_malloc (BUFSIZE
);
372 bytes_read
= read (sfd
, buffer
, BUFSIZE
);
373 if (bytes_read
== -1)
375 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
378 ANJUTA_DOCUMENT_ERROR
,
380 "%s", gnome_vfs_result_to_string (result
));
387 bytes_to_write
= bytes_read
;
388 write_buffer
= buffer
;
392 bytes_written
= write (dfd
, write_buffer
, bytes_to_write
);
393 if (bytes_written
== -1)
395 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
398 ANJUTA_DOCUMENT_ERROR
,
400 "%s", gnome_vfs_result_to_string (result
));
407 bytes_to_write
-= bytes_written
;
408 write_buffer
+= bytes_written
;
410 while (bytes_to_write
> 0);
412 } while ((bytes_read
!= 0) && (ret
== TRUE
));
420 /* FIXME: this is ugly for multple reasons: it refetches all the info,
421 * it doesn't use fd etc... we need something better, possibly in gnome-vfs
425 get_slow_mime_type (const char *text_uri
)
427 GnomeVFSFileInfo
*info
;
429 GnomeVFSResult result
;
431 info
= gnome_vfs_file_info_new ();
432 result
= gnome_vfs_get_file_info (text_uri
, info
,
433 GNOME_VFS_FILE_INFO_GET_MIME_TYPE
|
434 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE
|
435 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
436 if (info
->mime_type
== NULL
|| result
!= GNOME_VFS_OK
) {
439 mime_type
= g_strdup (info
->mime_type
);
441 gnome_vfs_file_info_unref (info
);
446 /* ----------- local files ----------- */
449 save_existing_local_file (AnjutaDocumentSaver
*saver
)
453 struct stat new_statbuf
;
454 gchar
*backup_filename
= NULL
;
455 gboolean backup_created
= FALSE
;
457 if (fstat (saver
->priv
->fd
, &statbuf
) != 0)
459 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
461 g_set_error (&saver
->priv
->error
,
462 ANJUTA_DOCUMENT_ERROR
,
464 "%s", gnome_vfs_result_to_string (result
));
469 /* not a regular file */
470 if (!S_ISREG (statbuf
.st_mode
))
472 if (S_ISDIR (statbuf
.st_mode
))
474 g_set_error (&saver
->priv
->error
,
475 ANJUTA_DOCUMENT_ERROR
,
476 GNOME_VFS_ERROR_IS_DIRECTORY
,
477 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_IS_DIRECTORY
));
481 g_set_error (&saver
->priv
->error
,
482 ANJUTA_DOCUMENT_ERROR
,
483 ANJUTA_DOCUMENT_ERROR_NOT_REGULAR_FILE
,
484 "Not a regular file");
490 /* check if the file is actually writable */
491 if ((statbuf
.st_mode
& 0222) == 0) //FIXME... check better what else vim does
493 g_set_error (&saver
->priv
->error
,
494 ANJUTA_DOCUMENT_ERROR
,
495 GNOME_VFS_ERROR_READ_ONLY
,
496 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_READ_ONLY
));
501 /* check if someone else modified the file externally,
502 * except when "saving as", when saving a new doc (mtime = 0)
503 * or when the mtime check is explicitely disabled
505 if (saver
->priv
->doc_mtime
> 0 &&
506 statbuf
.st_mtime
!= saver
->priv
->doc_mtime
&&
507 ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_MTIME
) == 0))
509 g_set_error (&saver
->priv
->error
,
510 ANJUTA_DOCUMENT_ERROR
,
511 ANJUTA_DOCUMENT_ERROR_EXTERNALLY_MODIFIED
,
512 "Externally modified");
517 /* prepare the backup name */
518 backup_filename
= get_backup_filename (saver
);
519 if (backup_filename
== NULL
)
521 /* bad bad luck... */
522 g_warning (_("Could not obtain backup filename"));
524 g_set_error (&saver
->priv
->error
,
525 ANJUTA_DOCUMENT_ERROR
,
526 GNOME_VFS_ERROR_GENERIC
,
527 "%s", gnome_vfs_result_to_string (GNOME_VFS_ERROR_GENERIC
));
532 /* We now use two backup strategies.
533 * The first one (which is faster) consist in saving to a
534 * tmp file then rename the original file to the backup and the
535 * tmp file to the original name. This is fast but doesn't work
536 * when the file is a link (hard or symbolic) or when we can't
537 * write to the current dir or can't set the permissions on the
538 * new file. We also do not use it when the backup is not in the
539 * current dir, since if it isn't on the same FS rename wont work.
540 * The second strategy consist simply in copying the old file
541 * to a backup file and rewrite the contents of the file.
544 if (saver
->priv
->backups_in_curr_dir
&&
545 !(statbuf
.st_nlink
> 1) &&
546 !g_file_test (saver
->priv
->local_path
, G_FILE_TEST_IS_SYMLINK
))
552 dirname
= g_path_get_dirname (saver
->priv
->local_path
);
553 tmp_filename
= g_build_filename (dirname
, ".anjuta-save-XXXXXX", NULL
);
556 /* We set the umask because some (buggy) implementations
557 * of mkstemp() use permissions 0666 and we want 0600.
559 saved_umask
= umask (0077);
560 tmpfd
= g_mkstemp (tmp_filename
);
565 g_free (tmp_filename
);
566 goto fallback_strategy
;
569 /* try to set permissions */
570 if (fchown (tmpfd
, statbuf
.st_uid
, statbuf
.st_gid
) == -1 ||
571 fchmod (tmpfd
, statbuf
.st_mode
) == -1)
574 unlink (tmp_filename
);
575 g_free (tmp_filename
);
576 goto fallback_strategy
;
579 if (!write_document_contents (tmpfd
,
580 GTK_TEXT_BUFFER (saver
->priv
->document
),
581 saver
->priv
->encoding
,
582 &saver
->priv
->error
))
585 unlink (tmp_filename
);
586 g_free (tmp_filename
);
590 /* original -> backup */
591 if (rename (saver
->priv
->local_path
, backup_filename
) != 0)
593 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
595 g_set_error (&saver
->priv
->error
,
596 ANJUTA_DOCUMENT_ERROR
,
598 "%s", gnome_vfs_result_to_string (result
));
601 unlink (tmp_filename
);
602 g_free (tmp_filename
);
606 /* tmp -> original */
607 if (rename (tmp_filename
, saver
->priv
->local_path
) != 0)
609 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
611 g_set_error (&saver
->priv
->error
,
612 ANJUTA_DOCUMENT_ERROR
,
614 "%s", gnome_vfs_result_to_string (result
));
616 /* try to restore... no error checking */
617 rename (backup_filename
, saver
->priv
->local_path
);
620 unlink (tmp_filename
);
621 g_free (tmp_filename
);
625 g_free (tmp_filename
);
627 /* restat and get the mime type */
628 if (fstat (tmpfd
, &new_statbuf
) != 0)
630 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
632 g_set_error (&saver
->priv
->error
,
633 ANJUTA_DOCUMENT_ERROR
,
635 "%s", gnome_vfs_result_to_string (result
));
641 saver
->priv
->doc_mtime
= new_statbuf
.st_mtime
;
643 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
645 if (!saver
->priv
->keep_backup
)
646 unlink (backup_filename
);
655 /* try to copy the old contents in a backup for safety
656 * unless we are explicetely told not to.
658 if ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_BACKUP
) == 0)
662 /* move away old backups */
663 if (!remove_file (backup_filename
))
665 /* we don't care about which was the problem, just
666 * that a backup was not possible.
668 g_set_error (&saver
->priv
->error
,
669 ANJUTA_DOCUMENT_ERROR
,
670 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
671 "No backup created");
676 bfd
= open (backup_filename
,
677 O_WRONLY
| O_CREAT
| O_EXCL
,
678 statbuf
.st_mode
& 0777);
682 g_set_error (&saver
->priv
->error
,
683 ANJUTA_DOCUMENT_ERROR
,
684 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
685 "No backup created");
690 /* Try to set the group of the backup same as the
691 * original file. If this fails, set the protection
692 * bits for the group same as the protection bits for
694 if (fchown (bfd
, (uid_t
) -1, statbuf
.st_gid
) != 0)
697 (statbuf
.st_mode
& 0707) |
698 ((statbuf
.st_mode
& 07) << 3)) != 0)
700 g_set_error (&saver
->priv
->error
,
701 ANJUTA_DOCUMENT_ERROR
,
702 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
703 "No backup created");
705 unlink (backup_filename
);
712 if (!copy_file_data (saver
->priv
->fd
, bfd
, NULL
))
714 g_set_error (&saver
->priv
->error
,
715 ANJUTA_DOCUMENT_ERROR
,
716 ANJUTA_DOCUMENT_ERROR_CANT_CREATE_BACKUP
,
717 "No backup created");
719 unlink (backup_filename
);
725 backup_created
= TRUE
;
729 /* finally overwrite the original */
730 if (!write_document_contents (saver
->priv
->fd
,
731 GTK_TEXT_BUFFER (saver
->priv
->document
),
732 saver
->priv
->encoding
,
733 &saver
->priv
->error
))
738 /* remove the backup if we don't want to keep it */
739 if (backup_created
&& !saver
->priv
->keep_backup
)
741 unlink (backup_filename
);
744 /* re stat the file and refetch the mime type */
745 if (fstat (saver
->priv
->fd
, &new_statbuf
) != 0)
747 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
749 g_set_error (&saver
->priv
->error
,
750 ANJUTA_DOCUMENT_ERROR
,
752 "%s", gnome_vfs_result_to_string (result
));
757 saver
->priv
->doc_mtime
= new_statbuf
.st_mtime
;
759 g_free (saver
->priv
->mime_type
);
760 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
763 if (close (saver
->priv
->fd
))
764 g_warning ("File '%s' has not been correctly closed: %s",
767 saver
->priv
->fd
= -1;
769 g_free (backup_filename
);
771 save_completed_or_failed (saver
);
773 /* stop the timeout */
778 save_new_local_file (AnjutaDocumentSaver
*saver
)
782 if (!write_document_contents (saver
->priv
->fd
,
783 GTK_TEXT_BUFFER (saver
->priv
->document
),
784 saver
->priv
->encoding
,
785 &saver
->priv
->error
))
790 /* stat the file and fetch the mime type */
791 if (fstat (saver
->priv
->fd
, &statbuf
) != 0)
793 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
795 g_set_error (&saver
->priv
->error
,
796 ANJUTA_DOCUMENT_ERROR
,
798 "%s", gnome_vfs_result_to_string (result
));
803 saver
->priv
->doc_mtime
= statbuf
.st_mtime
;
805 g_free (saver
->priv
->mime_type
);
806 saver
->priv
->mime_type
= get_slow_mime_type (saver
->priv
->uri
);
809 if (close (saver
->priv
->fd
))
810 g_warning ("File '%s' has not been correctly closed: %s",
814 saver
->priv
->fd
= -1;
816 save_completed_or_failed (saver
);
818 /* stop the timeout */
823 open_local_failed (AnjutaDocumentSaver
*saver
)
825 save_completed_or_failed (saver
);
827 /* stop the timeout */
832 save_local_file (AnjutaDocumentSaver
*saver
)
834 GSourceFunc next_phase
;
835 GnomeVFSResult result
;
838 g_signal_emit (saver
,
844 /* the file doesn't exist, create it */
845 saver
->priv
->fd
= open (saver
->priv
->local_path
,
846 O_CREAT
| O_EXCL
| O_WRONLY
,
848 if (saver
->priv
->fd
!= -1)
850 next_phase
= (GSourceFunc
) save_new_local_file
;
854 /* the file already exist */
855 else if (errno
== EEXIST
)
857 saver
->priv
->fd
= open (saver
->priv
->local_path
, O_RDWR
);
858 if (saver
->priv
->fd
!= -1)
860 next_phase
= (GSourceFunc
) save_existing_local_file
;
866 result
= gnome_vfs_result_from_errno (); //may it happen that no errno?
868 g_set_error (&saver
->priv
->error
,
869 ANJUTA_DOCUMENT_ERROR
,
871 "%s", gnome_vfs_result_to_string (result
));
873 next_phase
= (GSourceFunc
) open_local_failed
;
876 g_timeout_add_full (G_PRIORITY_HIGH
,
883 /* ----------- remote files ----------- */
886 remote_save_completed_or_failed (AnjutaDocumentSaver
*saver
)
888 /* we can now close and unlink the tmp file */
889 close (saver
->priv
->tmpfd
);
890 unlink (saver
->priv
->tmp_fname
);
892 save_completed_or_failed (saver
);
896 remote_get_info_cb (GnomeVFSAsyncHandle
*handle
,
900 AnjutaDocumentSaver
*saver
= ANJUTA_DOCUMENT_SAVER (data
);
901 GnomeVFSGetFileInfoResult
*info_result
;
903 /* assert that the list has one and only one item */
904 g_return_if_fail (results
!= NULL
&& results
->next
== NULL
);
906 info_result
= (GnomeVFSGetFileInfoResult
*) results
->data
;
907 g_return_if_fail (info_result
!= NULL
);
909 if (info_result
->result
!= GNOME_VFS_OK
)
911 g_set_error (&saver
->priv
->error
,
912 ANJUTA_DOCUMENT_ERROR
,
914 "%s", gnome_vfs_result_to_string (info_result
->result
));
916 remote_save_completed_or_failed (saver
);
921 if (info_result
->file_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
922 saver
->priv
->doc_mtime
= info_result
->file_info
->mtime
;
924 if (info_result
->file_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE
)
926 g_free (saver
->priv
->mime_type
);
927 saver
->priv
->mime_type
= g_strdup (info_result
->file_info
->mime_type
);
930 remote_save_completed_or_failed (saver
);
934 async_xfer_ok (GnomeVFSXferProgressInfo
*progress_info
,
935 AnjutaDocumentSaver
*saver
)
937 switch (progress_info
->phase
)
939 case GNOME_VFS_XFER_PHASE_INITIAL
:
941 case GNOME_VFS_XFER_CHECKING_DESTINATION
:
943 GnomeVFSFileInfo
*orig_info
;
946 /* we need to retrieve info ourselves too, since xfer
947 * doesn't allow to access it :(
948 * If that was not enough we need to do it sync or we are going
949 * to mess everything up
951 orig_info
= gnome_vfs_file_info_new ();
952 res
= gnome_vfs_get_file_info_uri (saver
->priv
->vfs_uri
,
954 GNOME_VFS_FILE_INFO_DEFAULT
|
955 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
);
957 if (res
== GNOME_VFS_ERROR_NOT_FOUND
)
959 /* ok, we are not overwriting, go on with the xfer */
963 if (res
!= GNOME_VFS_OK
)
965 // CHECK: do we want to ignore the error and try to go on anyway?
966 g_set_error (&saver
->priv
->error
,
967 ANJUTA_DOCUMENT_ERROR
,
969 "%s", gnome_vfs_result_to_string (res
));
976 /* check if someone else modified the file externally,
977 * except when "saving as", when saving a new doc (mtime = 0)
978 * or when the mtime check is explicitely disabled
980 if (orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_MTIME
)
982 if (saver
->priv
->doc_mtime
> 0 &&
983 orig_info
->mtime
!= saver
->priv
->doc_mtime
&&
984 ((saver
->priv
->flags
& ANJUTA_DOCUMENT_SAVE_IGNORE_MTIME
) == 0))
986 g_set_error (&saver
->priv
->error
,
987 ANJUTA_DOCUMENT_ERROR
,
988 ANJUTA_DOCUMENT_ERROR_EXTERNALLY_MODIFIED
,
989 "Externally modified");
996 /* store the original file info, so that we can restore permissions */
997 // FIXME: what about the case where we are usin "Save as" but overwriting a file... we don't want to restore perms
998 if (orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS
)
999 saver
->priv
->orig_info
= orig_info
;
1002 case GNOME_VFS_XFER_PHASE_COLLECTING
:
1003 case GNOME_VFS_XFER_PHASE_DELETESOURCE
: // why do we get this phase??
1005 case GNOME_VFS_XFER_PHASE_READYTOGO
:
1006 saver
->priv
->size
= progress_info
->bytes_total
;
1008 case GNOME_VFS_XFER_PHASE_OPENSOURCE
:
1009 case GNOME_VFS_XFER_PHASE_OPENTARGET
:
1010 case GNOME_VFS_XFER_PHASE_COPYING
:
1011 case GNOME_VFS_XFER_PHASE_WRITETARGET
:
1012 case GNOME_VFS_XFER_PHASE_CLOSETARGET
:
1013 if (progress_info
->bytes_copied
> 0)
1014 saver
->priv
->bytes_written
= MIN (progress_info
->total_bytes_copied
,
1015 progress_info
->bytes_total
);
1017 case GNOME_VFS_XFER_PHASE_FILECOMPLETED
:
1018 case GNOME_VFS_XFER_PHASE_CLEANUP
:
1020 case GNOME_VFS_XFER_PHASE_COMPLETED
:
1022 * Restore the permissions if needed and then refetch
1023 * info on our newly written file to get the mime etc */
1025 GList
*uri_list
= NULL
;
1027 /* Try is not as paranoid as the local version (GID)... it would take
1028 * yet another stat to do it...
1030 if (saver
->priv
->orig_info
!= NULL
&&
1031 (saver
->priv
->orig_info
->valid_fields
& GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS
))
1033 gnome_vfs_set_file_info_uri (saver
->priv
->vfs_uri
,
1034 saver
->priv
->orig_info
,
1035 GNOME_VFS_SET_FILE_INFO_PERMISSIONS
);
1037 // FIXME: for now is a blind try... do we want to error check?
1040 uri_list
= g_list_prepend (uri_list
, saver
->priv
->vfs_uri
);
1042 gnome_vfs_async_get_file_info (&saver
->priv
->info_handle
,
1044 GNOME_VFS_FILE_INFO_DEFAULT
|
1045 GNOME_VFS_FILE_INFO_GET_MIME_TYPE
|
1046 GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE
|
1047 GNOME_VFS_FILE_INFO_FOLLOW_LINKS
,
1048 GNOME_VFS_PRIORITY_MAX
,
1051 g_list_free (uri_list
);
1054 /* Phases we don't expect to see */
1055 case GNOME_VFS_XFER_PHASE_SETATTRIBUTES
:
1056 case GNOME_VFS_XFER_PHASE_CLOSESOURCE
:
1057 case GNOME_VFS_XFER_PHASE_MOVING
:
1058 case GNOME_VFS_XFER_PHASE_READSOURCE
:
1060 g_return_val_if_reached (0);
1063 /* signal the progress */
1064 g_signal_emit (saver
,
1074 async_xfer_error (GnomeVFSXferProgressInfo
*progress_info
,
1075 AnjutaDocumentSaver
*saver
)
1077 g_set_error (&saver
->priv
->error
,
1078 ANJUTA_DOCUMENT_ERROR
,
1079 progress_info
->vfs_status
,
1080 "%s", gnome_vfs_result_to_string (progress_info
->vfs_status
));
1082 remote_save_completed_or_failed (saver
);
1084 return GNOME_VFS_XFER_ERROR_ACTION_ABORT
;
1088 async_xfer_progress (GnomeVFSAsyncHandle
*handle
,
1089 GnomeVFSXferProgressInfo
*progress_info
,
1092 AnjutaDocumentSaver
*saver
= ANJUTA_DOCUMENT_SAVER (data
);
1094 switch (progress_info
->status
)
1096 case GNOME_VFS_XFER_PROGRESS_STATUS_OK
:
1097 return async_xfer_ok (progress_info
, saver
);
1098 case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR
:
1099 return async_xfer_error (progress_info
, saver
);
1101 /* we should never go in these */
1102 case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE
:
1103 case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE
:
1105 g_return_val_if_reached (0);
1110 save_remote_file_real (AnjutaDocumentSaver
*saver
)
1114 GnomeVFSURI
*tmp_vfs_uri
;
1115 GList
*source_uri_list
= NULL
;
1116 GList
*dest_uri_list
= NULL
;
1117 GnomeVFSResult result
;
1119 /* For remote files we use the following strategy:
1120 * we save to a local temp file and then transfer it
1121 * over to the requested location asyncronously.
1122 * There is no backup of the original remote file.
1125 /* We set the umask because some (buggy) implementations
1126 * of mkstemp() use permissions 0666 and we want 0600.
1128 saved_umask
= umask (0077);
1129 saver
->priv
->tmpfd
= g_file_open_tmp (".anjuta-save-XXXXXX",
1130 &saver
->priv
->tmp_fname
,
1131 &saver
->priv
->error
);
1132 umask (saved_umask
);
1134 if (saver
->priv
->tmpfd
== -1)
1136 GnomeVFSResult result
= gnome_vfs_result_from_errno ();
1138 g_set_error (&saver
->priv
->error
,
1139 ANJUTA_DOCUMENT_ERROR
,
1141 "%s", gnome_vfs_result_to_string (result
));
1143 /* in this case no need to close the tmp file */
1144 save_completed_or_failed (saver
);
1149 tmp_uri
= g_filename_to_uri (saver
->priv
->tmp_fname
,
1151 &saver
->priv
->error
);
1152 if (tmp_uri
== NULL
)
1157 tmp_vfs_uri
= gnome_vfs_uri_new (tmp_uri
);
1158 //needs error checking?
1162 source_uri_list
= g_list_prepend (source_uri_list
, tmp_vfs_uri
);
1163 dest_uri_list
= g_list_prepend (dest_uri_list
, saver
->priv
->vfs_uri
);
1165 if (!write_document_contents (saver
->priv
->tmpfd
,
1166 GTK_TEXT_BUFFER (saver
->priv
->document
),
1167 saver
->priv
->encoding
,
1168 &saver
->priv
->error
))
1173 result
= gnome_vfs_async_xfer (&saver
->priv
->handle
,
1176 GNOME_VFS_XFER_DEFAULT
| GNOME_VFS_XFER_TARGET_DEFAULT_PERMS
, // CHECK needs more thinking, follow symlinks etc... options are undocumented :(
1177 GNOME_VFS_XFER_ERROR_MODE_ABORT
, /* keep it simple, abort on any error */
1178 GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE
, /* We have already asked confirm (even if it is racy) */
1179 GNOME_VFS_PRIORITY_DEFAULT
,
1180 async_xfer_progress
, saver
,
1183 gnome_vfs_uri_unref (tmp_vfs_uri
);
1184 g_list_free (source_uri_list
);
1185 g_list_free (dest_uri_list
);
1187 if (result
!= GNOME_VFS_OK
)
1189 g_set_error (&saver
->priv
->error
,
1190 ANJUTA_DOCUMENT_ERROR
,
1192 "%s", gnome_vfs_result_to_string (result
));
1197 /* No errors: stop the timeout */
1201 remote_save_completed_or_failed (saver
);
1203 /* stop the timeout */
1208 save_remote_file (AnjutaDocumentSaver
*saver
)
1211 g_signal_emit (saver
,
1217 g_timeout_add_full (G_PRIORITY_HIGH
,
1219 (GSourceFunc
) save_remote_file_real
,
1224 /* ---------- public api ---------- */
1227 anjuta_document_saver_save (AnjutaDocumentSaver
*saver
,
1229 const AnjutaEncoding
*encoding
,
1231 AnjutaDocumentSaveFlags flags
)
1235 g_return_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
));
1236 g_return_if_fail ((uri
!= NULL
) && (strlen (uri
) > 0));
1239 // - sanity check a max len for the uri?
1240 // report async (in an idle handler) or sync (bool ret)
1241 // async is extra work here, sync is special casing in the caller
1243 saver
->priv
->uri
= g_strdup (uri
);
1245 /* fetch saving options */
1246 saver
->priv
->backup_ext
= g_strdup("~");
1248 /* never keep backup of autosaves */
1249 if ((flags
& ANJUTA_DOCUMENT_SAVE_PRESERVE_BACKUP
) != 0)
1250 saver
->priv
->keep_backup
= FALSE
;
1252 /* FIXME: This should be configurable */
1253 saver
->priv
->keep_backup
=TRUE
;
1255 /* TODO: add support for configurable backup dir */
1256 saver
->priv
->backups_in_curr_dir
= TRUE
;
1258 if (encoding
!= NULL
)
1259 saver
->priv
->encoding
= encoding
;
1261 saver
->priv
->encoding
= anjuta_encoding_get_utf8 ();
1263 saver
->priv
->doc_mtime
= oldmtime
;
1265 saver
->priv
->flags
= flags
;
1267 local_path
= gnome_vfs_get_local_path_from_uri (uri
);
1268 if (local_path
!= NULL
)
1270 saver
->priv
->local_path
= local_path
;
1271 save_local_file (saver
);
1275 saver
->priv
->vfs_uri
= gnome_vfs_uri_new (uri
);
1276 save_remote_file (saver
);
1281 anjuta_document_saver_get_uri (AnjutaDocumentSaver
*saver
)
1283 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), NULL
);
1285 return saver
->priv
->uri
;
1289 anjuta_document_saver_get_mime_type (AnjutaDocumentSaver
*saver
)
1291 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), NULL
);
1293 return saver
->priv
->mime_type
;
1297 anjuta_document_saver_get_mtime (AnjutaDocumentSaver
*saver
)
1299 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1301 return saver
->priv
->doc_mtime
;
1304 /* Returns 0 if file size is unknown */
1306 anjuta_document_saver_get_file_size (AnjutaDocumentSaver
*saver
)
1308 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1310 return saver
->priv
->size
;
1314 anjuta_document_saver_get_bytes_written (AnjutaDocumentSaver
*saver
)
1316 g_return_val_if_fail (ANJUTA_IS_DOCUMENT_SAVER (saver
), 0);
1318 return saver
->priv
->bytes_written
;