1 /* GIO - GLib Input, Output and Streaming Library 2 * 3 * Copyright (C) 2006-2007 Red Hat, Inc. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General 16 * Public License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 18 * Boston, MA 02111-1307, USA. 19 * 20 * Author: Alexander Larsson <alexl (at) redhat.com> 21 */ 22 23 #include "config.h" 24 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <string.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #ifdef HAVE_UNISTD_H 31 #include <unistd.h> 32 #endif 33 34 #if HAVE_SYS_STATFS_H 35 #include <sys/statfs.h> 36 #endif 37 #if HAVE_SYS_STATVFS_H 38 #include <sys/statvfs.h> 39 #endif 40 #if HAVE_SYS_VFS_H 41 #include <sys/vfs.h> 42 #elif HAVE_SYS_MOUNT_H 43 #if HAVE_SYS_PARAM_H 44 #include <sys/param.h> 45 #endif 46 #include <sys/mount.h> 47 #endif 48 49 #ifndef O_BINARY 50 #define O_BINARY 0 51 #endif 52 53 #if defined(HAVE_STATFS) && defined(HAVE_STATVFS) 54 /* Some systems have both statfs and statvfs, pick the 55 most "native" for these */ 56 # if !defined(HAVE_STRUCT_STATFS_F_BAVAIL) 57 /* on solaris and irix, statfs doesn't even have the 58 f_bavail field */ 59 # define USE_STATVFS 60 # else 61 /* at least on linux, statfs is the actual syscall */ 62 # define USE_STATFS 63 # endif 64 65 #elif defined(HAVE_STATFS) 66 67 # define USE_STATFS 68 69 #elif defined(HAVE_STATVFS) 70 71 # define USE_STATVFS 72 73 #endif 74 75 #include "gfileattribute.h" 76 #include "glocalfile.h" 77 #include "glocalfileinfo.h" 78 #include "glocalfileenumerator.h" 79 #include "glocalfileinputstream.h" 80 #include "glocalfileoutputstream.h" 81 #include "glocaldirectorymonitor.h" 82 #include "glocalfilemonitor.h" 83 #include "gmountprivate.h" 84 #include "gunixmounts.h" 85 #include "gioerror.h" 86 #include <glib/gstdio.h> 87 #include "glibintl.h" 88 89 #ifdef G_OS_WIN32 90 #define _WIN32_WINNT 0x0500 91 #include <windows.h> 92 #include <io.h> 93 #include <direct.h> 94 95 #ifndef FILE_READ_ONLY_VOLUME 96 #define FILE_READ_ONLY_VOLUME 0x00080000 97 #endif 98 99 #ifndef S_ISDIR 100 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) 101 #endif 102 #ifndef S_ISLNK 103 #define S_ISLNK(m) (0) 104 #endif 105 #endif 106 107 #include "gioalias.h" 108 109 static void g_local_file_file_iface_init (GFileIface *iface); 110 111 static GFileAttributeInfoList *local_writable_attributes = NULL; 112 static GFileAttributeInfoList *local_writable_namespaces = NULL; 113 114 struct _GLocalFile 115 { 116 GObject parent_instance; 117 118 char *filename; 119 }; 120 121 #define g_local_file_get_type _g_local_file_get_type 122 G_DEFINE_TYPE_WITH_CODE (GLocalFile, g_local_file, G_TYPE_OBJECT, 123 G_IMPLEMENT_INTERFACE (G_TYPE_FILE, 124 g_local_file_file_iface_init)) 125 126 static char *find_mountpoint_for (const char *file, dev_t dev); 127 128 static void 129 g_local_file_finalize (GObject *object) 130 { 131 GLocalFile *local; 132 133 local = G_LOCAL_FILE (object); 134 135 g_free (local->filename); 136 137 G_OBJECT_CLASS (g_local_file_parent_class)->finalize (object); 138 } 139 140 static void 141 g_local_file_class_init (GLocalFileClass *klass) 142 { 143 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 144 GFileAttributeInfoList *list; 145 146 gobject_class->finalize = g_local_file_finalize; 147 148 /* Set up attribute lists */ 149 150 /* Writable attributes: */ 151 152 list = g_file_attribute_info_list_new (); 153 154 g_file_attribute_info_list_add (list, 155 G_FILE_ATTRIBUTE_UNIX_MODE, 156 G_FILE_ATTRIBUTE_TYPE_UINT32, 157 G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE | 158 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 159 160 #ifdef HAVE_CHOWN 161 g_file_attribute_info_list_add (list, 162 G_FILE_ATTRIBUTE_UNIX_UID, 163 G_FILE_ATTRIBUTE_TYPE_UINT32, 164 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 165 g_file_attribute_info_list_add (list, 166 G_FILE_ATTRIBUTE_UNIX_GID, 167 G_FILE_ATTRIBUTE_TYPE_UINT32, 168 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 169 #endif 170 171 #ifdef HAVE_SYMLINK 172 g_file_attribute_info_list_add (list, 173 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, 174 G_FILE_ATTRIBUTE_TYPE_BYTE_STRING, 175 0); 176 #endif 177 178 #ifdef HAVE_UTIMES 179 g_file_attribute_info_list_add (list, 180 G_FILE_ATTRIBUTE_TIME_MODIFIED, 181 G_FILE_ATTRIBUTE_TYPE_UINT64, 182 G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE | 183 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 184 g_file_attribute_info_list_add (list, 185 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 186 G_FILE_ATTRIBUTE_TYPE_UINT32, 187 G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE | 188 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 189 /* When copying, the target file is accessed. Replicating 190 * the source access time does not make sense in this case. 191 */ 192 g_file_attribute_info_list_add (list, 193 G_FILE_ATTRIBUTE_TIME_ACCESS, 194 G_FILE_ATTRIBUTE_TYPE_UINT64, 195 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 196 g_file_attribute_info_list_add (list, 197 G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, 198 G_FILE_ATTRIBUTE_TYPE_UINT32, 199 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 200 #endif 201 202 local_writable_attributes = list; 203 204 /* Writable namespaces: */ 205 206 list = g_file_attribute_info_list_new (); 207 208 #ifdef HAVE_XATTR 209 g_file_attribute_info_list_add (list, 210 "xattr", 211 G_FILE_ATTRIBUTE_TYPE_STRING, 212 G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE | 213 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 214 g_file_attribute_info_list_add (list, 215 "xattr-sys", 216 G_FILE_ATTRIBUTE_TYPE_STRING, 217 G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED); 218 #endif 219 220 local_writable_namespaces = list; 221 } 222 223 static void 224 g_local_file_init (GLocalFile *local) 225 { 226 } 227 228 229 static char * 230 canonicalize_filename (const char *filename) 231 { 232 char *canon, *start, *p, *q; 233 char *cwd; 234 int i; 235 236 if (!g_path_is_absolute (filename)) 237 { 238 cwd = g_get_current_dir (); 239 canon = g_build_filename (cwd, filename, NULL); 240 g_free (cwd); 241 } 242 else 243 canon = g_strdup (filename); 244 245 start = (char *)g_path_skip_root (canon); 246 247 if (start == NULL) 248 { 249 /* This shouldn't really happen, as g_get_current_dir() should 250 return an absolute pathname, but bug 573843 shows this is 251 not always happening */ 252 g_free (canon); 253 return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL); 254 } 255 256 /* POSIX allows double slashes at the start to 257 * mean something special (as does windows too). 258 * So, "//" != "/", but more than two slashes 259 * is treated as "/". 260 */ 261 i = 0; 262 for (p = start - 1; 263 (p >= canon) && 264 G_IS_DIR_SEPARATOR (*p); 265 p--) 266 i++; 267 if (i > 2) 268 { 269 i -= 1; 270 start -= i; 271 memmove (start, start+i, strlen (start+i)+1); 272 } 273 274 p = start; 275 while (*p != 0) 276 { 277 if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) 278 { 279 memmove (p, p+1, strlen (p+1)+1); 280 } 281 else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) 282 { 283 q = p + 2; 284 /* Skip previous separator */ 285 p = p - 2; 286 if (p < start) 287 p = start; 288 while (p > start && !G_IS_DIR_SEPARATOR (*p)) 289 p--; 290 if (G_IS_DIR_SEPARATOR (*p)) 291 *p++ = G_DIR_SEPARATOR; 292 memmove (p, q, strlen (q)+1); 293 } 294 else 295 { 296 /* Skip until next separator */ 297 while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) 298 p++; 299 300 if (*p != 0) 301 { 302 /* Canonicalize one separator */ 303 *p++ = G_DIR_SEPARATOR; 304 } 305 } 306 307 /* Remove additional separators */ 308 q = p; 309 while (*q && G_IS_DIR_SEPARATOR (*q)) 310 q++; 311 312 if (p != q) 313 memmove (p, q, strlen (q)+1); 314 } 315 316 /* Remove trailing slashes */ 317 if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) 318 *(p-1) = 0; 319 320 return canon; 321 } 322 323 /** 324 * _g_local_file_new: 325 * @filename: filename of the file to create. 326 * 327 * Returns: new local #GFile. 328 **/ 329 GFile * 330 _g_local_file_new (const char *filename) 331 { 332 GLocalFile *local; 333 334 local = g_object_new (G_TYPE_LOCAL_FILE, NULL); 335 local->filename = canonicalize_filename (filename); 336 337 return G_FILE (local); 338 } 339 340 static gboolean 341 g_local_file_is_native (GFile *file) 342 { 343 return TRUE; 344 } 345 346 static gboolean 347 g_local_file_has_uri_scheme (GFile *file, 348 const char *uri_scheme) 349 { 350 return g_ascii_strcasecmp (uri_scheme, "file") == 0; 351 } 352 353 static char * 354 g_local_file_get_uri_scheme (GFile *file) 355 { 356 return g_strdup ("file"); 357 } 358 359 static char * 360 g_local_file_get_basename (GFile *file) 361 { 362 return g_path_get_basename (G_LOCAL_FILE (file)->filename); 363 } 364 365 static char * 366 g_local_file_get_path (GFile *file) 367 { 368 return g_strdup (G_LOCAL_FILE (file)->filename); 369 } 370 371 static char * 372 g_local_file_get_uri (GFile *file) 373 { 374 return g_filename_to_uri (G_LOCAL_FILE (file)->filename, NULL, NULL); 375 } 376 377 static gboolean 378 get_filename_charset (const gchar **filename_charset) 379 { 380 const gchar **charsets; 381 gboolean is_utf8; 382 383 is_utf8 = g_get_filename_charsets (&charsets); 384 385 if (filename_charset) 386 *filename_charset = charsets[0]; 387 388 return is_utf8; 389 } 390 391 static gboolean 392 name_is_valid_for_display (const char *string, 393 gboolean is_valid_utf8) 394 { 395 char c; 396 397 if (!is_valid_utf8 && 398 !g_utf8_validate (string, -1, NULL)) 399 return FALSE; 400 401 while ((c = *string++) != 0) 402 { 403 if (g_ascii_iscntrl (c)) 404 return FALSE; 405 } 406 407 return TRUE; 408 } 409 410 static char * 411 g_local_file_get_parse_name (GFile *file) 412 { 413 const char *filename; 414 char *parse_name; 415 const gchar *charset; 416 char *utf8_filename; 417 char *roundtripped_filename; 418 gboolean free_utf8_filename; 419 gboolean is_valid_utf8; 420 char *escaped_path; 421 422 filename = G_LOCAL_FILE (file)->filename; 423 if (get_filename_charset (&charset)) 424 { 425 utf8_filename = (char *)filename; 426 free_utf8_filename = FALSE; 427 is_valid_utf8 = FALSE; /* Can't guarantee this */ 428 } 429 else 430 { 431 utf8_filename = g_convert (filename, -1, 432 "UTF-8", charset, NULL, NULL, NULL); 433 free_utf8_filename = TRUE; 434 is_valid_utf8 = TRUE; 435 436 if (utf8_filename != NULL) 437 { 438 /* Make sure we can roundtrip: */ 439 roundtripped_filename = g_convert (utf8_filename, -1, 440 charset, "UTF-8", NULL, NULL, NULL); 441 442 if (roundtripped_filename == NULL || 443 strcmp (utf8_filename, roundtripped_filename) != 0) 444 { 445 g_free (utf8_filename); 446 utf8_filename = NULL; 447 } 448 449 g_free (roundtripped_filename); 450 } 451 } 452 453 if (utf8_filename != NULL && 454 name_is_valid_for_display (utf8_filename, is_valid_utf8)) 455 { 456 if (free_utf8_filename) 457 parse_name = utf8_filename; 458 else 459 parse_name = g_strdup (utf8_filename); 460 } 461 else 462 { 463 escaped_path = g_uri_escape_string (filename, 464 G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/", 465 TRUE); 466 parse_name = g_strconcat ("file://", 467 (*escaped_path != '/') ? "/" : "", 468 escaped_path, 469 NULL); 470 471 g_free (escaped_path); 472 473 if (free_utf8_filename) 474 g_free (utf8_filename); 475 } 476 477 return parse_name; 478 } 479 480 static GFile * 481 g_local_file_get_parent (GFile *file) 482 { 483 GLocalFile *local = G_LOCAL_FILE (file); 484 const char *non_root; 485 char *dirname; 486 GFile *parent; 487 488 /* Check for root */ 489 non_root = g_path_skip_root (local->filename); 490 if (*non_root == 0) 491 return NULL; 492 493 dirname = g_path_get_dirname (local->filename); 494 parent = _g_local_file_new (dirname); 495 g_free (dirname); 496 return parent; 497 } 498 499 static GFile * 500 g_local_file_dup (GFile *file) 501 { 502 GLocalFile *local = G_LOCAL_FILE (file); 503 504 return _g_local_file_new (local->filename); 505 } 506 507 static guint 508 g_local_file_hash (GFile *file) 509 { 510 GLocalFile *local = G_LOCAL_FILE (file); 511 512 return g_str_hash (local->filename); 513 } 514 515 static gboolean 516 g_local_file_equal (GFile *file1, 517 GFile *file2) 518 { 519 GLocalFile *local1 = G_LOCAL_FILE (file1); 520 GLocalFile *local2 = G_LOCAL_FILE (file2); 521 522 return g_str_equal (local1->filename, local2->filename); 523 } 524 525 static const char * 526 match_prefix (const char *path, 527 const char *prefix) 528 { 529 int prefix_len; 530 531 prefix_len = strlen (prefix); 532 if (strncmp (path, prefix, prefix_len) != 0) 533 return NULL; 534 535 /* Handle the case where prefix is the root, so that 536 * the IS_DIR_SEPRARATOR check below works */ 537 if (prefix_len > 0 && 538 G_IS_DIR_SEPARATOR (prefix[prefix_len-1])) 539 prefix_len--; 540 541 return path + prefix_len; 542 } 543 544 static gboolean 545 g_local_file_prefix_matches (GFile *parent, 546 GFile *descendant) 547 { 548 GLocalFile *parent_local = G_LOCAL_FILE (parent); 549 GLocalFile *descendant_local = G_LOCAL_FILE (descendant); 550 const char *remainder; 551 552 remainder = match_prefix (descendant_local->filename, parent_local->filename); 553 if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder)) 554 return TRUE; 555 return FALSE; 556 } 557 558 static char * 559 g_local_file_get_relative_path (GFile *parent, 560 GFile *descendant) 561 { 562 GLocalFile *parent_local = G_LOCAL_FILE (parent); 563 GLocalFile *descendant_local = G_LOCAL_FILE (descendant); 564 const char *remainder; 565 566 remainder = match_prefix (descendant_local->filename, parent_local->filename); 567 568 if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder)) 569 return g_strdup (remainder + 1); 570 return NULL; 571 } 572 573 static GFile * 574 g_local_file_resolve_relative_path (GFile *file, 575 const char *relative_path) 576 { 577 GLocalFile *local = G_LOCAL_FILE (file); 578 char *filename; 579 GFile *child; 580 581 if (g_path_is_absolute (relative_path)) 582 return _g_local_file_new (relative_path); 583 584 filename = g_build_filename (local->filename, relative_path, NULL); 585 child = _g_local_file_new (filename); 586 g_free (filename); 587 588 return child; 589 } 590 591 static GFileEnumerator * 592 g_local_file_enumerate_children (GFile *file, 593 const char *attributes, 594 GFileQueryInfoFlags flags, 595 GCancellable *cancellable, 596 GError **error) 597 { 598 GLocalFile *local = G_LOCAL_FILE (file); 599 return _g_local_file_enumerator_new (local, 600 attributes, flags, 601 cancellable, error); 602 } 603 604 static GFile * 605 g_local_file_get_child_for_display_name (GFile *file, 606 const char *display_name, 607 GError **error) 608 { 609 GFile *new_file; 610 char *basename; 611 612 basename = g_filename_from_utf8 (display_name, -1, NULL, NULL, NULL); 613 if (basename == NULL) 614 { 615 g_set_error (error, G_IO_ERROR, 616 G_IO_ERROR_INVALID_FILENAME, 617 _("Invalid filename %s"), display_name); 618 return NULL; 619 } 620 621 new_file = g_file_get_child (file, basename); 622 g_free (basename); 623 624 return new_file; 625 } 626 627 #ifdef USE_STATFS 628 static const char * 629 get_fs_type (long f_type) 630 { 631 /* filesystem ids taken from linux manpage */ 632 switch (f_type) 633 { 634 case 0xadf5: 635 return "adfs"; 636 case 0x5346414f: 637 return "afs"; 638 case 0x0187: 639 return "autofs"; 640 case 0xADFF: 641 return "affs"; 642 case 0x42465331: 643 return "befs"; 644 case 0x1BADFACE: 645 return "bfs"; 646 case 0x9123683E: 647 return "btrfs"; 648 case 0xFF534D42: 649 return "cifs"; 650 case 0x73757245: 651 return "coda"; 652 case 0x012FF7B7: 653 return "coh"; 654 case 0x28cd3d45: 655 return "cramfs"; 656 case 0x1373: 657 return "devfs"; 658 case 0x00414A53: 659 return "efs"; 660 case 0x137D: 661 return "ext"; 662 case 0xEF51: 663 return "ext2"; 664 case 0xEF53: 665 return "ext3/ext4"; 666 case 0x4244: 667 return "hfs"; 668 case 0xF995E849: 669 return "hpfs"; 670 case 0x958458f6: 671 return "hugetlbfs"; 672 case 0x9660: 673 return "isofs"; 674 case 0x72b6: 675 return "jffs2"; 676 case 0x3153464a: 677 return "jfs"; 678 case 0x137F: 679 return "minix"; 680 case 0x138F: 681 return "minix2"; 682 case 0x2468: 683 return "minix2"; 684 case 0x2478: 685 return "minix22"; 686 case 0x4d44: 687 return "msdos"; 688 case 0x564c: 689 return "ncp"; 690 case 0x6969: 691 return "nfs"; 692 case 0x5346544e: 693 return "ntfs"; 694 case 0x9fa1: 695 return "openprom"; 696 case 0x9fa0: 697 return "proc"; 698 case 0x002f: 699 return "qnx4"; 700 case 0x52654973: 701 return "reiserfs"; 702 case 0x7275: 703 return "romfs"; 704 case 0x517B: 705 return "smb"; 706 case 0x73717368: 707 return "squashfs"; 708 case 0x012FF7B6: 709 return "sysv2"; 710 case 0x012FF7B5: 711 return "sysv4"; 712 case 0x01021994: 713 return "tmpfs"; 714 case 0x15013346: 715 return "udf"; 716 case 0x00011954: 717 return "ufs"; 718 case 0x9fa2: 719 return "usbdevice"; 720 case 0xa501FCF5: 721 return "vxfs"; 722 case 0x012FF7B4: 723 return "xenix"; 724 case 0x58465342: 725 return "xfs"; 726 case 0x012FD16D: 727 return "xiafs"; 728 default: 729 return NULL; 730 } 731 } 732 #endif 733 734 #ifndef G_OS_WIN32 735 736 G_LOCK_DEFINE_STATIC(mount_info_hash); 737 static GHashTable *mount_info_hash = NULL; 738 static guint64 mount_info_hash_cache_time = 0; 739 740 typedef enum { 741 MOUNT_INFO_READONLY = 1<<0 742 } MountInfo; 743 744 static gboolean 745 device_equal (gconstpointer v1, 746 gconstpointer v2) 747 { 748 return *(dev_t *)v1 == *(dev_t *)v2; 749 } 750 751 static guint 752 device_hash (gconstpointer v) 753 { 754 return (guint) *(dev_t *)v; 755 } 756 757 static void 758 get_mount_info (GFileInfo *fs_info, 759 const char *path, 760 GFileAttributeMatcher *matcher) 761 { 762 struct stat buf; 763 gboolean got_info; 764 gpointer info_as_ptr; 765 guint mount_info; 766 char *mountpoint; 767 dev_t *dev; 768 GUnixMountEntry *mount; 769 guint64 cache_time; 770 771 if (g_lstat (path, &buf) != 0) 772 return; 773 774 G_LOCK (mount_info_hash); 775 776 if (mount_info_hash == NULL) 777 mount_info_hash = g_hash_table_new_full (device_hash, device_equal, 778 g_free, NULL); 779 780 781 if (g_unix_mounts_changed_since (mount_info_hash_cache_time)) 782 g_hash_table_remove_all (mount_info_hash); 783 784 got_info = g_hash_table_lookup_extended (mount_info_hash, 785 &buf.st_dev, 786 NULL, 787 &info_as_ptr); 788 789 G_UNLOCK (mount_info_hash); 790 791 mount_info = GPOINTER_TO_UINT (info_as_ptr); 792 793 if (!got_info) 794 { 795 mount_info = 0; 796 797 mountpoint = find_mountpoint_for (path, buf.st_dev); 798 if (mountpoint == NULL) 799 mountpoint = g_strdup ("/"); 800 801 mount = g_unix_mount_at (mountpoint, &cache_time); 802 if (mount) 803 { 804 if (g_unix_mount_is_readonly (mount)) 805 mount_info |= MOUNT_INFO_READONLY; 806 807 g_unix_mount_free (mount); 808 } 809 810 g_free (mountpoint); 811 812 dev = g_new0 (dev_t, 1); 813 *dev = buf.st_dev; 814 815 G_LOCK (mount_info_hash); 816 mount_info_hash_cache_time = cache_time; 817 g_hash_table_insert (mount_info_hash, dev, GUINT_TO_POINTER (mount_info)); 818 G_UNLOCK (mount_info_hash); 819 } 820 821 if (mount_info & MOUNT_INFO_READONLY) 822 g_file_info_set_attribute_boolean (fs_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE); 823 } 824 825 #endif 826 827 #ifdef G_OS_WIN32 828 829 static gboolean 830 is_xp_or_later (void) 831 { 832 static int result = -1; 833 834 if (result == -1) 835 { 836 #ifndef _MSC_VER 837 OSVERSIONINFOEX ver_info = {0}; 838 DWORDLONG cond_mask = 0; 839 int op = VER_GREATER_EQUAL; 840 841 ver_info.dwOSVersionInfoSize = sizeof ver_info; 842 ver_info.dwMajorVersion = 5; 843 ver_info.dwMinorVersion = 1; 844 845 VER_SET_CONDITION (cond_mask, VER_MAJORVERSION, op); 846 VER_SET_CONDITION (cond_mask, VER_MINORVERSION, op); 847 848 result = VerifyVersionInfo (&ver_info, 849 VER_MAJORVERSION | VER_MINORVERSION, 850 cond_mask) != 0; 851 #else 852 result = ((DWORD)(LOBYTE (LOWORD (GetVersion ())))) >= 5; 853 #endif 854 } 855 856 return result; 857 } 858 859 static wchar_t * 860 get_volume_for_path (const char *path) 861 { 862 long len; 863 wchar_t *wpath; 864 wchar_t *result; 865 866 wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); 867 result = g_new (wchar_t, MAX_PATH); 868 869 if (!GetVolumePathNameW (wpath, result, MAX_PATH)) 870 { 871 char *msg = g_win32_error_message (GetLastError ()); 872 g_critical ("GetVolumePathName failed: %s", msg); 873 g_free (msg); 874 g_free (result); 875 g_free (wpath); 876 return NULL; 877 } 878 879 len = wcslen (result); 880 if (len > 0 && result[len-1] != L'\\') 881 { 882 result = g_renew (wchar_t, result, len + 2); 883 result[len] = L'\\'; 884 result[len + 1] = 0; 885 } 886 887 g_free (wpath); 888 return result; 889 } 890 891 static char * 892 find_mountpoint_for (const char *file, dev_t dev) 893 { 894 wchar_t *wpath; 895 char *utf8_path; 896 897 wpath = get_volume_for_path (file); 898 if (!wpath) 899 return NULL; 900 901 utf8_path = g_utf16_to_utf8 (wpath, -1, NULL, NULL, NULL); 902 903 g_free (wpath); 904 return utf8_path; 905 } 906 907 static void 908 get_filesystem_readonly (GFileInfo *info, 909 const char *path) 910 { 911 wchar_t *rootdir; 912 913 rootdir = get_volume_for_path (path); 914 915 if (rootdir) 916 { 917 if (is_xp_or_later ()) 918 { 919 DWORD flags; 920 if (GetVolumeInformationW (rootdir, NULL, 0, NULL, NULL, &flags, NULL, 0)) 921 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, 922 (flags & FILE_READ_ONLY_VOLUME) != 0); 923 } 924 else 925 { 926 if (GetDriveTypeW (rootdir) == DRIVE_CDROM) 927 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE); 928 } 929 } 930 931 g_free (rootdir); 932 } 933 934 #endif /* G_OS_WIN32 */ 935 936 static GFileInfo * 937 g_local_file_query_filesystem_info (GFile *file, 938 const char *attributes, 939 GCancellable *cancellable, 940 GError **error) 941 { 942 GLocalFile *local = G_LOCAL_FILE (file); 943 GFileInfo *info; 944 int statfs_result = 0; 945 gboolean no_size; 946 #ifndef G_OS_WIN32 947 guint64 block_size; 948 const char *fstype; 949 #ifdef USE_STATFS 950 struct statfs statfs_buffer; 951 #elif defined(USE_STATVFS) 952 struct statvfs statfs_buffer; 953 #endif 954 #endif 955 GFileAttributeMatcher *attribute_matcher; 956 957 no_size = FALSE; 958 959 #ifdef USE_STATFS 960 961 #if STATFS_ARGS == 2 962 statfs_result = statfs (local->filename, &statfs_buffer); 963 #elif STATFS_ARGS == 4 964 statfs_result = statfs (local->filename, &statfs_buffer, 965 sizeof (statfs_buffer), 0); 966 #endif 967 block_size = statfs_buffer.f_bsize; 968 969 /* Many backends can't report free size (for instance the gvfs fuse 970 backend for backend not supporting this), and set f_bfree to 0, 971 but it can be 0 for real too. We treat the availible == 0 and 972 free == 0 case as "both of these are invalid". 973 */ 974 #ifndef G_OS_WIN32 975 if (statfs_buffer.f_bavail == 0 && statfs_buffer.f_bfree == 0) 976 no_size = TRUE; 977 #endif 978 979 #elif defined(USE_STATVFS) 980 statfs_result = statvfs (local->filename, &statfs_buffer); 981 block_size = statfs_buffer.f_frsize; 982 #endif 983 984 if (statfs_result == -1) 985 { 986 int errsv = errno; 987 988 g_set_error (error, G_IO_ERROR, 989 g_io_error_from_errno (errsv), 990 _("Error getting filesystem info: %s"), 991 g_strerror (errsv)); 992 return NULL; 993 } 994 995 info = g_file_info_new (); 996 997 attribute_matcher = g_file_attribute_matcher_new (attributes); 998 999 if (!no_size && 1000 g_file_attribute_matcher_matches (attribute_matcher, 1001 G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) 1002 { 1003 #ifdef G_OS_WIN32 1004 gchar *localdir = g_path_get_dirname (local->filename); 1005 wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL); 1006 ULARGE_INTEGER li; 1007 1008 g_free (localdir); 1009 if (GetDiskFreeSpaceExW (wdirname, &li, NULL, NULL)) 1010 g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, (guint64)li.QuadPart); 1011 g_free (wdirname); 1012 #else 1013 g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, block_size * statfs_buffer.f_bavail); 1014 #endif 1015 } 1016 if (!no_size && 1017 g_file_attribute_matcher_matches (attribute_matcher, 1018 G_FILE_ATTRIBUTE_FILESYSTEM_SIZE)) 1019 { 1020 #ifdef G_OS_WIN32 1021 gchar *localdir = g_path_get_dirname (local->filename); 1022 wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL); 1023 ULARGE_INTEGER li; 1024 1025 g_free (localdir); 1026 if (GetDiskFreeSpaceExW (wdirname, NULL, &li, NULL)) 1027 g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, (guint64)li.QuadPart); 1028 g_free (wdirname); 1029 #else 1030 g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, block_size * statfs_buffer.f_blocks); 1031 #endif 1032 } 1033 #ifdef USE_STATFS 1034 #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) 1035 fstype = g_strdup(statfs_buffer.f_fstypename); 1036 #else 1037 fstype = get_fs_type (statfs_buffer.f_type); 1038 #endif 1039 1040 #elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE) 1041 fstype = g_strdup(statfs_buffer.f_basetype); 1042 #endif 1043 1044 #ifndef G_OS_WIN32 1045 if (fstype && 1046 g_file_attribute_matcher_matches (attribute_matcher, 1047 G_FILE_ATTRIBUTE_FILESYSTEM_TYPE)) 1048 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, fstype); 1049 #endif 1050 1051 if (g_file_attribute_matcher_matches (attribute_matcher, 1052 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY)) 1053 { 1054 #ifdef G_OS_WIN32 1055 get_filesystem_readonly (info, local->filename); 1056 #else 1057 get_mount_info (info, local->filename, attribute_matcher); 1058 #endif 1059 } 1060 1061 g_file_attribute_matcher_unref (attribute_matcher); 1062 1063 return info; 1064 } 1065 1066 static GMount * 1067 g_local_file_find_enclosing_mount (GFile *file, 1068 GCancellable *cancellable, 1069 GError **error) 1070 { 1071 GLocalFile *local = G_LOCAL_FILE (file); 1072 struct stat buf; 1073 char *mountpoint; 1074 GMount *mount; 1075 1076 if (g_lstat (local->filename, &buf) != 0) 1077 { 1078 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, 1079 /* Translators: This is an error message when trying to 1080 * find the enclosing (user visible) mount of a file, but 1081 * none exists. */ 1082 _("Containing mount does not exist")); 1083 return NULL; 1084 } 1085 1086 mountpoint = find_mountpoint_for (local->filename, buf.st_dev); 1087 if (mountpoint == NULL) 1088 { 1089 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, 1090 /* Translators: This is an error message when trying to 1091 * find the enclosing (user visible) mount of a file, but 1092 * none exists. */ 1093 _("Containing mount does not exist")); 1094 return NULL; 1095 } 1096 1097 mount = _g_mount_get_for_mount_path (mountpoint, cancellable); 1098 g_free (mountpoint); 1099 if (mount) 1100 return mount; 1101 1102 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, 1103 /* Translators: This is an error message when trying to find 1104 * the enclosing (user visible) mount of a file, but none 1105 * exists. */ 1106 _("Containing mount does not exist")); 1107 return NULL; 1108 } 1109 1110 static GFile * 1111 g_local_file_set_display_name (GFile *file, 1112 const char *display_name, 1113 GCancellable *cancellable, 1114 GError **error) 1115 { 1116 GLocalFile *local, *new_local; 1117 GFile *new_file, *parent; 1118 struct stat statbuf; 1119 int errsv; 1120 1121 parent = g_file_get_parent (file); 1122 if (parent == NULL) 1123 { 1124 g_set_error_literal (error, G_IO_ERROR, 1125 G_IO_ERROR_FAILED, 1126 _("Can't rename root directory")); 1127 return NULL; 1128 } 1129 1130 new_file = g_file_get_child_for_display_name (parent, display_name, error); 1131 g_object_unref (parent); 1132 1133 if (new_file == NULL) 1134 return NULL; 1135 local = G_LOCAL_FILE (file); 1136 new_local = G_LOCAL_FILE (new_file); 1137 1138 if (g_lstat (new_local->filename, &statbuf) == -1) 1139 { 1140 errsv = errno; 1141 1142 if (errsv != ENOENT) 1143 { 1144 g_set_error (error, G_IO_ERROR, 1145 g_io_error_from_errno (errsv), 1146 _("Error renaming file: %s"), 1147 g_strerror (errsv)); 1148 return NULL; 1149 } 1150 } 1151 else 1152 { 1153 g_set_error_literal (error, G_IO_ERROR, 1154 G_IO_ERROR_EXISTS, 1155 _("Can't rename file, filename already exist")); 1156 return NULL; 1157 } 1158 1159 if (g_rename (local->filename, new_local->filename) == -1) 1160 { 1161 errsv = errno; 1162 1163 if (errsv == EINVAL) 1164 /* We can't get a rename file into itself error herer, 1165 so this must be an invalid filename, on e.g. FAT */ 1166 g_set_error_literal (error, G_IO_ERROR, 1167 G_IO_ERROR_INVALID_FILENAME, 1168 _("Invalid filename")); 1169 else 1170 g_set_error (error, G_IO_ERROR, 1171 g_io_error_from_errno (errsv), 1172 _("Error renaming file: %s"), 1173 g_strerror (errsv)); 1174 g_object_unref (new_file); 1175 return NULL; 1176 } 1177 1178 return new_file; 1179 } 1180 1181 static GFileInfo * 1182 g_local_file_query_info (GFile *file, 1183 const char *attributes, 1184 GFileQueryInfoFlags flags, 1185 GCancellable *cancellable, 1186 GError **error) 1187 { 1188 GLocalFile *local = G_LOCAL_FILE (file); 1189 GFileInfo *info; 1190 GFileAttributeMatcher *matcher; 1191 char *basename, *dirname; 1192 GLocalParentFileInfo parent_info; 1193 1194 matcher = g_file_attribute_matcher_new (attributes); 1195 1196 basename = g_path_get_basename (local->filename); 1197 1198 dirname = g_path_get_dirname (local->filename); 1199 _g_local_file_info_get_parent_info (dirname, matcher, &parent_info); 1200 g_free (dirname); 1201 1202 info = _g_local_file_info_get (basename, local->filename, 1203 matcher, flags, &parent_info, 1204 error); 1205 1206 g_free (basename); 1207 1208 g_file_attribute_matcher_unref (matcher); 1209 1210 return info; 1211 } 1212 1213 static GFileAttributeInfoList * 1214 g_local_file_query_settable_attributes (GFile *file, 1215 GCancellable *cancellable, 1216 GError **error) 1217 { 1218 return g_file_attribute_info_list_ref (local_writable_attributes); 1219 } 1220 1221 static GFileAttributeInfoList * 1222 g_local_file_query_writable_namespaces (GFile *file, 1223 GCancellable *cancellable, 1224 GError **error) 1225 { 1226 return g_file_attribute_info_list_ref (local_writable_namespaces); 1227 } 1228 1229 static gboolean 1230 g_local_file_set_attribute (GFile *file, 1231 const char *attribute, 1232 GFileAttributeType type, 1233 gpointer value_p, 1234 GFileQueryInfoFlags flags, 1235 GCancellable *cancellable, 1236 GError **error) 1237 { 1238 GLocalFile *local = G_LOCAL_FILE (file); 1239 1240 return _g_local_file_info_set_attribute (local->filename, 1241 attribute, 1242 type, 1243 value_p, 1244 flags, 1245 cancellable, 1246 error); 1247 } 1248 1249 static gboolean 1250 g_local_file_set_attributes_from_info (GFile *file, 1251 GFileInfo *info, 1252 GFileQueryInfoFlags flags, 1253 GCancellable *cancellable, 1254 GError **error) 1255 { 1256 GLocalFile *local = G_LOCAL_FILE (file); 1257 int res, chained_res; 1258 GFileIface *default_iface; 1259 1260 res = _g_local_file_info_set_attributes (local->filename, 1261 info, flags, 1262 cancellable, 1263 error); 1264 1265 if (!res) 1266 error = NULL; /* Don't write over error if further errors */ 1267 1268 default_iface = g_type_default_interface_peek (G_TYPE_FILE); 1269 1270 chained_res = (default_iface->set_attributes_from_info) (file, info, flags, cancellable, error); 1271 1272 return res && chained_res; 1273 } 1274 1275 static GFileInputStream * 1276 g_local_file_read (GFile *file, 1277 GCancellable *cancellable, 1278 GError **error) 1279 { 1280 GLocalFile *local = G_LOCAL_FILE (file); 1281 int fd; 1282 struct stat buf; 1283 1284 fd = g_open (local->filename, O_RDONLY|O_BINARY, 0); 1285 if (fd == -1) 1286 { 1287 int errsv = errno; 1288 1289 g_set_error (error, G_IO_ERROR, 1290 g_io_error_from_errno (errsv), 1291 _("Error opening file: %s"), 1292 g_strerror (errsv)); 1293 return NULL; 1294 } 1295 1296 if (fstat(fd, &buf) == 0 && S_ISDIR (buf.st_mode)) 1297 { 1298 close (fd); 1299 g_set_error_literal (error, G_IO_ERROR, 1300 G_IO_ERROR_IS_DIRECTORY, 1301 _("Can't open directory")); 1302 return NULL; 1303 } 1304 1305 return _g_local_file_input_stream_new (fd); 1306 } 1307 1308 static GFileOutputStream * 1309 g_local_file_append_to (GFile *file, 1310 GFileCreateFlags flags, 1311 GCancellable *cancellable, 1312 GError **error) 1313 { 1314 return _g_local_file_output_stream_append (G_LOCAL_FILE (file)->filename, 1315 flags, cancellable, error); 1316 } 1317 1318 static GFileOutputStream * 1319 g_local_file_create (GFile *file, 1320 GFileCreateFlags flags, 1321 GCancellable *cancellable, 1322 GError **error) 1323 { 1324 return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename, 1325 flags, cancellable, error); 1326 } 1327 1328 static GFileOutputStream * 1329 g_local_file_replace (GFile *file, 1330 const char *etag, 1331 gboolean make_backup, 1332 GFileCreateFlags flags, 1333 GCancellable *cancellable, 1334 GError **error) 1335 { 1336 return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename, 1337 etag, make_backup, flags, 1338 cancellable, error); 1339 } 1340 1341 1342 static gboolean 1343 g_local_file_delete (GFile *file, 1344 GCancellable *cancellable, 1345 GError **error) 1346 { 1347 GLocalFile *local = G_LOCAL_FILE (file); 1348 1349 if (g_remove (local->filename) == -1) 1350 { 1351 int errsv = errno; 1352 1353 /* Posix allows EEXIST too, but the more sane error 1354 is G_IO_ERROR_NOT_FOUND, and it's what nautilus 1355 expects */ 1356 if (errsv == EEXIST) 1357 errsv = ENOTEMPTY; 1358 1359 g_set_error (error, G_IO_ERROR, 1360 g_io_error_from_errno (errsv), 1361 _("Error removing file: %s"), 1362 g_strerror (errsv)); 1363 return FALSE; 1364 } 1365 1366 return TRUE; 1367 } 1368 1369 static char * 1370 strip_trailing_slashes (const char *path) 1371 { 1372 char *path_copy; 1373 int len; 1374 1375 path_copy = g_strdup (path); 1376 len = strlen (path_copy); 1377 while (len > 1 && path_copy[len-1] == '/') 1378 path_copy[--len] = 0; 1379 1380 return path_copy; 1381 } 1382 1383 static char * 1384 expand_symlink (const char *link) 1385 { 1386 char *resolved, *canonical, *parent, *link2; 1387 char symlink_value[4096]; 1388 #ifdef G_OS_WIN32 1389 #else 1390 ssize_t res; 1391 #endif 1392 1393 #ifdef G_OS_WIN32 1394 #else 1395 res = readlink (link, symlink_value, sizeof (symlink_value) - 1); 1396 1397 if (res == -1) 1398 return g_strdup (link); 1399 symlink_value[res] = 0; 1400 #endif 1401 1402 if (g_path_is_absolute (symlink_value)) 1403 return canonicalize_filename (symlink_value); 1404 else 1405 { 1406 link2 = strip_trailing_slashes (link); 1407 parent = g_path_get_dirname (link2); 1408 g_free (link2); 1409 1410 resolved = g_build_filename (parent, symlink_value, NULL); 1411 g_free (parent); 1412 1413 canonical = canonicalize_filename (resolved); 1414 1415 g_free (resolved); 1416 1417 return canonical; 1418 } 1419 } 1420 1421 static char * 1422 get_parent (const char *path, 1423 dev_t *parent_dev) 1424 { 1425 char *parent, *tmp; 1426 struct stat parent_stat; 1427 int num_recursions; 1428 char *path_copy; 1429 1430 path_copy = strip_trailing_slashes (path); 1431 1432 parent = g_path_get_dirname (path_copy); 1433 if (strcmp (parent, ".") == 0 || 1434 strcmp (parent, path_copy) == 0) 1435 { 1436 g_free (parent); 1437 g_free (path_copy); 1438 return NULL; 1439 } 1440 g_free (path_copy); 1441 1442 num_recursions = 0; 1443 do { 1444 if (g_lstat (parent, &parent_stat) != 0) 1445 { 1446 g_free (parent); 1447 return NULL; 1448 } 1449 1450 if (S_ISLNK (parent_stat.st_mode)) 1451 { 1452 tmp = parent; 1453 parent = expand_symlink (parent); 1454 g_free (tmp); 1455 } 1456 1457 num_recursions++; 1458 if (num_recursions > 12) 1459 { 1460 g_free (parent); 1461 return NULL; 1462 } 1463 } while (S_ISLNK (parent_stat.st_mode)); 1464 1465 *parent_dev = parent_stat.st_dev; 1466 1467 return parent; 1468 } 1469 1470 static char * 1471 expand_all_symlinks (const char *path) 1472 { 1473 char *parent, *parent_expanded; 1474 char *basename, *res; 1475 dev_t parent_dev; 1476 1477 parent = get_parent (path, &parent_dev); 1478 if (parent) 1479 { 1480 parent_expanded = expand_all_symlinks (parent); 1481 g_free (parent); 1482 basename = g_path_get_basename (path); 1483 res = g_build_filename (parent_expanded, basename, NULL); 1484 g_free (basename); 1485 g_free (parent_expanded); 1486 } 1487 else 1488 res = g_strdup (path); 1489 1490 return res; 1491 } 1492 1493 #ifndef G_OS_WIN32 1494 1495 static char * 1496 find_mountpoint_for (const char *file, 1497 dev_t dev) 1498 { 1499 char *dir, *parent; 1500 dev_t dir_dev, parent_dev; 1501 1502 dir = g_strdup (file); 1503 dir_dev = dev; 1504 1505 while (1) 1506 { 1507 parent = get_parent (dir, &parent_dev); 1508 if (parent == NULL) 1509 return dir; 1510 1511 if (parent_dev != dir_dev) 1512 { 1513 g_free (parent); 1514 return dir; 1515 } 1516 1517 g_free (dir); 1518 dir = parent; 1519 } 1520 } 1521 1522 static char * 1523 find_topdir_for (const char *file) 1524 { 1525 char *dir; 1526 dev_t dir_dev; 1527 1528 dir = get_parent (file, &dir_dev); 1529 if (dir == NULL) 1530 return NULL; 1531 1532 return find_mountpoint_for (dir, dir_dev); 1533 } 1534 1535 static char * 1536 get_unique_filename (const char *basename, 1537 int id) 1538 { 1539 const char *dot; 1540 1541 if (id == 1) 1542 return g_strdup (basename); 1543 1544 dot = strchr (basename, '.'); 1545 if (dot) 1546 return g_strdup_printf ("%.*s.%d%s", (int)(dot - basename), basename, id, dot); 1547 else 1548 return g_strdup_printf ("%s.%d", basename, id); 1549 } 1550 1551 static gboolean 1552 path_has_prefix (const char *path, 1553 const char *prefix) 1554 { 1555 int prefix_len; 1556 1557 if (prefix == NULL) 1558 return TRUE; 1559 1560 prefix_len = strlen (prefix); 1561 1562 if (strncmp (path, prefix, prefix_len) == 0 && 1563 (prefix_len == 0 || /* empty prefix always matches */ 1564 prefix[prefix_len - 1] == '/' || /* last char in prefix was a /, so it must be in path too */ 1565 path[prefix_len] == 0 || 1566 path[prefix_len] == '/')) 1567 return TRUE; 1568 1569 return FALSE; 1570 } 1571 1572 static char * 1573 try_make_relative (const char *path, 1574 const char *base) 1575 { 1576 char *path2, *base2; 1577 char *relative; 1578 1579 path2 = expand_all_symlinks (path); 1580 base2 = expand_all_symlinks (base); 1581 1582 relative = NULL; 1583 if (path_has_prefix (path2, base2)) 1584 { 1585 relative = path2 + strlen (base2); 1586 while (*relative == '/') 1587 relative ++; 1588 relative = g_strdup (relative); 1589 } 1590 g_free (path2); 1591 g_free (base2); 1592 1593 if (relative) 1594 return relative; 1595 1596 /* Failed, use abs path */ 1597 return g_strdup (path); 1598 } 1599 1600 static char * 1601 escape_trash_name (char *name) 1602 { 1603 GString *str; 1604 const gchar hex[16] = "0123456789ABCDEF"; 1605 1606 str = g_string_new (""); 1607 1608 while (*name != 0) 1609 { 1610 char c; 1611 1612 c = *name++; 1613 1614 if (g_ascii_isprint (c)) 1615 g_string_append_c (str, c); 1616 else 1617 { 1618 g_string_append_c (str, '%'); 1619 g_string_append_c (str, hex[((guchar)c) >> 4]); 1620 g_string_append_c (str, hex[((guchar)c) & 0xf]); 1621 } 1622 } 1623 1624 return g_string_free (str, FALSE); 1625 } 1626 1627 gboolean 1628 _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) 1629 { 1630 static gsize home_dev_set = 0; 1631 static dev_t home_dev; 1632 char *topdir, *globaldir, *trashdir, *tmpname; 1633 uid_t uid; 1634 char uid_str[32]; 1635 struct stat global_stat, trash_stat; 1636 gboolean res; 1637 int statres; 1638 1639 if (g_once_init_enter (&home_dev_set)) 1640 { 1641 struct stat home_stat; 1642 1643 g_stat (g_get_home_dir (), &home_stat); 1644 home_dev = home_stat.st_dev; 1645 g_once_init_leave (&home_dev_set, 1); 1646 } 1647 1648 /* Assume we can trash to the home */ 1649 if (dir_dev == home_dev) 1650 return TRUE; 1651 1652 topdir = find_mountpoint_for (dirname, dir_dev); 1653 if (topdir == NULL) 1654 return FALSE; 1655 1656 globaldir = g_build_filename (topdir, ".Trash", NULL); 1657 statres = g_lstat (globaldir, &global_stat); 1658 if (g_lstat (globaldir, &global_stat) == 0 && 1659 S_ISDIR (global_stat.st_mode) && 1660 (global_stat.st_mode & S_ISVTX) != 0) 1661 { 1662 /* got a toplevel sysadmin created dir, assume we 1663 * can trash to it (we should be able to create a dir) 1664 * This fails for the FAT case where the ownership of 1665 * that dir would be wrong though.. 1666 */ 1667 g_free (globaldir); 1668 g_free (topdir); 1669 return TRUE; 1670 } 1671 g_free (globaldir); 1672 1673 /* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */ 1674 uid = geteuid (); 1675 g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long) uid); 1676 1677 tmpname = g_strdup_printf (".Trash-%s", uid_str); 1678 trashdir = g_build_filename (topdir, tmpname, NULL); 1679 g_free (tmpname); 1680 1681 if (g_lstat (trashdir, &trash_stat) == 0) 1682 { 1683 g_free (topdir); 1684 g_free (trashdir); 1685 return 1686 S_ISDIR (trash_stat.st_mode) && 1687 trash_stat.st_uid == uid; 1688 } 1689 g_free (trashdir); 1690 1691 /* User specific trash didn't exist, can we create it? */ 1692 res = g_access (topdir, W_OK) == 0; 1693 1694 g_free (topdir); 1695 1696 return res; 1697 } 1698 1699 1700 static gboolean 1701 g_local_file_trash (GFile *file, 1702 GCancellable *cancellable, 1703 GError **error) 1704 { 1705 GLocalFile *local = G_LOCAL_FILE (file); 1706 struct stat file_stat, home_stat; 1707 const char *homedir; 1708 char *trashdir, *topdir, *infodir, *filesdir; 1709 char *basename, *trashname, *trashfile, *infoname, *infofile; 1710 char *original_name, *original_name_escaped; 1711 int i; 1712 char *data; 1713 gboolean is_homedir_trash; 1714 char delete_time[32]; 1715 int fd; 1716 struct stat trash_stat, global_stat; 1717 char *dirname, *globaldir; 1718 1719 if (g_lstat (local->filename, &file_stat) != 0) 1720 { 1721 int errsv = errno; 1722 1723 g_set_error (error, G_IO_ERROR, 1724 g_io_error_from_errno (errsv), 1725 _("Error trashing file: %s"), 1726 g_strerror (errsv)); 1727 return FALSE; 1728 } 1729 1730 homedir = g_get_home_dir (); 1731 g_stat (homedir, &home_stat); 1732 1733 is_homedir_trash = FALSE; 1734 trashdir = NULL; 1735 if (file_stat.st_dev == home_stat.st_dev) 1736 { 1737 is_homedir_trash = TRUE; 1738 errno = 0; 1739 trashdir = g_build_filename (g_get_user_data_dir (), "Trash", NULL); 1740 if (g_mkdir_with_parents (trashdir, 0700) < 0) 1741 { 1742 char *display_name; 1743 int errsv = errno; 1744 1745 display_name = g_filename_display_name (trashdir); 1746 g_set_error (error, G_IO_ERROR, 1747 g_io_error_from_errno (errsv), 1748 _("Unable to create trash dir %s: %s"), 1749 display_name, g_strerror (errsv)); 1750 g_free (display_name); 1751 g_free (trashdir); 1752 return FALSE; 1753 } 1754 topdir = g_strdup (g_get_user_data_dir ()); 1755 } 1756 else 1757 { 1758 uid_t uid; 1759 char uid_str[32]; 1760 1761 uid = geteuid (); 1762 g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid); 1763 1764 topdir = find_topdir_for (local->filename); 1765 if (topdir == NULL) 1766 { 1767 g_set_error_literal (error, G_IO_ERROR, 1768 G_IO_ERROR_NOT_SUPPORTED, 1769 _("Unable to find toplevel directory for trash")); 1770 return FALSE; 1771 } 1772 1773 /* Try looking for global trash dir $topdir/.Trash/$uid */ 1774 globaldir = g_build_filename (topdir, ".Trash", NULL); 1775 if (g_lstat (globaldir, &global_stat) == 0 && 1776 S_ISDIR (global_stat.st_mode) && 1777 (global_stat.st_mode & S_ISVTX) != 0) 1778 { 1779 trashdir = g_build_filename (globaldir, uid_str, NULL); 1780 1781 if (g_lstat (trashdir, &trash_stat) == 0) 1782 { 1783 if (!S_ISDIR (trash_stat.st_mode) || 1784 trash_stat.st_uid != uid) 1785 { 1786 /* Not a directory or not owned by user, ignore */ 1787 g_free (trashdir); 1788 trashdir = NULL; 1789 } 1790 } 1791 else if (g_mkdir (trashdir, 0700) == -1) 1792 { 1793 g_free (trashdir); 1794 trashdir = NULL; 1795 } 1796 } 1797 g_free (globaldir); 1798 1799 if (trashdir == NULL) 1800 { 1801 gboolean tried_create; 1802 1803 /* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */ 1804 dirname = g_strdup_printf (".Trash-%s", uid_str); 1805 trashdir = g_build_filename (topdir, dirname, NULL); 1806 g_free (dirname); 1807 1808 tried_create = FALSE; 1809 1810 retry: 1811 if (g_lstat (trashdir, &trash_stat) == 0) 1812 { 1813 if (!S_ISDIR (trash_stat.st_mode) || 1814 trash_stat.st_uid != uid) 1815 { 1816 /* Remove the failed directory */ 1817 if (tried_create) 1818 g_remove (trashdir); 1819 1820 /* Not a directory or not owned by user, ignore */ 1821 g_free (trashdir); 1822 trashdir = NULL; 1823 } 1824 } 1825 else 1826 { 1827 if (!tried_create && 1828 g_mkdir (trashdir, 0700) != -1) 1829 { 1830 /* Ensure that the created dir has the right uid etc. 1831 This might fail on e.g. a FAT dir */ 1832 tried_create = TRUE; 1833 goto retry; 1834 } 1835 else 1836 { 1837 g_free (trashdir); 1838 trashdir = NULL; 1839 } 1840 } 1841 } 1842 1843 if (trashdir == NULL) 1844 { 1845 g_free (topdir); 1846 g_set_error_literal (error, G_IO_ERROR, 1847 G_IO_ERROR_NOT_SUPPORTED, 1848 _("Unable to find or create trash directory")); 1849 return FALSE; 1850 } 1851 } 1852 1853 /* Trashdir points to the trash dir with the "info" and "files" subdirectories */ 1854 1855 infodir = g_build_filename (trashdir, "info", NULL); 1856 filesdir = g_build_filename (trashdir, "files", NULL); 1857 g_free (trashdir); 1858 1859 /* Make sure we have the subdirectories */ 1860 if ((g_mkdir (infodir, 0700) == -1 && errno != EEXIST) || 1861 (g_mkdir (filesdir, 0700) == -1 && errno != EEXIST)) 1862 { 1863 g_free (topdir); 1864 g_free (infodir); 1865 g_free (filesdir); 1866 g_set_error_literal (error, G_IO_ERROR, 1867 G_IO_ERROR_NOT_SUPPORTED, 1868 _("Unable to find or create trash directory")); 1869 return FALSE; 1870 } 1871 1872 basename = g_path_get_basename (local->filename); 1873 i = 1; 1874 trashname = NULL; 1875 infofile = NULL; 1876 do { 1877 g_free (trashname); 1878 g_free (infofile); 1879 1880 trashname = get_unique_filename (basename, i++); 1881 infoname = g_strconcat (trashname, ".trashinfo", NULL); 1882 infofile = g_build_filename (infodir, infoname, NULL); 1883 g_free (infoname); 1884 1885 fd = open (infofile, O_CREAT | O_EXCL, 0666); 1886 } while (fd == -1 && errno == EEXIST); 1887 1888 g_free (basename); 1889 g_free (infodir); 1890 1891 if (fd == -1) 1892 { 1893 int errsv = errno; 1894 1895 g_free (filesdir); 1896 g_free (topdir); 1897 g_free (trashname); 1898 g_free (infofile); 1899 1900 g_set_error (error, G_IO_ERROR, 1901 g_io_error_from_errno (errsv), 1902 _("Unable to create trashing info file: %s"), 1903 g_strerror (errsv)); 1904 return FALSE; 1905 } 1906 1907 close (fd); 1908 1909 /* TODO: Maybe we should verify that you can delete the file from the trash 1910 before moving it? OTOH, that is hard, as it needs a recursive scan */ 1911 1912 trashfile = g_build_filename (filesdir, trashname, NULL); 1913 1914 g_free (filesdir); 1915 1916 if (g_rename (local->filename, trashfile) == -1) 1917 { 1918 int errsv = errno; 1919 1920 g_free (topdir); 1921 g_free (trashname); 1922 g_free (infofile); 1923 g_free (trashfile); 1924 1925 if (errsv == EXDEV) 1926 /* The trash dir was actually on another fs anyway!? 1927 This can happen when the same device is mounted multiple 1928 times, or with bind mounts of the same fs. */ 1929 g_set_error (error, G_IO_ERROR, 1930 G_IO_ERROR_NOT_SUPPORTED, 1931 _("Unable to trash file: %s"), 1932 g_strerror (errsv)); 1933 else 1934 g_set_error (error, G_IO_ERROR, 1935 g_io_error_from_errno (errsv), 1936 _("Unable to trash file: %s"), 1937 g_strerror (errsv)); 1938 return FALSE; 1939 } 1940 1941 g_free (trashfile); 1942 1943 /* TODO: Do we need to update mtime/atime here after the move? */ 1944 1945 /* Use absolute names for homedir */ 1946 if (is_homedir_trash) 1947 original_name = g_strdup (local->filename); 1948 else 1949 original_name = try_make_relative (local->filename, topdir); 1950 original_name_escaped = escape_trash_name (original_name); 1951 1952 g_free (original_name); 1953 g_free (topdir); 1954 1955 { 1956 time_t t; 1957 struct tm now; 1958 t = time (NULL); 1959 localtime_r (&t, &now); 1960 delete_time[0] = 0; 1961 strftime(delete_time, sizeof (delete_time), "%Y-%m-%dT%H:%M:%S", &now); 1962 } 1963 1964 data = g_strdup_printf ("[Trash Info]\nPath=%s\nDeletionDate=%s\n", 1965 original_name_escaped, delete_time); 1966 1967 g_file_set_contents (infofile, data, -1, NULL); 1968 g_free (infofile); 1969 g_free (data); 1970 1971 g_free (original_name_escaped); 1972 g_free (trashname); 1973 1974 return TRUE; 1975 } 1976 #else /* G_OS_WIN32 */ 1977 gboolean 1978 _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) 1979 { 1980 return FALSE; /* XXX ??? */ 1981 } 1982 1983 static gboolean 1984 g_local_file_trash (GFile *file, 1985 GCancellable *cancellable, 1986 GError **error) 1987 { 1988 GLocalFile *local = G_LOCAL_FILE (file); 1989 SHFILEOPSTRUCTW op = {0}; 1990 gboolean success; 1991 wchar_t *wfilename; 1992 long len; 1993 1994 wfilename = g_utf8_to_utf16 (local->filename, -1, NULL, &len, NULL); 1995 /* SHFILEOPSTRUCT.pFrom is double-zero-terminated */ 1996 wfilename = g_renew (wchar_t, wfilename, len + 2); 1997 wfilename[len + 1] = 0; 1998 1999 op.wFunc = FO_DELETE; 2000 op.pFrom = wfilename; 2001 op.fFlags = FOF_ALLOWUNDO; 2002 2003 success = SHFileOperationW (&op) == 0; 2004 2005 if (success && op.fAnyOperationsAborted) 2006 { 2007 if (cancellable && !g_cancellable_is_cancelled (cancellable)) 2008 g_cancellable_cancel (cancellable); 2009 g_set_error (error, G_IO_ERROR, 2010 G_IO_ERROR_CANCELLED, 2011 _("Unable to trash file: %s"), 2012 _("Operation was cancelled")); 2013 success = FALSE; 2014 } 2015 else if (!success) 2016 g_set_error (error, G_IO_ERROR, 2017 G_IO_ERROR_FAILED, 2018 _("Unable to trash file: %s"), 2019 _("internal error")); 2020 2021 g_free (wfilename); 2022 return success; 2023 } 2024 #endif /* G_OS_WIN32 */ 2025 2026 static gboolean 2027 g_local_file_make_directory (GFile *file, 2028 GCancellable *cancellable, 2029 GError **error) 2030 { 2031 GLocalFile *local = G_LOCAL_FILE (file); 2032 2033 if (g_mkdir (local->filename, 0777) == -1) 2034 { 2035 int errsv = errno; 2036 2037 if (errsv == EINVAL) 2038 /* This must be an invalid filename, on e.g. FAT */ 2039 g_set_error_literal (error, G_IO_ERROR, 2040 G_IO_ERROR_INVALID_FILENAME, 2041 _("Invalid filename")); 2042 else 2043 g_set_error (error, G_IO_ERROR, 2044 g_io_error_from_errno (errsv), 2045 _("Error creating directory: %s"), 2046 g_strerror (errsv)); 2047 return FALSE; 2048 } 2049 2050 return TRUE; 2051 } 2052 2053 static gboolean 2054 g_local_file_make_symbolic_link (GFile *file, 2055 const char *symlink_value, 2056 GCancellable *cancellable, 2057 GError **error) 2058 { 2059 #ifdef HAVE_SYMLINK 2060 GLocalFile *local = G_LOCAL_FILE (file); 2061 2062 if (symlink (symlink_value, local->filename) == -1) 2063 { 2064 int errsv = errno; 2065 2066 if (errsv == EINVAL) 2067 /* This must be an invalid filename, on e.g. FAT */ 2068 g_set_error_literal (error, G_IO_ERROR, 2069 G_IO_ERROR_INVALID_FILENAME, 2070 _("Invalid filename")); 2071 else 2072 g_set_error (error, G_IO_ERROR, 2073 g_io_error_from_errno (errsv), 2074 _("Error making symbolic link: %s"), 2075 g_strerror (errsv)); 2076 return FALSE; 2077 } 2078 return TRUE; 2079 #else 2080 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Symlinks not supported"); 2081 return FALSE; 2082 #endif 2083 } 2084 2085 2086 static gboolean 2087 g_local_file_copy (GFile *source, 2088 GFile *destination, 2089 GFileCopyFlags flags, 2090 GCancellable *cancellable, 2091 GFileProgressCallback progress_callback, 2092 gpointer progress_callback_data, 2093 GError **error) 2094 { 2095 /* Fall back to default copy */ 2096 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Copy not supported"); 2097 return FALSE; 2098 } 2099 2100 static gboolean 2101 g_local_file_move (GFile *source, 2102 GFile *destination, 2103 GFileCopyFlags flags, 2104 GCancellable *cancellable, 2105 GFileProgressCallback progress_callback, 2106 gpointer progress_callback_data, 2107 GError **error) 2108 { 2109 GLocalFile *local_source, *local_destination; 2110 struct stat statbuf; 2111 gboolean destination_exist, source_is_dir; 2112 char *backup_name; 2113 int res; 2114 off_t source_size; 2115 2116 if (!G_IS_LOCAL_FILE (source) || 2117 !G_IS_LOCAL_FILE (destination)) 2118 { 2119 /* Fall back to default move */ 2120 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Move not supported"); 2121 return FALSE; 2122 } 2123 2124 local_source = G_LOCAL_FILE (source); 2125 local_destination = G_LOCAL_FILE (destination); 2126 2127 res = g_lstat (local_source->filename, &statbuf); 2128 if (res == -1) 2129 { 2130 int errsv = errno; 2131 2132 g_set_error (error, G_IO_ERROR, 2133 g_io_error_from_errno (errsv), 2134 _("Error moving file: %s"), 2135 g_strerror (errsv)); 2136 return FALSE; 2137 } 2138 2139 source_is_dir = S_ISDIR (statbuf.st_mode); 2140 source_size = statbuf.st_size; 2141 2142 destination_exist = FALSE; 2143 res = g_lstat (local_destination->filename, &statbuf); 2144 if (res == 0) 2145 { 2146 destination_exist = TRUE; /* Target file exists */ 2147 2148 if (flags & G_FILE_COPY_OVERWRITE) 2149 { 2150 /* Always fail on dirs, even with overwrite */ 2151 if (S_ISDIR (statbuf.st_mode)) 2152 { 2153 if (source_is_dir) 2154 g_set_error_literal (error, 2155 G_IO_ERROR, 2156 G_IO_ERROR_WOULD_MERGE, 2157 _("Can't move directory over directory")); 2158 else 2159 g_set_error_literal (error, 2160 G_IO_ERROR, 2161 G_IO_ERROR_IS_DIRECTORY, 2162 _("Can't copy over directory")); 2163 return FALSE; 2164 } 2165 } 2166 else 2167 { 2168 g_set_error_literal (error, 2169 G_IO_ERROR, 2170 G_IO_ERROR_EXISTS, 2171 _("Target file exists")); 2172 return FALSE; 2173 } 2174 } 2175 2176 if (flags & G_FILE_COPY_BACKUP && destination_exist) 2177 { 2178 backup_name = g_strconcat (local_destination->filename, "~", NULL); 2179 if (g_rename (local_destination->filename, backup_name) == -1) 2180 { 2181 g_set_error_literal (error, 2182 G_IO_ERROR, 2183 G_IO_ERROR_CANT_CREATE_BACKUP, 2184 _("Backup file creation failed")); 2185 g_free (backup_name); 2186 return FALSE; 2187 } 2188 g_free (backup_name); 2189 destination_exist = FALSE; /* It did, but no more */ 2190 } 2191 2192 if (source_is_dir && destination_exist && (flags & G_FILE_COPY_OVERWRITE)) 2193 { 2194 /* Source is a dir, destination exists (and is not a dir, because that would have failed 2195 earlier), and we're overwriting. Manually remove the target so we can do the rename. */ 2196 res = g_unlink (local_destination->filename); 2197 if (res == -1) 2198 { 2199 int errsv = errno; 2200 2201 g_set_error (error, G_IO_ERROR, 2202 g_io_error_from_errno (errsv), 2203 _("Error removing target file: %s"), 2204 g_strerror (errsv)); 2205 return FALSE; 2206 } 2207 } 2208 2209 if (g_rename (local_source->filename, local_destination->filename) == -1) 2210 { 2211 int errsv = errno; 2212 2213 if (errsv == EXDEV) 2214 /* This will cause the fallback code to run */ 2215 g_set_error_literal (error, G_IO_ERROR, 2216 G_IO_ERROR_NOT_SUPPORTED, 2217 _("Move between mounts not supported")); 2218 else if (errsv == EINVAL) 2219 /* This must be an invalid filename, on e.g. FAT, or 2220 we're trying to move the file into itself... 2221 We return invalid filename for both... */ 2222 g_set_error_literal (error, G_IO_ERROR, 2223 G_IO_ERROR_INVALID_FILENAME, 2224 _("Invalid filename")); 2225 else 2226 g_set_error (error, G_IO_ERROR, 2227 g_io_error_from_errno (errsv), 2228 _("Error moving file: %s"), 2229 g_strerror (errsv)); 2230 return FALSE; 2231 } 2232 2233 /* Make sure we send full copied size */ 2234 if (progress_callback) 2235 progress_callback (source_size, source_size, progress_callback_data); 2236 2237 return TRUE; 2238 } 2239 2240 static GFileMonitor* 2241 g_local_file_monitor_dir (GFile *file, 2242 GFileMonitorFlags flags, 2243 GCancellable *cancellable, 2244 GError **error) 2245 { 2246 GLocalFile* local_file = G_LOCAL_FILE(file); 2247 return _g_local_directory_monitor_new (local_file->filename, flags, error); 2248 } 2249 2250 static GFileMonitor* 2251 g_local_file_monitor_file (GFile *file, 2252 GFileMonitorFlags flags, 2253 GCancellable *cancellable, 2254 GError **error) 2255 { 2256 GLocalFile* local_file = G_LOCAL_FILE(file); 2257 return _g_local_file_monitor_new (local_file->filename, flags, error); 2258 } 2259 2260 static void 2261 g_local_file_file_iface_init (GFileIface *iface) 2262 { 2263 iface->dup = g_local_file_dup; 2264 iface->hash = g_local_file_hash; 2265 iface->equal = g_local_file_equal; 2266 iface->is_native = g_local_file_is_native; 2267 iface->has_uri_scheme = g_local_file_has_uri_scheme; 2268 iface->get_uri_scheme = g_local_file_get_uri_scheme; 2269 iface->get_basename = g_local_file_get_basename; 2270 iface->get_path = g_local_file_get_path; 2271 iface->get_uri = g_local_file_get_uri; 2272 iface->get_parse_name = g_local_file_get_parse_name; 2273 iface->get_parent = g_local_file_get_parent; 2274 iface->prefix_matches = g_local_file_prefix_matches; 2275 iface->get_relative_path = g_local_file_get_relative_path; 2276 iface->resolve_relative_path = g_local_file_resolve_relative_path; 2277 iface->get_child_for_display_name = g_local_file_get_child_for_display_name; 2278 iface->set_display_name = g_local_file_set_display_name; 2279 iface->enumerate_children = g_local_file_enumerate_children; 2280 iface->query_info = g_local_file_query_info; 2281 iface->query_filesystem_info = g_local_file_query_filesystem_info; 2282 iface->find_enclosing_mount = g_local_file_find_enclosing_mount; 2283 iface->query_settable_attributes = g_local_file_query_settable_attributes; 2284 iface->query_writable_namespaces = g_local_file_query_writable_namespaces; 2285 iface->set_attribute = g_local_file_set_attribute; 2286 iface->set_attributes_from_info = g_local_file_set_attributes_from_info; 2287 iface->read_fn = g_local_file_read; 2288 iface->append_to = g_local_file_append_to; 2289 iface->create = g_local_file_create; 2290 iface->replace = g_local_file_replace; 2291 iface->delete_file = g_local_file_delete; 2292 iface->trash = g_local_file_trash; 2293 iface->make_directory = g_local_file_make_directory; 2294 iface->make_symbolic_link = g_local_file_make_symbolic_link; 2295 iface->copy = g_local_file_copy; 2296 iface->move = g_local_file_move; 2297 iface->monitor_dir = g_local_file_monitor_dir; 2298 iface->monitor_file = g_local_file_monitor_file; 2299 } 2300