388
308
g_return_val_if_reached (FALSE);
391
/* The following function has been copied from gnome-vfs
392
(modules/file-method.c) file */
394
get_access_info (GnomeVFSFileInfo *file_info,
395
const gchar *full_name)
397
/* FIXME: should check errno after calling access because we don't
398
* want to set valid_fields if something bad happened during one
399
* of the access calls
401
if (g_access (full_name, W_OK) == 0)
402
file_info->permissions |= GNOME_VFS_PERM_ACCESS_WRITABLE;
405
* We don't need to know if a local file is readable or
406
* executable so I have commented the followig code to avoid
407
* multiple g_access calls - Paolo (Oct. 18, 2005)
411
* if (g_access (full_name, R_OK) == 0)
412
* file_info->permissions |= GNOME_VFS_PERM_ACCESS_READABLE;
415
* if (g_file_test (full_name, G_FILE_TEST_IS_EXECUTABLE))
416
* file_info->permissions |= GNOME_VFS_PERM_ACCESS_EXECUTABLE;
418
* if (g_access (full_name, X_OK) == 0)
419
* file_info->permissions |= GNOME_VFS_PERM_ACCESS_EXECUTABLE;
423
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_ACCESS;
426
/* The following function has been copied from gnome-vfs
427
(gnome-vfs-module-shared.c) file */
429
stat_to_file_info (GnomeVFSFileInfo *file_info,
430
const struct stat *statptr)
432
if (S_ISDIR (statptr->st_mode))
433
file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
434
else if (S_ISCHR (statptr->st_mode))
435
file_info->type = GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE;
436
else if (S_ISBLK (statptr->st_mode))
437
file_info->type = GNOME_VFS_FILE_TYPE_BLOCK_DEVICE;
438
else if (S_ISFIFO (statptr->st_mode))
439
file_info->type = GNOME_VFS_FILE_TYPE_FIFO;
440
else if (S_ISSOCK (statptr->st_mode))
441
file_info->type = GNOME_VFS_FILE_TYPE_SOCKET;
442
else if (S_ISREG (statptr->st_mode))
443
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
444
else if (S_ISLNK (statptr->st_mode))
445
file_info->type = GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;
447
file_info->type = GNOME_VFS_FILE_TYPE_UNKNOWN;
449
file_info->permissions
450
= statptr->st_mode & (GNOME_VFS_PERM_USER_ALL
451
| GNOME_VFS_PERM_GROUP_ALL
452
| GNOME_VFS_PERM_OTHER_ALL
453
| GNOME_VFS_PERM_SUID
454
| GNOME_VFS_PERM_SGID
455
| GNOME_VFS_PERM_STICKY);
457
file_info->device = statptr->st_dev;
458
file_info->inode = statptr->st_ino;
460
file_info->link_count = statptr->st_nlink;
462
file_info->uid = statptr->st_uid;
463
file_info->gid = statptr->st_gid;
465
file_info->size = statptr->st_size;
466
file_info->block_count = statptr->st_blocks;
467
file_info->io_block_size = statptr->st_blksize;
468
if (file_info->io_block_size > 0 &&
469
file_info->io_block_size < 4096) {
470
/* Never use smaller block than 4k,
471
should probably be pagesize.. */
472
file_info->io_block_size = 4096;
475
file_info->atime = statptr->st_atime;
476
file_info->ctime = statptr->st_ctime;
477
file_info->mtime = statptr->st_mtime;
479
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE |
480
GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS | GNOME_VFS_FILE_INFO_FIELDS_FLAGS |
481
GNOME_VFS_FILE_INFO_FIELDS_DEVICE | GNOME_VFS_FILE_INFO_FIELDS_INODE |
482
GNOME_VFS_FILE_INFO_FIELDS_LINK_COUNT | GNOME_VFS_FILE_INFO_FIELDS_SIZE |
483
GNOME_VFS_FILE_INFO_FIELDS_BLOCK_COUNT | GNOME_VFS_FILE_INFO_FIELDS_IO_BLOCK_SIZE |
484
GNOME_VFS_FILE_INFO_FIELDS_ATIME | GNOME_VFS_FILE_INFO_FIELDS_MTIME |
485
GNOME_VFS_FILE_INFO_FIELDS_CTIME;
489
load_completed_or_failed (GeditDocumentLoader *loader)
491
/* the object will be unrefed in the callback of the loading
492
* signal, so we need to prevent finalization.
494
g_object_ref (loader);
496
g_signal_emit (loader,
499
TRUE, /* completed */
500
loader->priv->error);
502
if (loader->priv->error == NULL)
503
gedit_debug_message (DEBUG_LOADER, "load completed");
505
gedit_debug_message (DEBUG_LOADER, "load failed");
507
g_object_unref (loader);
510
/* ----------- local files ----------- */
512
#define MAX_MIME_SNIFF_SIZE 4096
514
static sigjmp_buf mmap_env;
515
static struct sigaction old_sigbusact;
517
/* When we access the mmapped data we need to handle
518
* SIGBUS signal, which is emitted if there was an
519
* I/O error or if the file was truncated */
521
mmap_sigbus_handler (int signo)
523
siglongjmp (mmap_env, 0);
527
load_local_file_real (GeditDocumentLoader *loader)
530
GnomeVFSResult result;
533
g_return_val_if_fail (loader->priv->fd != -1, FALSE);
535
if (fstat (loader->priv->fd, &statbuf) != 0)
537
result = gnome_vfs_result_from_errno ();
539
g_set_error (&loader->priv->error,
540
GEDIT_DOCUMENT_ERROR,
542
gnome_vfs_result_to_string (result));
547
/* not a regular file */
548
if (!S_ISREG (statbuf.st_mode))
550
if (S_ISDIR (statbuf.st_mode))
552
g_set_error (&loader->priv->error,
553
GEDIT_DOCUMENT_ERROR,
554
GNOME_VFS_ERROR_IS_DIRECTORY,
555
gnome_vfs_result_to_string (GNOME_VFS_ERROR_IS_DIRECTORY));
559
g_set_error (&loader->priv->error,
560
GEDIT_DOCUMENT_ERROR,
561
GEDIT_DOCUMENT_ERROR_NOT_REGULAR_FILE,
562
"Not a regular file");
568
loader->priv->info = gnome_vfs_file_info_new ();
569
stat_to_file_info (loader->priv->info, &statbuf);
570
GNOME_VFS_FILE_INFO_SET_LOCAL (loader->priv->info, TRUE);
571
get_access_info (loader->priv->info, loader->priv->local_file_name);
573
if (loader->priv->info->size == 0)
575
if (loader->priv->encoding == NULL)
576
loader->priv->auto_detected_encoding = gedit_encoding_get_current ();
578
/* clear the contents in case we are reverting */
579
insert_text_in_document (loader, "", 0);
581
/* guessing the mime from the filename is up to the caller */
586
const gchar *mime_type;
587
struct sigaction sigbusact;
589
/* CHECK: should we lock the file */
590
mapped_file = mmap (0, /* start */
591
loader->priv->info->size,
593
MAP_PRIVATE, /* flags */
597
if (mapped_file == MAP_FAILED)
599
gedit_debug_message (DEBUG_LOADER, "mmap failed");
601
result = gnome_vfs_result_from_errno ();
603
g_set_error (&loader->priv->error,
604
GEDIT_DOCUMENT_ERROR,
606
gnome_vfs_result_to_string (result));
611
/* prepare to handle the SIGBUS signal which
612
* may be fired when accessing the mmapped
613
* data in case of I/O error.
616
sigbusact.sa_handler = mmap_sigbus_handler;
617
sigemptyset (&sigbusact.sa_mask);
618
sigbusact.sa_flags = SA_RESETHAND;
619
sigaction (SIGBUS, &sigbusact, &old_sigbusact );
621
if (sigsetjmp (mmap_env, 1) != 0)
623
gedit_debug_message (DEBUG_LOADER, "SIGBUS during mmap");
625
g_set_error (&loader->priv->error,
626
GEDIT_DOCUMENT_ERROR,
628
gnome_vfs_result_to_string (GNOME_VFS_ERROR_IO));
630
ret = munmap (mapped_file, loader->priv->info->size);
632
g_warning ("File '%s' has not been correctly unmapped: %s",
639
loader->priv->bytes_read = loader->priv->info->size;
641
if (!update_document_contents (loader,
643
loader->priv->info->size,
644
&loader->priv->error))
646
ret = munmap (mapped_file, loader->priv->info->size);
648
g_warning ("File '%s' has not been correctly unmapped: %s",
655
/* restore the default sigbus handler */
656
sigaction (SIGBUS, &old_sigbusact, 0);
658
mime_type = gnome_vfs_get_mime_type_for_name_and_data (loader->priv->local_file_name,
660
MIN (loader->priv->bytes_read, MAX_MIME_SNIFF_SIZE));
662
if ((mime_type != NULL) &&
663
strcmp (mime_type, GNOME_VFS_MIME_TYPE_UNKNOWN) != 0)
665
loader->priv->info->mime_type = g_strdup (mime_type);
666
loader->priv->info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE;
669
ret = munmap (mapped_file, loader->priv->info->size);
672
g_warning ("File '%s' has not been correctly unmapped: %s",
678
ret = close (loader->priv->fd);
681
g_warning ("File '%s' has not been correctly closed: %s",
685
loader->priv->fd = -1;
687
load_completed_or_failed (loader);
693
open_local_failed (GeditDocumentLoader *loader)
695
load_completed_or_failed (loader);
697
/* stop the timeout */
702
load_local_file (GeditDocumentLoader *loader,
705
gedit_debug (DEBUG_LOADER);
707
g_signal_emit (loader,
713
loader->priv->fd = open (fname, O_RDONLY);
714
if (loader->priv->fd == -1)
716
GnomeVFSResult result = gnome_vfs_result_from_errno ();
718
g_set_error (&loader->priv->error,
719
GEDIT_DOCUMENT_ERROR,
721
gnome_vfs_result_to_string (result));
723
g_timeout_add_full (G_PRIORITY_HIGH,
725
(GSourceFunc) open_local_failed,
732
g_free (loader->priv->local_file_name);
733
loader->priv->local_file_name = g_strdup (fname);
735
g_timeout_add_full (G_PRIORITY_HIGH,
737
(GSourceFunc) load_local_file_real,
742
/* ----------- remote files ----------- */
745
async_close_cb (GnomeVFSAsyncHandle *handle,
746
GnomeVFSResult result,
749
/* nothing to do... no point in reporting an error */
753
remote_load_completed_or_failed (GeditDocumentLoader *loader)
755
/* free the buffer and close the handle */
756
gnome_vfs_async_close (loader->priv->handle,
760
loader->priv->handle = NULL;
762
g_free (loader->priv->buffer);
763
loader->priv->buffer = NULL;
765
load_completed_or_failed (loader);
768
/* prototype, because they call each other... isn't C lovely */
769
static void read_file_chunk (GeditDocumentLoader *loader);
772
async_read_cb (GnomeVFSAsyncHandle *handle,
773
GnomeVFSResult result,
775
GnomeVFSFileSize bytes_requested,
776
GnomeVFSFileSize bytes_read,
779
GeditDocumentLoader *loader = GEDIT_DOCUMENT_LOADER (data);
781
gedit_debug (DEBUG_LOADER);
783
/* reality checks. */
784
g_return_if_fail (bytes_requested == READ_CHUNK_SIZE);
785
g_return_if_fail (loader->priv->handle == handle);
786
g_return_if_fail (loader->priv->buffer + loader->priv->bytes_read == buffer);
787
g_return_if_fail (bytes_read <= bytes_requested);
790
if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF)
792
g_set_error (&loader->priv->error,
793
GEDIT_DOCUMENT_ERROR,
795
gnome_vfs_result_to_string (result));
797
remote_load_completed_or_failed (loader);
802
/* Check for the extremely unlikely case where the file size overflows. */
803
if (loader->priv->bytes_read + bytes_read < loader->priv->bytes_read)
805
g_set_error (&loader->priv->error,
806
GEDIT_DOCUMENT_ERROR,
807
GNOME_VFS_ERROR_TOO_BIG,
808
gnome_vfs_result_to_string (GNOME_VFS_ERROR_TOO_BIG));
810
remote_load_completed_or_failed (loader);
816
loader->priv->bytes_read += bytes_read;
818
/* end of the file, we are done! */
819
if (bytes_read == 0 || result != GNOME_VFS_OK)
821
if (loader->priv->bytes_read == 0)
823
if (loader->priv->encoding == NULL)
824
loader->priv->auto_detected_encoding = gedit_encoding_get_current ();
828
update_document_contents (loader,
829
loader->priv->buffer,
830
loader->priv->bytes_read,
831
&loader->priv->error);
834
remote_load_completed_or_failed (loader);
839
/* otherwise emit progress and read some more */
841
/* note that this signal blocks the read... check if it isn't
842
* a performance problem
844
g_signal_emit (loader,
850
read_file_chunk (loader);
854
read_file_chunk (GeditDocumentLoader *loader)
856
loader->priv->buffer = g_realloc (loader->priv->buffer,
857
loader->priv->bytes_read + READ_CHUNK_SIZE);
859
gnome_vfs_async_read (loader->priv->handle,
860
loader->priv->buffer + loader->priv->bytes_read,
867
remote_get_info_cb (GnomeVFSAsyncHandle *handle,
871
GeditDocumentLoader *loader = GEDIT_DOCUMENT_LOADER (data);
872
GnomeVFSGetFileInfoResult *info_result;
874
gedit_debug (DEBUG_LOADER);
876
/* assert that the list has one and only one item */
877
g_return_if_fail (results != NULL && results->next == NULL);
879
loader->priv->info_handle = NULL;
881
info_result = (GnomeVFSGetFileInfoResult *) results->data;
882
g_return_if_fail (info_result != NULL);
884
if (info_result->result != GNOME_VFS_OK)
886
g_set_error (&loader->priv->error,
887
GEDIT_DOCUMENT_ERROR,
889
gnome_vfs_result_to_string (info_result->result));
891
remote_load_completed_or_failed (loader);
896
/* CHECK: ref is necessary, right? or the info will go away... */
897
loader->priv->info = info_result->file_info;
898
gnome_vfs_file_info_ref (loader->priv->info);
900
/* if it's not a regular file, error out... */
901
if (info_result->file_info->type != GNOME_VFS_FILE_TYPE_REGULAR)
903
g_set_error (&loader->priv->error,
904
GEDIT_DOCUMENT_ERROR,
905
GEDIT_DOCUMENT_ERROR_NOT_REGULAR_FILE,
906
"Not a regular file");
908
remote_load_completed_or_failed (loader);
914
read_file_chunk (loader);
918
async_open_callback (GnomeVFSAsyncHandle *handle,
919
GnomeVFSResult result,
920
GeditDocumentLoader *loader)
922
GList *uri_list = NULL;
924
gedit_debug (DEBUG_LOADER);
926
g_return_if_fail (loader->priv->handle == handle);
928
if (result != GNOME_VFS_OK)
930
g_set_error (&loader->priv->error,
931
GEDIT_DOCUMENT_ERROR,
933
gnome_vfs_result_to_string (result));
935
/* in this case we don't need to close the handle */
936
load_completed_or_failed (loader);
941
/* get the file info after open to avoid races... this really
942
* should be async_get_file_info_from_handle (fstat equivalent)
943
* but gnome-vfs lacks that.
946
uri_list = g_list_prepend (uri_list, loader->priv->vfs_uri);
948
gnome_vfs_async_get_file_info (&loader->priv->info_handle,
950
GNOME_VFS_FILE_INFO_DEFAULT |
951
GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
952
GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE |
953
GNOME_VFS_FILE_INFO_FOLLOW_LINKS,
954
GNOME_VFS_PRIORITY_MAX,
958
g_list_free (uri_list);
962
load_remote_file (GeditDocumentLoader *loader)
964
gedit_debug (DEBUG_LOADER);
966
g_return_if_fail (loader->priv->handle == NULL);
969
g_signal_emit (loader,
975
gnome_vfs_async_open_uri (&loader->priv->handle,
976
loader->priv->vfs_uri,
978
GNOME_VFS_PRIORITY_MAX,
979
(GnomeVFSAsyncOpenCallback) async_open_callback,
983
/* ---------- public api ---------- */
986
vfs_uri_new_failed (GeditDocumentLoader *loader)
988
load_completed_or_failed (loader);
990
/* stop the timeout */
312
gedit_document_loader_loading (GeditDocumentLoader *loader,
316
/* the object will be unrefed in the callback of the loading signal
317
* (when completed == TRUE), so we need to prevent finalization.
321
g_object_ref (loader);
324
g_signal_emit (loader, signals[LOADING], 0, completed, error);
329
gedit_debug_message (DEBUG_LOADER, "load completed");
331
gedit_debug_message (DEBUG_LOADER, "load failed");
333
g_object_unref (loader);
337
static const GeditEncoding *
338
get_metadata_encoding (const gchar *uri)
340
const GeditEncoding *enc;
343
charset = gedit_metadata_manager_get (uri, "encoding");
348
enc = gedit_encoding_get_from_charset (charset);
355
GeditDocumentLoader *
356
gedit_document_loader_new (GeditDocument *doc,
358
const GeditEncoding *encoding)
360
GeditDocumentLoader *loader;
363
g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
365
if (gedit_utils_uri_has_file_scheme (uri))
366
loader_type = GEDIT_TYPE_MMAP_DOCUMENT_LOADER;
368
loader_type = GEDIT_TYPE_GNOMEVFS_DOCUMENT_LOADER;
370
loader = GEDIT_DOCUMENT_LOADER (g_object_new (loader_type,
373
"encoding", encoding,
994
379
/* If enconding == NULL, the encoding will be autodetected */
996
gedit_document_loader_load (GeditDocumentLoader *loader,
998
const GeditEncoding *encoding)
381
gedit_document_loader_load (GeditDocumentLoader *loader)
1002
383
gedit_debug (DEBUG_LOADER);
1004
385
g_return_if_fail (GEDIT_IS_DOCUMENT_LOADER (loader));
1005
g_return_if_fail (uri != NULL);
1007
387
/* the loader can be used just once, then it must be thrown away */
1008
g_return_if_fail (loader->priv->used == FALSE);
1009
loader->priv->used = TRUE;
1011
/* vfs_uri may be NULL for some valid but unsupported uris */
1012
loader->priv->vfs_uri = gnome_vfs_uri_new (uri);
1013
if (loader->priv->vfs_uri == NULL)
1015
g_set_error (&loader->priv->error,
1016
GEDIT_DOCUMENT_ERROR,
1017
GNOME_VFS_ERROR_NOT_SUPPORTED,
1018
gnome_vfs_result_to_string (GNOME_VFS_ERROR_NOT_SUPPORTED));
1020
g_timeout_add_full (G_PRIORITY_HIGH,
1022
(GSourceFunc) vfs_uri_new_failed,
1029
loader->priv->encoding = encoding;
1031
if (encoding == NULL)
1033
loader->priv->metadata_encoding = get_metadata_encoding (uri);
1036
loader->priv->uri = g_strdup (uri);
1038
local_path = gnome_vfs_get_local_path_from_uri (uri);
1039
if (local_path != NULL)
1041
load_local_file (loader, local_path);
1042
g_free (local_path);
1046
load_remote_file (loader);
388
g_return_if_fail (loader->used == FALSE);
391
if (loader->encoding == NULL)
392
loader->metadata_encoding = get_metadata_encoding (loader->uri);
394
GEDIT_DOCUMENT_LOADER_GET_CLASS (loader)->load (loader);
398
gedit_document_loader_cancel (GeditDocumentLoader *loader)
400
gedit_debug (DEBUG_LOADER);
402
g_return_val_if_fail (GEDIT_IS_DOCUMENT_LOADER (loader), FALSE);
404
return GEDIT_DOCUMENT_LOADER_GET_CLASS (loader)->cancel (loader);
1050
407
/* Returns STDIN_URI if loading from stdin */