mirror of https://gitee.com/openkylin/gvfs.git
merge upstream 1.50.3
This commit is contained in:
parent
e118d16b14
commit
cfb097cdca
|
@ -0,0 +1,43 @@
|
||||||
|
fedora:
|
||||||
|
image:
|
||||||
|
name: registry.gitlab.gnome.org/gnome/gvfs:latest
|
||||||
|
entrypoint: ["/bin/sh", "-c"]
|
||||||
|
tags:
|
||||||
|
- x86_64
|
||||||
|
- ipv6
|
||||||
|
script:
|
||||||
|
- meson
|
||||||
|
-Dinstalled_tests=true
|
||||||
|
-Ddevel_utils=true
|
||||||
|
-Dman=true
|
||||||
|
-Dafc=true
|
||||||
|
-Darchive=true
|
||||||
|
-Dsftp=true
|
||||||
|
-Dsmb=true
|
||||||
|
-Dudisks2=true
|
||||||
|
-Dhttp=true
|
||||||
|
-Dgphoto2=true
|
||||||
|
--prefix /usr --werror build
|
||||||
|
- sudo ninja -C build install
|
||||||
|
- GIO_USE_VOLUME_MONITOR=unix gnome-desktop-testing-runner gvfs
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
update-image:
|
||||||
|
variables:
|
||||||
|
STORAGE_DRIVER: vfs
|
||||||
|
BUILDAH_FORMAT: docker
|
||||||
|
BUILDAH_ISOLATION: chroot
|
||||||
|
image: registry.fedoraproject.org/fedora:latest
|
||||||
|
script:
|
||||||
|
- dnf install -y buildah runc
|
||||||
|
- sed -i '/^mountopt =.*/d' /etc/containers/storage.conf
|
||||||
|
- buildah bud --tag $CI_REGISTRY_IMAGE -f .gitlab-ci/Dockerfile
|
||||||
|
- buildah tag $CI_REGISTRY_IMAGE "$CI_REGISTRY_IMAGE:v$CI_JOB_ID"
|
||||||
|
- buildah login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
- buildah push --creds $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD $CI_REGISTRY_IMAGE
|
||||||
|
- buildah push --creds $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD "$CI_REGISTRY_IMAGE:v$CI_JOB_ID"
|
||||||
|
when: manual
|
||||||
|
only:
|
||||||
|
variables:
|
||||||
|
- $CI_PROJECT_NAMESPACE == "GNOME"
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
FROM fedora:latest
|
||||||
|
|
||||||
|
RUN dnf install --nogpg -y dnf-plugins-core git gnome-desktop-testing dbus-daemon python3-twisted python3-gobject procps-ng bzip2 httpd mod_ssl openssh-server passwd gcc-c++ \
|
||||||
|
&& dnf builddep --nogpg -y gvfs \
|
||||||
|
&& dnf clean all
|
||||||
|
|
||||||
|
RUN dnf builddep --nogpg -y glib \
|
||||||
|
&& dnf clean all \
|
||||||
|
&& git clone --depth 1 https://gitlab.gnome.org/GNOME/glib.git \
|
||||||
|
&& cd glib \
|
||||||
|
&& meson . _build --prefix=/usr \
|
||||||
|
&& ninja -C _build \
|
||||||
|
&& ninja -C _build install \
|
||||||
|
&& cd .. \
|
||||||
|
&& rm -rf glib
|
||||||
|
|
||||||
|
RUN dnf builddep --nogpg -y glib-networking \
|
||||||
|
&& dnf clean all \
|
||||||
|
&& git clone --depth 1 https://gitlab.gnome.org/GNOME/glib-networking.git \
|
||||||
|
&& cd glib-networking \
|
||||||
|
&& meson . _build --prefix=/usr \
|
||||||
|
&& ninja -C _build \
|
||||||
|
&& ninja -C _build install \
|
||||||
|
&& cd .. \
|
||||||
|
&& rm -rf glib-networking
|
||||||
|
|
||||||
|
RUN dnf builddep --nogpg -y libsoup \
|
||||||
|
&& dnf install -y --nogpg libnghttp2-devel \
|
||||||
|
&& dnf clean all \
|
||||||
|
&& git clone --depth 1 https://gitlab.gnome.org/GNOME/libsoup.git \
|
||||||
|
&& cd libsoup \
|
||||||
|
&& meson . _build --prefix=/usr \
|
||||||
|
&& ninja -C _build \
|
||||||
|
&& ninja -C _build install \
|
||||||
|
&& cd .. \
|
||||||
|
&& rm -rf libsoup
|
||||||
|
|
||||||
|
RUN sed -i -e 's/# %wheel/%wheel/' /etc/sudoers
|
||||||
|
RUN useradd -G wheel -m user
|
||||||
|
RUN passwd -d user
|
||||||
|
USER user
|
||||||
|
WORKDIR /home/user
|
||||||
|
ENV USER user
|
||||||
|
ENV XDG_RUNTIME_DIR /home/user
|
||||||
|
|
||||||
|
RUN ssh-keygen -t rsa -q -N "" -f ~/.ssh/id_rsa
|
|
@ -8,6 +8,6 @@ GVfs source repository is at https://gitlab.gnome.org/GNOME/gvfs.
|
||||||
|
|
||||||
## Code Contribution
|
## Code Contribution
|
||||||
|
|
||||||
See https://wiki.gnome.org/GitLab for general informations about GitLab workflow
|
See https://wiki.gnome.org/GitLab for general information about GitLab workflow
|
||||||
for code contribution. GVfs still uses linear GIT history without merge commits,
|
for code contribution. GVfs still uses linear GIT history without merge commits,
|
||||||
please see general commit guidelines at https://wiki.gnome.org/Git/CommitMessages.
|
please see general commit guidelines at https://wiki.gnome.org/Git/CommitMessages.
|
118
NEWS
118
NEWS
|
@ -1,3 +1,121 @@
|
||||||
|
Major changes in 1.50.3
|
||||||
|
=======================
|
||||||
|
* dav: Prevent usage of NULL when user is not specified (Ondrej Holy)
|
||||||
|
* ftp: Fix hangs when the connection is released (wangrong)
|
||||||
|
* fuse: Decrease file handle reference when open file fail (wangrong)
|
||||||
|
* sftp: PATH-expand the ssh client (Alex Stewart)
|
||||||
|
* test: Several smaller enhancements (Sébastien Bacher)
|
||||||
|
* backend: Add support for xx-large and x-large thumbnails (Ondrej Holy)
|
||||||
|
* goa: Prevent automounts when resuming from suspension (Ondrej Holy)
|
||||||
|
* Translation updates (GNOME Translation Project contributors)
|
||||||
|
|
||||||
|
Major changes in 1.50.2
|
||||||
|
=======================
|
||||||
|
* smb: Rework anonymous handling to avoid EINVAL (Ondrej Holy)
|
||||||
|
* http: Unescape prefix to fix handling of encoded URIs (Ondrej Holy)
|
||||||
|
* build: Fix build without Avahi support (Ondrej Holy)
|
||||||
|
|
||||||
|
Major changes in 1.50.1
|
||||||
|
=======================
|
||||||
|
* dav: Drop user from URI as a workaround for Nextcloud bug (Ondrej Holy)
|
||||||
|
* dav: Port DNS-SD resolver to async API to fix hangs when mounting (Ondrej Holy)
|
||||||
|
* smb: Ignore EINVAL for kerberos/ccache login (Ondrej Holy)
|
||||||
|
* dav: Rewrite to libsoup async API to fix crashes (Daniel Kolesa)
|
||||||
|
* dav: Do not lose userinfo when copying URIs (Daniel Kolesa)
|
||||||
|
|
||||||
|
Major changes in 1.50.0
|
||||||
|
=======================
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.49.90
|
||||||
|
========================
|
||||||
|
* http/dav: Port to libsoup3 (Daniel Kolesa)
|
||||||
|
* http: Do not silently accept invalid certificates (Daniel Kolesa)
|
||||||
|
* build: Remove incorrect i18n.merge_file argument to fix build (Ondrej Holy)
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.49.1
|
||||||
|
=======================
|
||||||
|
* sftp: Adapt on new OpenSSH password prompts
|
||||||
|
* build: Set of improvements for meson
|
||||||
|
* Add PartOf=graphical-session.target to all systemd units
|
||||||
|
* Move systemd services to session slice
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.48.1
|
||||||
|
=======================
|
||||||
|
* build: Use install prefix in systemd files paths
|
||||||
|
* client: Prevent socket leaks if socket dir is inaccessible from client
|
||||||
|
* admin: Fix regressions caused by port to named sockets
|
||||||
|
* udisks2: Report unmount progress after showing blocking processes
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.48.0
|
||||||
|
=======================
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.47.91
|
||||||
|
========================
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.47.90
|
||||||
|
========================
|
||||||
|
* google: Add Shared drives folder
|
||||||
|
* google: Add Shared with me folder
|
||||||
|
* google: Improve performance for folders with large number of files
|
||||||
|
* daemon: Set filesystem::use-preview explicitly and consistently
|
||||||
|
* daemon: Unify and shorten strings for prompt dialog titles
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.47.1
|
||||||
|
=======================
|
||||||
|
* mtp: Fix crashes when storage descriptions are not provided
|
||||||
|
* trash: Explicitly cancel file monitor to prevent deadlock
|
||||||
|
* admin: Add copy and push implementations for better performance
|
||||||
|
* client: Add fallback to session bus for synchronous API
|
||||||
|
* daemon: Use named sockets to avoid network permission requirement
|
||||||
|
* smb: Set fast content type independently of other attributes
|
||||||
|
* ftp: Prevent source file removal in case of transfer failure
|
||||||
|
* google: Report progress for file transfers from local filesystem
|
||||||
|
* sftp: Add support for two factor authentication
|
||||||
|
* sftp: Use connection multiplexing instead of multiple connections
|
||||||
|
* smb: Report progress when move operation is done
|
||||||
|
* google: Set the display name for the root folder also
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.46.1
|
||||||
|
=======================
|
||||||
|
* trash: Do not fail when G_FILE_COPY_NO_FALLBACK_FOR_MOVE is used
|
||||||
|
* dav: Be sure that enumeration is possible when looking for a root
|
||||||
|
|
||||||
|
Major changes in 1.46.0
|
||||||
|
=======================
|
||||||
|
* No changes
|
||||||
|
|
||||||
|
Major changes in 1.45.92
|
||||||
|
========================
|
||||||
|
* build: Link libgvfscommon to libmetadata
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.45.90
|
||||||
|
========================
|
||||||
|
* trash: Add support for x-gvfs-notrash option to ignore mounts
|
||||||
|
* recent: Port to GDateTime
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.45.3
|
||||||
|
=======================
|
||||||
|
* client: Add support for zone identifiers in IPv6 addresses
|
||||||
|
* afc: Add support for libplist-2.2
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
|
Major changes in 1.45.2
|
||||||
|
=======================
|
||||||
|
* metadata: Emit D-Bus signal when metadata are modified
|
||||||
|
* sftp: Preserve timestamps during copy and move operations
|
||||||
|
* dav: Add support for Negotiate and NTLM authentication
|
||||||
|
* Translation updates
|
||||||
|
|
||||||
Major changes in 1.44.1
|
Major changes in 1.44.1
|
||||||
=======================
|
=======================
|
||||||
* udisks2: Fix several memory leaks
|
* udisks2: Fix several memory leaks
|
||||||
|
|
11
README.md
11
README.md
|
@ -7,15 +7,16 @@ implement volume monitors and persistent metadata storage. There is also FUSE
|
||||||
support that provides limited access to the GVfs filesystems for applications
|
support that provides limited access to the GVfs filesystems for applications
|
||||||
not using GIO.
|
not using GIO.
|
||||||
|
|
||||||
For more info about GVfs see https://wiki.gnome.org/Projects/gvfs.
|
For more info about GVfs, see https://wiki.gnome.org/Projects/gvfs.
|
||||||
|
|
||||||
## Reporting Bugs
|
## Reporting Bugs
|
||||||
|
|
||||||
Bug reports can be found and filed at https://gitlab.gnome.org/GNOME/gvfs/issues.
|
Bug reports can be found and filed at https://gitlab.gnome.org/GNOME/gvfs/issues.
|
||||||
For security related issues, please use [security@gnome.org](mailto:security@gnome.org).
|
For security-related issues, please use https://security.gnome.org/.
|
||||||
|
|
||||||
|
See https://wiki.gnome.org/Projects/gvfs/debugging for info about getting debug
|
||||||
|
logs.
|
||||||
|
|
||||||
## Ask Questions
|
## Ask Questions
|
||||||
|
|
||||||
For questions use gvfs mailing list [gvfs-list@gnome.org](mailto:gvfs-list@gnome.org).
|
For questions use [GNOME Discourse](https://discourse.gnome.org/).
|
||||||
See https://mail.gnome.org/mailman/listinfo/gvfs-list for subscription info.
|
|
||||||
Alternatively you use irc://irc.gnome.org/nautilus.
|
|
||||||
|
|
|
@ -438,6 +438,17 @@ create_proxy_for_file2 (GFile *file1,
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = _g_dbus_connection_get_sync (mount_info1->dbus_id, cancellable, &local_error);
|
connection = _g_dbus_connection_get_sync (mount_info1->dbus_id, cancellable, &local_error);
|
||||||
|
if (connection == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_dbus_error_strip_remote_error (local_error);
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", local_error->message);
|
||||||
|
g_clear_error (&local_error);
|
||||||
|
|
||||||
|
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
|
||||||
|
}
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -613,8 +624,19 @@ async_got_connection_cb (GDBusConnection *connection,
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
{
|
{
|
||||||
/* TODO: we should probably test if we really want a session bus;
|
g_dbus_error_strip_remote_error (io_error);
|
||||||
* for now, this code is on par with the old dbus code */
|
|
||||||
|
if (g_error_matches (io_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_task_return_error (data->task, g_error_copy (io_error));
|
||||||
|
async_proxy_create_free (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", io_error->message);
|
||||||
|
|
||||||
g_bus_get (G_BUS_TYPE_SESSION,
|
g_bus_get (G_BUS_TYPE_SESSION,
|
||||||
g_task_get_cancellable (data->task),
|
g_task_get_cancellable (data->task),
|
||||||
bus_get_cb,
|
bus_get_cb,
|
||||||
|
@ -2689,14 +2711,6 @@ file_transfer (GFile *source,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!native_transfer && remove_source &&
|
|
||||||
(flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
|
||||||
{
|
|
||||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
||||||
_("Operation not supported"));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!native_transfer && local_path == NULL)
|
if (!native_transfer && local_path == NULL)
|
||||||
{
|
{
|
||||||
/* This will cause the fallback code to be involved */
|
/* This will cause the fallback code to be involved */
|
||||||
|
|
|
@ -178,6 +178,17 @@ g_daemon_file_monitor_new (const char *remote_id,
|
||||||
daemon_monitor->remote_obj_path = g_strdup (remote_obj_path);
|
daemon_monitor->remote_obj_path = g_strdup (remote_obj_path);
|
||||||
|
|
||||||
connection = _g_dbus_connection_get_sync (daemon_monitor->remote_id, NULL, &error);
|
connection = _g_dbus_connection_get_sync (daemon_monitor->remote_id, NULL, &error);
|
||||||
|
if (connection == NULL && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_dbus_error_strip_remote_error (error);
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
|
||||||
|
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||||
|
}
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
{
|
{
|
||||||
g_printerr ("Error getting connection for monitoring: %s (%s, %d)\n",
|
g_printerr ("Error getting connection for monitoring: %s (%s, %d)\n",
|
||||||
|
|
|
@ -315,8 +315,19 @@ async_got_connection_cb (GDBusConnection *connection,
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
{
|
{
|
||||||
/* TODO: we should probably test if we really want a session bus;
|
g_dbus_error_strip_remote_error (io_error);
|
||||||
* for now, this code is on par with the old dbus code */
|
|
||||||
|
if (g_error_matches (io_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_task_return_error (task, g_error_copy (io_error));
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", io_error->message);
|
||||||
|
|
||||||
g_bus_get (G_BUS_TYPE_SESSION,
|
g_bus_get (G_BUS_TYPE_SESSION,
|
||||||
g_task_get_cancellable (task),
|
g_task_get_cancellable (task),
|
||||||
bus_get_cb,
|
bus_get_cb,
|
||||||
|
|
|
@ -1434,7 +1434,7 @@ g_daemon_vfs_deserialize_icon (GVfs *vfs,
|
||||||
GDBusConnection *
|
GDBusConnection *
|
||||||
_g_daemon_vfs_get_async_bus (void)
|
_g_daemon_vfs_get_async_bus (void)
|
||||||
{
|
{
|
||||||
return the_vfs ? the_vfs->async_bus : NULL;
|
return the_vfs->async_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -31,12 +31,14 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <glib/gi18n-lib.h>
|
#include <glib/gi18n-lib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include "gvfsdaemondbus.h"
|
#include "gvfsdaemondbus.h"
|
||||||
#include <gvfsdaemonprotocol.h>
|
#include <gvfsdaemonprotocol.h>
|
||||||
#include <gdaemonvfs.h>
|
#include <gdaemonvfs.h>
|
||||||
#include <gvfsdbus.h>
|
#include <gvfsdbus.h>
|
||||||
|
#include <gvfsutils.h>
|
||||||
|
|
||||||
/* Extra vfs-specific data for GDBusConnections */
|
/* Extra vfs-specific data for GDBusConnections */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -156,6 +158,7 @@ set_connection_for_async (GDBusConnection *connection, const char *dbus_id)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *dbus_id;
|
char *dbus_id;
|
||||||
|
|
||||||
|
GVfsDBusDaemon *proxy;
|
||||||
GDBusConnection *connection;
|
GDBusConnection *connection;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
@ -174,6 +177,7 @@ async_call_finish (AsyncDBusCall *async_call)
|
||||||
async_call->io_error,
|
async_call->io_error,
|
||||||
async_call->callback_data);
|
async_call->callback_data);
|
||||||
|
|
||||||
|
g_clear_object (&async_call->proxy);
|
||||||
g_clear_object (&async_call->connection);
|
g_clear_object (&async_call->connection);
|
||||||
g_clear_object (&async_call->cancellable);
|
g_clear_object (&async_call->cancellable);
|
||||||
g_clear_error (&async_call->io_error);
|
g_clear_error (&async_call->io_error);
|
||||||
|
@ -260,32 +264,67 @@ async_get_connection_response (GVfsDBusDaemon *proxy,
|
||||||
g_free (address1);
|
g_free (address1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
socket_dir_query_info_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
AsyncDBusCall *async_call = user_data;
|
||||||
|
g_autoptr (GFileInfo) socket_dir_info = NULL;
|
||||||
|
|
||||||
|
socket_dir_info = g_file_query_info_finish (G_FILE (source_object),
|
||||||
|
res,
|
||||||
|
&async_call->io_error);
|
||||||
|
if (socket_dir_info == NULL ||
|
||||||
|
!g_file_info_get_attribute_boolean (socket_dir_info,
|
||||||
|
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
|
||||||
|
{
|
||||||
|
if (!async_call->io_error)
|
||||||
|
async_call->io_error = g_error_new_literal (G_IO_ERROR,
|
||||||
|
G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
_("Permission denied"));
|
||||||
|
|
||||||
|
async_call_finish (async_call);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (async_call->proxy), G_VFS_DBUS_TIMEOUT_MSECS);
|
||||||
|
|
||||||
|
gvfs_dbus_daemon_call_get_connection (async_call->proxy,
|
||||||
|
async_call->cancellable,
|
||||||
|
(GAsyncReadyCallback) async_get_connection_response,
|
||||||
|
async_call);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
open_connection_async_cb (GObject *source_object,
|
open_connection_async_cb (GObject *source_object,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GVfsDBusDaemon *proxy;
|
|
||||||
AsyncDBusCall *async_call = user_data;
|
AsyncDBusCall *async_call = user_data;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
g_autofree gchar *socket_dir_path = NULL;
|
||||||
proxy = gvfs_dbus_daemon_proxy_new_finish (res, &error);
|
g_autoptr (GFile) socket_dir = NULL;
|
||||||
if (proxy == NULL)
|
|
||||||
|
async_call->proxy = gvfs_dbus_daemon_proxy_new_finish (res, &error);
|
||||||
|
if (async_call->proxy == NULL)
|
||||||
{
|
{
|
||||||
async_call->io_error = g_error_copy (error);
|
async_call->io_error = g_error_copy (error);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
async_call_finish (async_call);
|
async_call_finish (async_call);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_TIMEOUT_MSECS);
|
/* This is needed to prevent socket leaks. */
|
||||||
|
socket_dir_path = gvfs_get_socket_dir ();
|
||||||
gvfs_dbus_daemon_call_get_connection (proxy,
|
socket_dir = g_file_new_for_path (socket_dir_path);
|
||||||
async_call->cancellable,
|
g_file_query_info_async (socket_dir,
|
||||||
(GAsyncReadyCallback) async_get_connection_response,
|
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
|
||||||
async_call);
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
g_object_unref (proxy);
|
async_call->cancellable,
|
||||||
|
socket_dir_query_info_cb,
|
||||||
|
user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -522,6 +561,9 @@ _g_dbus_connection_get_sync (const char *dbus_id,
|
||||||
gchar *address1;
|
gchar *address1;
|
||||||
GVfsDBusDaemon *daemon_proxy;
|
GVfsDBusDaemon *daemon_proxy;
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
g_autofree gchar *socket_dir_path = NULL;
|
||||||
|
g_autoptr (GFile) socket_dir = NULL;
|
||||||
|
g_autoptr (GFileInfo) socket_dir_info = NULL;
|
||||||
|
|
||||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -591,6 +633,26 @@ _g_dbus_connection_get_sync (const char *dbus_id,
|
||||||
if (daemon_proxy == NULL)
|
if (daemon_proxy == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/* This is needed to prevent socket leaks. */
|
||||||
|
socket_dir_path = gvfs_get_socket_dir ();
|
||||||
|
socket_dir = g_file_new_for_path (socket_dir_path);
|
||||||
|
socket_dir_info = g_file_query_info (socket_dir,
|
||||||
|
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
|
||||||
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
if (socket_dir_info == NULL ||
|
||||||
|
!g_file_info_get_attribute_boolean (socket_dir_info,
|
||||||
|
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
|
||||||
|
{
|
||||||
|
if (error && !*error)
|
||||||
|
*error = g_error_new_literal (G_IO_ERROR,
|
||||||
|
G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
_("Permission denied"));
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
address1 = NULL;
|
address1 = NULL;
|
||||||
res = gvfs_dbus_daemon_call_get_connection_sync (daemon_proxy,
|
res = gvfs_dbus_daemon_call_get_connection_sync (daemon_proxy,
|
||||||
&address1,
|
&address1,
|
||||||
|
|
|
@ -43,7 +43,8 @@
|
||||||
#include <gvfsdbus.h>
|
#include <gvfsdbus.h>
|
||||||
#include <gvfsutils.h>
|
#include <gvfsutils.h>
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
|
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include <fuse_lowlevel.h>
|
#include <fuse_lowlevel.h>
|
||||||
|
|
||||||
|
@ -859,7 +860,7 @@ getattr_for_file_handle (FileHandle *fh, struct stat *sbuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_getattr (const gchar *path, struct stat *sbuf)
|
vfs_getattr (const gchar *path, struct stat *sbuf, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
GFile *file;
|
GFile *file;
|
||||||
gint result = 0;
|
gint result = 0;
|
||||||
|
@ -1090,6 +1091,9 @@ open_common (const gchar *path, struct fuse_file_info *fi, GFile *file, int outp
|
||||||
|
|
||||||
g_mutex_unlock (&fh->mutex);
|
g_mutex_unlock (&fh->mutex);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
file_handle_unref (fh);
|
||||||
|
|
||||||
/* The added reference to the file handle is released in vfs_release() */
|
/* The added reference to the file handle is released in vfs_release() */
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1581,12 +1585,12 @@ readdir_for_file (GFile *base_file, gpointer buf, fuse_fill_dir_t filler)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
filler (buf, ".", NULL, 0);
|
filler (buf, ".", NULL, 0, 0);
|
||||||
filler (buf, "..", NULL, 0);
|
filler (buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
|
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
|
||||||
{
|
{
|
||||||
filler (buf, g_file_info_get_name (file_info), NULL, 0);
|
filler (buf, g_file_info_get_name (file_info), NULL, 0, 0);
|
||||||
g_object_unref (file_info);
|
g_object_unref (file_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1597,7 +1601,7 @@ readdir_for_file (GFile *base_file, gpointer buf, fuse_fill_dir_t filler)
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offset,
|
vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offset,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi, enum fuse_readdir_flags fl)
|
||||||
{
|
{
|
||||||
GFile *base_file;
|
GFile *base_file;
|
||||||
gint result = 0;
|
gint result = 0;
|
||||||
|
@ -1610,8 +1614,8 @@ vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offs
|
||||||
|
|
||||||
/* Mount list */
|
/* Mount list */
|
||||||
|
|
||||||
filler (buf, ".", NULL, 0);
|
filler (buf, ".", NULL, 0, 0);
|
||||||
filler (buf, "..", NULL, 0);
|
filler (buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
mount_list_lock ();
|
mount_list_lock ();
|
||||||
|
|
||||||
|
@ -1619,7 +1623,7 @@ vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offs
|
||||||
{
|
{
|
||||||
MountRecord *mount_record = l->data;
|
MountRecord *mount_record = l->data;
|
||||||
|
|
||||||
filler (buf, mount_record->name, NULL, 0);
|
filler (buf, mount_record->name, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mount_list_unlock ();
|
mount_list_unlock ();
|
||||||
|
@ -1643,13 +1647,21 @@ vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offs
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_rename (const gchar *old_path, const gchar *new_path)
|
vfs_rename (const gchar *old_path, const gchar *new_path, unsigned int vfs_flags)
|
||||||
{
|
{
|
||||||
GFile *old_file;
|
GFile *old_file;
|
||||||
GFile *new_file;
|
GFile *new_file;
|
||||||
|
GFileCopyFlags flags = G_FILE_COPY_OVERWRITE;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gint result = 0;
|
gint result = 0;
|
||||||
|
|
||||||
|
/* Can not implement this flag because limitation of GFile. */
|
||||||
|
if (vfs_flags & RENAME_EXCHANGE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (vfs_flags & RENAME_NOREPLACE)
|
||||||
|
flags = G_FILE_COPY_NONE;
|
||||||
|
|
||||||
g_debug ("vfs_rename: %s -> %s\n", old_path, new_path);
|
g_debug ("vfs_rename: %s -> %s\n", old_path, new_path);
|
||||||
|
|
||||||
old_file = file_from_full_path (old_path);
|
old_file = file_from_full_path (old_path);
|
||||||
|
@ -1665,7 +1677,7 @@ vfs_rename (const gchar *old_path, const gchar *new_path)
|
||||||
file_handle_close_stream (fh);
|
file_handle_close_stream (fh);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_file_move (old_file, new_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
|
g_file_move (old_file, new_file, flags, NULL, NULL, NULL, &error);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -2072,6 +2084,15 @@ vfs_truncate (const gchar *path, off_t size)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
vfs_truncate_dispatch (const gchar *path, off_t size, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
if (fi)
|
||||||
|
return vfs_ftruncate (path, size, fi);
|
||||||
|
|
||||||
|
return vfs_truncate (path, size);
|
||||||
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_symlink (const gchar *path_old, const gchar *path_new)
|
vfs_symlink (const gchar *path_old, const gchar *path_new)
|
||||||
{
|
{
|
||||||
|
@ -2178,7 +2199,7 @@ vfs_access (const gchar *path, gint mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_utimens (const gchar *path, const struct timespec tv [2])
|
vfs_utimens (const gchar *path, const struct timespec tv [2], struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
GFile *file;
|
GFile *file;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
@ -2253,7 +2274,7 @@ vfs_utimens (const gchar *path, const struct timespec tv [2])
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
vfs_chmod (const gchar *path, mode_t mode)
|
vfs_chmod (const gchar *path, mode_t mode, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
GFile *file;
|
GFile *file;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
@ -2376,7 +2397,7 @@ register_fuse_cb (GVfsDBusMountTracker *proxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gpointer
|
static gpointer
|
||||||
vfs_init (struct fuse_conn_info *conn)
|
vfs_init (struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
{
|
{
|
||||||
GVfsDBusMountTracker *proxy;
|
GVfsDBusMountTracker *proxy;
|
||||||
GError *error;
|
GError *error;
|
||||||
|
@ -2452,11 +2473,7 @@ vfs_init (struct fuse_conn_info *conn)
|
||||||
conn->want |= FUSE_CAP_ATOMIC_O_TRUNC;
|
conn->want |= FUSE_CAP_ATOMIC_O_TRUNC;
|
||||||
|
|
||||||
/* Prevent out-of-order readahead */
|
/* Prevent out-of-order readahead */
|
||||||
conn->async_read = 0;
|
conn->want &= ~FUSE_CAP_ASYNC_READ;
|
||||||
|
|
||||||
/* Use up to a 64KiB write block size. Only has an effect if -o big_writes
|
|
||||||
* is given on the command-line. */
|
|
||||||
conn->max_write = 65536;
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2503,8 +2520,7 @@ static struct fuse_operations vfs_oper =
|
||||||
.unlink = vfs_unlink,
|
.unlink = vfs_unlink,
|
||||||
.mkdir = vfs_mkdir,
|
.mkdir = vfs_mkdir,
|
||||||
.rmdir = vfs_rmdir,
|
.rmdir = vfs_rmdir,
|
||||||
.ftruncate = vfs_ftruncate,
|
.truncate = vfs_truncate_dispatch,
|
||||||
.truncate = vfs_truncate,
|
|
||||||
.symlink = vfs_symlink,
|
.symlink = vfs_symlink,
|
||||||
.access = vfs_access,
|
.access = vfs_access,
|
||||||
.utimens = vfs_utimens,
|
.utimens = vfs_utimens,
|
||||||
|
@ -2516,6 +2532,7 @@ static struct fuse_operations vfs_oper =
|
||||||
.getxattr = vfs_getxattr,
|
.getxattr = vfs_getxattr,
|
||||||
.listxattr = vfs_listxattr,
|
.listxattr = vfs_listxattr,
|
||||||
.removexattr = vfs_removexattr,
|
.removexattr = vfs_removexattr,
|
||||||
|
.ftruncate = vfs_ftruncate,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2537,35 +2554,65 @@ gint
|
||||||
main (gint argc, gchar *argv [])
|
main (gint argc, gchar *argv [])
|
||||||
{
|
{
|
||||||
struct fuse *fuse;
|
struct fuse *fuse;
|
||||||
struct fuse_chan *ch;
|
|
||||||
struct fuse_session *se;
|
struct fuse_session *se;
|
||||||
char *mountpoint;
|
|
||||||
int multithreaded;
|
|
||||||
int res;
|
int res;
|
||||||
|
struct fuse_cmdline_opts opts;
|
||||||
|
struct fuse_args args = FUSE_ARGS_INIT (argc, argv);
|
||||||
|
|
||||||
fuse = fuse_setup (argc, argv, &vfs_oper, sizeof (vfs_oper), &mountpoint,
|
if (fuse_opt_parse (&args, NULL, NULL, NULL) == -1)
|
||||||
&multithreaded, NULL /* user data */);
|
return 1;
|
||||||
|
|
||||||
|
if (fuse_parse_cmdline (&args, &opts) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (opts.show_version)
|
||||||
|
{
|
||||||
|
printf ("%s\n", PACKAGE_STRING);
|
||||||
|
fuse_lowlevel_version ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.show_help)
|
||||||
|
{
|
||||||
|
printf ("usage: %s [options] <mountpoint>\n\n", argv[0]);
|
||||||
|
printf ("FUSE options:\n");
|
||||||
|
fuse_cmdline_help ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.mountpoint)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "error: no mountpoint specified\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fuse = fuse_new (&args, &vfs_oper, sizeof (vfs_oper), NULL /* user data */);
|
||||||
if (fuse == NULL)
|
if (fuse == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (multithreaded)
|
if (fuse_mount (fuse, opts.mountpoint) != 0)
|
||||||
res = fuse_loop_mt (fuse);
|
return 1;
|
||||||
else
|
|
||||||
res = fuse_loop (fuse);
|
if (fuse_daemonize (opts.foreground) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
se = fuse_get_session (fuse);
|
se = fuse_get_session (fuse);
|
||||||
ch = fuse_session_next_chan (se, NULL);
|
if (fuse_set_signal_handlers (se) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (opts.singlethread)
|
||||||
|
res = fuse_loop (fuse);
|
||||||
|
else
|
||||||
|
res = fuse_loop_mt (fuse, opts.clone_fd);
|
||||||
|
|
||||||
/* Ignore new signals during exit procedure in order to terminate properly */
|
/* Ignore new signals during exit procedure in order to terminate properly */
|
||||||
set_custom_signal_handlers (SIG_IGN);
|
set_custom_signal_handlers (SIG_IGN);
|
||||||
fuse_remove_signal_handlers (se);
|
fuse_remove_signal_handlers (se);
|
||||||
|
|
||||||
fuse_unmount (mountpoint, ch);
|
fuse_unmount (fuse);
|
||||||
fuse_destroy (fuse);
|
fuse_destroy (fuse);
|
||||||
free (mountpoint);
|
free (opts.mountpoint);
|
||||||
|
fuse_opt_free_args (&args);
|
||||||
|
|
||||||
if (res == -1)
|
return res;
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,17 @@ create_proxy_for_icon (GVfsIcon *vfs_icon,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
connection = _g_dbus_connection_get_sync (mount_info->dbus_id, cancellable, &local_error);
|
connection = _g_dbus_connection_get_sync (mount_info->dbus_id, cancellable, &local_error);
|
||||||
|
if (connection == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_dbus_error_strip_remote_error (local_error);
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", local_error->message);
|
||||||
|
g_clear_error (&local_error);
|
||||||
|
|
||||||
|
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
|
||||||
|
}
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -196,20 +207,9 @@ async_proxy_new_cb (GObject *source_object,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
async_got_connection_cb (GDBusConnection *connection,
|
async_construct_proxy (GDBusConnection *connection,
|
||||||
GError *io_error,
|
AsyncPathCall *data)
|
||||||
gpointer callback_data)
|
|
||||||
{
|
{
|
||||||
AsyncPathCall *data = callback_data;
|
|
||||||
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
g_dbus_error_strip_remote_error (io_error);
|
|
||||||
g_task_return_error (data->task, io_error);
|
|
||||||
async_path_call_free (data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->connection = g_object_ref (connection);
|
data->connection = g_object_ref (connection);
|
||||||
gvfs_dbus_mount_proxy_new (connection,
|
gvfs_dbus_mount_proxy_new (connection,
|
||||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
||||||
|
@ -220,6 +220,62 @@ async_got_connection_cb (GDBusConnection *connection,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
bus_get_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
AsyncPathCall *data = user_data;
|
||||||
|
GDBusConnection *connection;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
connection = g_bus_get_finish (res, &error);
|
||||||
|
|
||||||
|
if (connection == NULL)
|
||||||
|
{
|
||||||
|
g_dbus_error_strip_remote_error (error);
|
||||||
|
g_task_return_error (data->task, error);
|
||||||
|
async_path_call_free (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async_construct_proxy (connection, data);
|
||||||
|
g_object_unref (connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
async_got_connection_cb (GDBusConnection *connection,
|
||||||
|
GError *io_error,
|
||||||
|
gpointer callback_data)
|
||||||
|
{
|
||||||
|
AsyncPathCall *data = callback_data;
|
||||||
|
|
||||||
|
if (connection == NULL)
|
||||||
|
{
|
||||||
|
g_dbus_error_strip_remote_error (io_error);
|
||||||
|
|
||||||
|
if (g_error_matches (io_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
g_task_return_error (data->task, g_error_copy (io_error));
|
||||||
|
async_path_call_free (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_warning ("The peer-to-peer connection failed: %s. Falling back to the "
|
||||||
|
"session bus. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.", io_error->message);
|
||||||
|
|
||||||
|
g_bus_get (G_BUS_TYPE_SESSION,
|
||||||
|
g_task_get_cancellable (data->task),
|
||||||
|
bus_get_cb,
|
||||||
|
data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async_construct_proxy (connection, data);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
async_got_mount_info (GMountInfo *mount_info,
|
async_got_mount_info (GMountInfo *mount_info,
|
||||||
gpointer _data,
|
gpointer _data,
|
||||||
|
|
|
@ -245,7 +245,21 @@ g_vfs_decode_uri (const char *uri)
|
||||||
decoded->port = -1;
|
decoded->port = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoded->host = g_uri_unescape_segment (host_start, host_end, NULL);
|
/* Let's use the IPv6 address without unescaping. This is needed in order
|
||||||
|
* to prevent g_uri_unescape_segment failures when zone identifier
|
||||||
|
* separated by the bare % as it is defined by RFC 4007 is used here. The
|
||||||
|
* zone identifier should contain just ASCII characters as per RFC 4007,
|
||||||
|
* so it doesn't need to be unescaped. I intentionally don't support here
|
||||||
|
* what is suggested by RFC 6874, which changes the separator to %25 and
|
||||||
|
* at the same time, it suggests that the bare % sign should still be
|
||||||
|
* accepted in user interfaces. Such a thing would make this too complex
|
||||||
|
* and lead to various problems (e.g. it would not be clear what separator
|
||||||
|
* should be used for g_file_get_uri function)...
|
||||||
|
*/
|
||||||
|
if (*host_start == '[')
|
||||||
|
decoded->host = g_strndup (host_start, host_end - host_start);
|
||||||
|
else
|
||||||
|
decoded->host = g_uri_unescape_segment (host_start, host_end, NULL);
|
||||||
|
|
||||||
hier_part_start = authority_end;
|
hier_part_start = authority_end;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ sources = uri_parser_sources + uri_utils + files(
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
gio_unix_dep,
|
gio_unix_dep,
|
||||||
libgvfscommon_dep,
|
|
||||||
libmetadata_dep,
|
libmetadata_dep,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -129,19 +129,16 @@ gvfs_setup_debug_handler (void)
|
||||||
gboolean
|
gboolean
|
||||||
gvfs_is_ipv6 (const char *host)
|
gvfs_is_ipv6 (const char *host)
|
||||||
{
|
{
|
||||||
const char *p = host;
|
|
||||||
|
|
||||||
g_return_val_if_fail (host != NULL, FALSE);
|
g_return_val_if_fail (host != NULL, FALSE);
|
||||||
|
|
||||||
if (*p != '[')
|
if (*host != '[' || host[strlen (host) - 1] != ']')
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
while (++p)
|
|
||||||
if (!g_ascii_isxdigit (*p) && *p != ':')
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (*p != ']' || *(p + 1) != '\0')
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
gvfs_get_socket_dir (void)
|
||||||
|
{
|
||||||
|
return g_build_filename (g_get_user_runtime_dir (), "gvfsd", NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ void gvfs_set_debug (gboolean debugging
|
||||||
void gvfs_setup_debug_handler (void);
|
void gvfs_setup_debug_handler (void);
|
||||||
|
|
||||||
gboolean gvfs_is_ipv6 (const char *host);
|
gboolean gvfs_is_ipv6 (const char *host);
|
||||||
|
gchar * gvfs_get_socket_dir (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[Mount]
|
[Mount]
|
||||||
Type=admin
|
Type=admin
|
||||||
# Add a dummy argument after pkexec, or '/bin/sh -c' will eat the first argument in '$@'
|
# Add a dummy argument after pkexec, or '/bin/sh -c' will eat the first argument in '$@'
|
||||||
Exec=/bin/sh -c 'pkexec @libexecdir@/gvfsd-admin "$@" --address $DBUS_SESSION_BUS_ADDRESS' gvfsd-admin
|
Exec=/bin/sh -c 'pkexec @libexecdir@/gvfsd-admin "$@" --address $DBUS_SESSION_BUS_ADDRESS --dir $XDG_RUNTIME_DIR' gvfsd-admin
|
||||||
AutoMount=false
|
AutoMount=false
|
||||||
DBusName=org.gtk.vfs.mountpoint_admin
|
DBusName=org.gtk.vfs.mountpoint_admin
|
||||||
MountPerClient=true
|
MountPerClient=true
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service
|
Description=Virtual filesystem service
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfsd
|
ExecStart=@libexecdir@/gvfsd
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.Daemon
|
BusName=org.gtk.vfs.Daemon
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -1053,22 +1053,17 @@ g_vfs_afp_server_login (GVfsAfpServer *server,
|
||||||
gboolean aborted;
|
gboolean aborted;
|
||||||
|
|
||||||
g_free (prompt);
|
g_free (prompt);
|
||||||
|
g_clear_error (&err);
|
||||||
|
|
||||||
str = g_string_new (NULL);
|
str = g_string_new (NULL);
|
||||||
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
g_string_append_printf (str, "%s\n", err->message);
|
|
||||||
g_clear_error (&err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create prompt */
|
/* create prompt */
|
||||||
if (initial_user)
|
if (initial_user)
|
||||||
/* translators: %s here is the hostname */
|
/* Translators: the first %s is the username, the second the host name */
|
||||||
g_string_append_printf (str, _("Enter your password for the server “%s”."), server_name);
|
g_string_append_printf (str, _("Authentication Required\nEnter password for “%s” on “%s”:"), initial_user, server_name);
|
||||||
else
|
else
|
||||||
/* translators: %s here is the hostname */
|
/* Translators: %s here is the hostname */
|
||||||
g_string_append_printf (str, _("Enter your name and password for the server “%s”."), server_name);
|
g_string_append_printf (str, _("Authentication Required\nEnter user and password for “%s”:"), server_name);
|
||||||
|
|
||||||
prompt = g_string_free (str, FALSE);
|
prompt = g_string_free (str, FALSE);
|
||||||
|
|
||||||
|
|
|
@ -524,6 +524,8 @@ get_thumbnail_attributes (const char *uri,
|
||||||
GChecksum *checksum;
|
GChecksum *checksum;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *basename;
|
char *basename;
|
||||||
|
const char *size_dirs[4] = { "xx-large", "x-large", "large", "normal" };
|
||||||
|
gsize i;
|
||||||
|
|
||||||
checksum = g_checksum_new (G_CHECKSUM_MD5);
|
checksum = g_checksum_new (G_CHECKSUM_MD5);
|
||||||
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
|
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
|
||||||
|
@ -531,34 +533,31 @@ get_thumbnail_attributes (const char *uri,
|
||||||
basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
|
basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
|
||||||
g_checksum_free (checksum);
|
g_checksum_free (checksum);
|
||||||
|
|
||||||
filename = g_build_filename (g_get_user_cache_dir (),
|
for (i = 0; i < G_N_ELEMENTS (size_dirs); i++)
|
||||||
"thumbnails", "large", basename,
|
{
|
||||||
NULL);
|
filename = g_build_filename (g_get_user_cache_dir (),
|
||||||
|
"thumbnails", size_dirs[i], basename,
|
||||||
|
NULL);
|
||||||
|
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
||||||
|
break;
|
||||||
|
|
||||||
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
g_clear_pointer (&filename, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename)
|
||||||
g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
|
g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_free (filename);
|
|
||||||
filename = g_build_filename (g_get_user_cache_dir (),
|
filename = g_build_filename (g_get_user_cache_dir (),
|
||||||
"thumbnails", "normal", basename,
|
"thumbnails", "fail",
|
||||||
|
"gnome-thumbnail-factory",
|
||||||
|
basename,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
||||||
g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
|
||||||
else
|
|
||||||
{
|
|
||||||
g_free (filename);
|
|
||||||
filename = g_build_filename (g_get_user_cache_dir (),
|
|
||||||
"thumbnails", "fail",
|
|
||||||
"gnome-thumbnail-factory",
|
|
||||||
basename,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (basename);
|
g_free (basename);
|
||||||
g_free (filename);
|
g_free (filename);
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,15 @@ check_permission (GVfsBackendAdmin *self,
|
||||||
invocation = dbus_job->invocation;
|
invocation = dbus_job->invocation;
|
||||||
connection = g_dbus_method_invocation_get_connection (invocation);
|
connection = g_dbus_method_invocation_get_connection (invocation);
|
||||||
credentials = g_dbus_connection_get_peer_credentials (connection);
|
credentials = g_dbus_connection_get_peer_credentials (connection);
|
||||||
|
if (!credentials)
|
||||||
|
{
|
||||||
|
g_warning ("The admin backend doesn't work with the session bus "
|
||||||
|
"fallback. Your application is probably missing "
|
||||||
|
"--filesystem=xdg-run/gvfsd privileges.");
|
||||||
|
g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
pid = g_credentials_get_unix_pid (credentials, &error);
|
pid = g_credentials_get_unix_pid (credentials, &error);
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
|
@ -807,6 +816,36 @@ do_move (GVfsBackend *backend,
|
||||||
complete_job (job, error);
|
complete_job (job, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_copy (GVfsBackend *backend,
|
||||||
|
GVfsJobCopy *copy_job,
|
||||||
|
const char *source,
|
||||||
|
const char *destination,
|
||||||
|
GFileCopyFlags flags,
|
||||||
|
GFileProgressCallback progress_callback,
|
||||||
|
gpointer progress_callback_data)
|
||||||
|
{
|
||||||
|
GVfsBackendAdmin *self = G_VFS_BACKEND_ADMIN (backend);
|
||||||
|
GVfsJob *job = G_VFS_JOB (copy_job);
|
||||||
|
GError *error = NULL;
|
||||||
|
GFile *src_file, *dst_file;
|
||||||
|
|
||||||
|
if (!check_permission (self, job))
|
||||||
|
return;
|
||||||
|
|
||||||
|
src_file = g_file_new_for_path (source);
|
||||||
|
dst_file = g_file_new_for_path (destination);
|
||||||
|
g_file_copy (src_file, dst_file, flags,
|
||||||
|
job->cancellable,
|
||||||
|
progress_callback, progress_callback_data,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
g_object_unref (src_file);
|
||||||
|
g_object_unref (dst_file);
|
||||||
|
|
||||||
|
complete_job (job, error);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_pull (GVfsBackend *backend,
|
do_pull (GVfsBackend *backend,
|
||||||
GVfsJobPull *pull_job,
|
GVfsJobPull *pull_job,
|
||||||
|
@ -852,6 +891,40 @@ do_pull (GVfsBackend *backend,
|
||||||
complete_job (job, error);
|
complete_job (job, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_push (GVfsBackend *backend,
|
||||||
|
GVfsJobPush *push_job,
|
||||||
|
const char *destination,
|
||||||
|
const char *local_path,
|
||||||
|
GFileCopyFlags flags,
|
||||||
|
gboolean remove_source,
|
||||||
|
GFileProgressCallback progress_callback,
|
||||||
|
gpointer progress_callback_data)
|
||||||
|
{
|
||||||
|
GVfsBackendAdmin *self = G_VFS_BACKEND_ADMIN (backend);
|
||||||
|
GVfsJob *job = G_VFS_JOB (push_job);
|
||||||
|
GError *error = NULL;
|
||||||
|
GFile *src_file, *dst_file;
|
||||||
|
|
||||||
|
if (!check_permission (self, job))
|
||||||
|
return;
|
||||||
|
|
||||||
|
src_file = g_file_new_for_path (local_path);
|
||||||
|
dst_file = g_file_new_for_path (destination);
|
||||||
|
|
||||||
|
if (remove_source)
|
||||||
|
g_file_move (src_file, dst_file, flags, job->cancellable,
|
||||||
|
progress_callback, progress_callback_data, &error);
|
||||||
|
else
|
||||||
|
g_file_copy (src_file, dst_file, flags, job->cancellable,
|
||||||
|
progress_callback, progress_callback_data, &error);
|
||||||
|
|
||||||
|
g_object_unref (src_file);
|
||||||
|
g_object_unref (dst_file);
|
||||||
|
|
||||||
|
complete_job (job, error);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_query_settable_attributes (GVfsBackend *backend,
|
do_query_settable_attributes (GVfsBackend *backend,
|
||||||
GVfsJobQueryAttributes *query_job,
|
GVfsJobQueryAttributes *query_job,
|
||||||
|
@ -972,7 +1045,9 @@ g_vfs_backend_admin_class_init (GVfsBackendAdminClass * klass)
|
||||||
backend_class->set_attribute = do_set_attribute;
|
backend_class->set_attribute = do_set_attribute;
|
||||||
backend_class->delete = do_delete;
|
backend_class->delete = do_delete;
|
||||||
backend_class->move = do_move;
|
backend_class->move = do_move;
|
||||||
|
backend_class->copy = do_copy;
|
||||||
backend_class->pull = do_pull;
|
backend_class->pull = do_pull;
|
||||||
|
backend_class->push = do_push;
|
||||||
backend_class->query_settable_attributes = do_query_settable_attributes;
|
backend_class->query_settable_attributes = do_query_settable_attributes;
|
||||||
backend_class->query_writable_namespaces = do_query_writable_namespaces;
|
backend_class->query_writable_namespaces = do_query_writable_namespaces;
|
||||||
}
|
}
|
||||||
|
@ -1028,8 +1103,10 @@ acquire_caps (uid_t uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *session_address = NULL;
|
static char *session_address = NULL;
|
||||||
|
static char *runtime_dir = NULL;
|
||||||
static GOptionEntry entries[] = {
|
static GOptionEntry entries[] = {
|
||||||
{ "address", 0, 0, G_OPTION_ARG_STRING, &session_address, "DBus session address", NULL },
|
{ "address", 0, 0, G_OPTION_ARG_STRING, &session_address, "DBus session address", NULL },
|
||||||
|
{ "dir", 0, 0, G_OPTION_ARG_STRING, &runtime_dir, "Runtime dir", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1068,4 +1145,7 @@ g_vfs_backend_admin_pre_setup (int *argc,
|
||||||
|
|
||||||
acquire_caps (uid);
|
acquire_caps (uid);
|
||||||
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_address, TRUE);
|
g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_address, TRUE);
|
||||||
|
|
||||||
|
if (runtime_dir)
|
||||||
|
g_setenv ("XDG_RUNTIME_DIR", runtime_dir, TRUE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -574,7 +574,7 @@ g_vfs_backend_afc_mount (GVfsBackend *backend,
|
||||||
/* translators:
|
/* translators:
|
||||||
* %s is the device name. 'Try again' is the caption of the button
|
* %s is the device name. 'Try again' is the caption of the button
|
||||||
* shown in the dialog which is defined above. */
|
* shown in the dialog which is defined above. */
|
||||||
message = g_strdup_printf (_("The device “%s” is locked. Enter the passcode on the device and click “Try again”."), display_name);
|
message = g_strdup_printf (_("Device Locked\nThe device “%s” is locked.\n\nEnter the passcode on the device and click “Try again”."), display_name);
|
||||||
}
|
}
|
||||||
else if (lerr == LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING)
|
else if (lerr == LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING)
|
||||||
{
|
{
|
||||||
|
@ -582,7 +582,7 @@ g_vfs_backend_afc_mount (GVfsBackend *backend,
|
||||||
* %s is the device name. 'Try again' is the caption of the button
|
* %s is the device name. 'Try again' is the caption of the button
|
||||||
* shown in the dialog which is defined above. 'Trust' is the caption
|
* shown in the dialog which is defined above. 'Trust' is the caption
|
||||||
* of the button shown in the device. */
|
* of the button shown in the device. */
|
||||||
message = g_strdup_printf (_("The device “%s” is not trusted yet. Select “Trust” on the device and click “Try again”."), display_name);
|
message = g_strdup_printf (_("Untrusted Device\nThe device “%s” is not trusted yet.\n\nSelect “Trust” on the device and click “Try again”."), display_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
@ -2186,6 +2186,7 @@ g_vfs_backend_afc_query_fs_info (GVfsBackend *backend,
|
||||||
|
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afc");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afc");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (!self->connected)
|
if (!self->connected)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1821,6 +1821,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
|
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afp");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afp");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
|
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
|
||||||
vol_bitmap |= AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT;
|
vol_bitmap |= AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT;
|
||||||
|
|
|
@ -540,6 +540,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afp");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "afp");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1033,6 +1033,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "burn");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "burn");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1424,6 +1424,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "computer");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "computer");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -842,6 +842,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "dns-sd");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "dns-sd");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,10 +527,10 @@ restart:
|
||||||
{
|
{
|
||||||
if (ftp->has_initial_user)
|
if (ftp->has_initial_user)
|
||||||
/* Translators: the first %s is the username, the second the host name */
|
/* Translators: the first %s is the username, the second the host name */
|
||||||
prompt = g_strdup_printf (_("Enter password for %s on %s"), ftp->user, ftp->host_display_name);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter password for “%s” on “%s”:"), ftp->user, ftp->host_display_name);
|
||||||
else
|
else
|
||||||
/* translators: %s here is the hostname */
|
/* Translators: %s here is the hostname */
|
||||||
prompt = g_strdup_printf (_("Enter password for %s"), ftp->host_display_name);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter user and password for “%s”:"), ftp->host_display_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = G_ASK_PASSWORD_NEED_PASSWORD;
|
flags = G_ASK_PASSWORD_NEED_PASSWORD;
|
||||||
|
@ -1533,47 +1533,6 @@ out:
|
||||||
g_vfs_ftp_task_done (&task);
|
g_vfs_ftp_task_done (&task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gssize
|
|
||||||
ftp_output_stream_splice (GOutputStream *output,
|
|
||||||
GInputStream *input,
|
|
||||||
goffset total_size,
|
|
||||||
GFileProgressCallback progress_callback,
|
|
||||||
gpointer progress_callback_data,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gssize n_read, n_written;
|
|
||||||
gssize bytes_copied;
|
|
||||||
char buffer[8192], *p;
|
|
||||||
|
|
||||||
bytes_copied = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
n_read = g_input_stream_read (input, buffer, sizeof (buffer), cancellable, error);
|
|
||||||
if (n_read == -1)
|
|
||||||
return -1;
|
|
||||||
if (n_read == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
p = buffer;
|
|
||||||
while (n_read > 0)
|
|
||||||
{
|
|
||||||
n_written = g_output_stream_write (output, p, n_read, cancellable, error);
|
|
||||||
if (n_written == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
p += n_written;
|
|
||||||
n_read -= n_written;
|
|
||||||
bytes_copied += n_written;
|
|
||||||
|
|
||||||
if (progress_callback)
|
|
||||||
progress_callback (bytes_copied, total_size, progress_callback_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_copied;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_pull_improve_error_message (GVfsFtpTask *task,
|
do_pull_improve_error_message (GVfsFtpTask *task,
|
||||||
GFile *dest,
|
GFile *dest,
|
||||||
|
@ -1657,6 +1616,15 @@ do_pull (GVfsBackend * backend,
|
||||||
src = g_vfs_ftp_file_new_from_gvfs (ftp, source);
|
src = g_vfs_ftp_file_new_from_gvfs (ftp, source);
|
||||||
dest = g_file_new_for_path (local_path);
|
dest = g_file_new_for_path (local_path);
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
||||||
|
{
|
||||||
|
g_set_error_literal (&task.error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the source is a symlink, then it needs to be handled specially. */
|
/* If the source is a symlink, then it needs to be handled specially. */
|
||||||
if (flags & G_FILE_COPY_NOFOLLOW_SYMLINKS)
|
if (flags & G_FILE_COPY_NOFOLLOW_SYMLINKS)
|
||||||
{
|
{
|
||||||
|
@ -1726,18 +1694,19 @@ do_pull (GVfsBackend * backend,
|
||||||
}
|
}
|
||||||
|
|
||||||
input = g_io_stream_get_input_stream (g_vfs_ftp_connection_get_data_stream (task.conn));
|
input = g_io_stream_get_input_stream (g_vfs_ftp_connection_get_data_stream (task.conn));
|
||||||
ftp_output_stream_splice (output,
|
gvfs_output_stream_splice (output,
|
||||||
input,
|
input,
|
||||||
total_size,
|
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||||
progress_callback,
|
total_size,
|
||||||
progress_callback_data,
|
progress_callback,
|
||||||
task.cancellable,
|
progress_callback_data,
|
||||||
&task.error);
|
task.cancellable,
|
||||||
|
&task.error);
|
||||||
g_vfs_ftp_task_close_data_connection (&task);
|
g_vfs_ftp_task_close_data_connection (&task);
|
||||||
g_vfs_ftp_task_receive (&task, 0, NULL);
|
g_vfs_ftp_task_receive (&task, 0, NULL);
|
||||||
g_object_unref (output);
|
g_object_unref (output);
|
||||||
|
|
||||||
if (remove_source)
|
if (!g_vfs_ftp_task_is_in_error (&task) && remove_source)
|
||||||
{
|
{
|
||||||
g_vfs_ftp_task_send (&task,
|
g_vfs_ftp_task_send (&task,
|
||||||
G_VFS_FTP_PASS_500,
|
G_VFS_FTP_PASS_500,
|
||||||
|
@ -1759,6 +1728,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "ftp");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "ftp");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,17 +49,22 @@
|
||||||
#include "gvfsjobsetdisplayname.h"
|
#include "gvfsjobsetdisplayname.h"
|
||||||
#include "gvfsjobwrite.h"
|
#include "gvfsjobwrite.h"
|
||||||
#include "gvfsmonitor.h"
|
#include "gvfsmonitor.h"
|
||||||
|
#include "gvfsdaemonutils.h"
|
||||||
|
|
||||||
struct _GVfsBackendGoogle
|
struct _GVfsBackendGoogle
|
||||||
{
|
{
|
||||||
GVfsBackend parent;
|
GVfsBackend parent;
|
||||||
GDataDocumentsService *service;
|
GDataDocumentsService *service;
|
||||||
GDataEntry *root;
|
GDataEntry *root;
|
||||||
|
GDataEntry *home;
|
||||||
|
GDataEntry *shared_with_me_dir;
|
||||||
|
GDataEntry *shared_drives_dir;
|
||||||
GHashTable *entries; /* gchar *entry_id -> GDataEntry */
|
GHashTable *entries; /* gchar *entry_id -> GDataEntry */
|
||||||
GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
|
GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
|
||||||
GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */
|
GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */
|
||||||
GHashTable *monitors;
|
GHashTable *monitors;
|
||||||
GList *dir_collisions;
|
GList *dir_collisions;
|
||||||
|
GList *shared_drives;
|
||||||
GRecMutex mutex; /* guards cache */
|
GRecMutex mutex; /* guards cache */
|
||||||
GoaClient *client;
|
GoaClient *client;
|
||||||
gchar *account_identity;
|
gchar *account_identity;
|
||||||
|
@ -79,14 +84,16 @@ G_DEFINE_TYPE(GVfsBackendGoogle, g_vfs_backend_google, G_VFS_TYPE_BACKEND)
|
||||||
|
|
||||||
#define CONTENT_TYPE_PREFIX_GOOGLE "application/vnd.google-apps"
|
#define CONTENT_TYPE_PREFIX_GOOGLE "application/vnd.google-apps"
|
||||||
|
|
||||||
#define MAX_RESULTS 50
|
|
||||||
|
|
||||||
#define REBUILD_ENTRIES_TIMEOUT 60 /* s */
|
#define REBUILD_ENTRIES_TIMEOUT 60 /* s */
|
||||||
|
|
||||||
#define URI_PREFIX "https://www.googleapis.com/drive/v2/files/"
|
#define URI_PREFIX "https://www.googleapis.com/drive/v2/files/"
|
||||||
|
|
||||||
#define SOURCE_ID_PROPERTY_KEY "GVfsSourceID"
|
#define SOURCE_ID_PROPERTY_KEY "GVfsSourceID"
|
||||||
#define PARENT_ID_PROPERTY_KEY "GVfsParentID"
|
#define PARENT_ID_PROPERTY_KEY "GVfsParentID"
|
||||||
|
|
||||||
|
#define ROOT_ID "GVfsRoot"
|
||||||
|
#define SHARED_WITH_ME_ID "GVfsSharedWithMe"
|
||||||
|
#define SHARED_DRIVES_ID "GVfsSharedDrives"
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -441,6 +448,12 @@ is_owner (GVfsBackendGoogle *self, GDataEntry *entry)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_shared_with_me (GDataEntry *entry)
|
||||||
|
{
|
||||||
|
return gdata_documents_entry_get_shared_with_me_date (GDATA_DOCUMENTS_ENTRY (entry)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static const gchar *
|
static const gchar *
|
||||||
|
@ -717,6 +730,27 @@ insert_entry (GVfsBackendGoogle *self,
|
||||||
insert_entry_full (self, entry, TRUE);
|
insert_entry_full (self, entry, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_custom_entry (GVfsBackendGoogle *self,
|
||||||
|
GDataEntry *entry,
|
||||||
|
const gchar *parent_id)
|
||||||
|
{
|
||||||
|
DirEntriesKey *k;
|
||||||
|
const gchar *id;
|
||||||
|
const gchar *title;
|
||||||
|
|
||||||
|
id = gdata_entry_get_id (entry);
|
||||||
|
title = gdata_entry_get_title (entry);
|
||||||
|
|
||||||
|
g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (entry));
|
||||||
|
|
||||||
|
k = dir_entries_key_new (id, parent_id);
|
||||||
|
g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
|
||||||
|
|
||||||
|
k = dir_entries_key_new (title, parent_id);
|
||||||
|
g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_entry_full (GVfsBackendGoogle *self,
|
remove_entry_full (GVfsBackendGoogle *self,
|
||||||
GDataEntry *entry,
|
GDataEntry *entry,
|
||||||
|
@ -733,6 +767,9 @@ remove_entry_full (GVfsBackendGoogle *self,
|
||||||
|
|
||||||
g_hash_table_remove (self->entries, id);
|
g_hash_table_remove (self->entries, id);
|
||||||
|
|
||||||
|
if (is_shared_with_me (entry))
|
||||||
|
g_hash_table_remove (self->dir_timestamps, SHARED_WITH_ME_ID);
|
||||||
|
|
||||||
parent_ids = get_parent_ids (self, entry);
|
parent_ids = get_parent_ids (self, entry);
|
||||||
for (ll = parent_ids; ll != NULL; ll = ll->next)
|
for (ll = parent_ids; ll != NULL; ll = ll->next)
|
||||||
{
|
{
|
||||||
|
@ -875,6 +912,9 @@ is_entry_valid (GDataEntry *entry)
|
||||||
gint64 *timestamp;
|
gint64 *timestamp;
|
||||||
|
|
||||||
timestamp = g_object_get_data (G_OBJECT (entry), "timestamp");
|
timestamp = g_object_get_data (G_OBJECT (entry), "timestamp");
|
||||||
|
if (timestamp == NULL)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
|
return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,6 +923,9 @@ is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent)
|
||||||
{
|
{
|
||||||
gint64 *timestamp;
|
gint64 *timestamp;
|
||||||
|
|
||||||
|
if (parent == self->root)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent));
|
timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent));
|
||||||
if (timestamp != NULL)
|
if (timestamp != NULL)
|
||||||
return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
|
return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
|
||||||
|
@ -890,6 +933,48 @@ is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rebuild_shared_drives_dir (GVfsBackendGoogle *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
|
||||||
|
{
|
||||||
|
GDataAuthorizationDomain *auth_domain;
|
||||||
|
GList *l;
|
||||||
|
gint64 *timestamp;
|
||||||
|
|
||||||
|
auth_domain = gdata_documents_service_get_primary_authorization_domain ();
|
||||||
|
|
||||||
|
remove_dir (self, self->shared_drives_dir);
|
||||||
|
|
||||||
|
for (l = self->shared_drives; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
GDataDocumentsDrive *drive = GDATA_DOCUMENTS_DRIVE (l->data);
|
||||||
|
GDataEntry *entry = NULL;
|
||||||
|
|
||||||
|
entry = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
|
||||||
|
auth_domain,
|
||||||
|
gdata_entry_get_id (GDATA_ENTRY (drive)),
|
||||||
|
NULL,
|
||||||
|
GDATA_TYPE_DOCUMENTS_FOLDER,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
if (entry == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Replace "My Drive" title by the real name of the Drive. */
|
||||||
|
gdata_entry_set_title (entry, gdata_documents_drive_get_name (drive));
|
||||||
|
|
||||||
|
insert_custom_entry (self, entry, SHARED_DRIVES_ID);
|
||||||
|
|
||||||
|
g_object_unref (entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp = g_new (gint64, 1);
|
||||||
|
*timestamp = g_get_real_time ();
|
||||||
|
g_hash_table_insert (self->dir_timestamps, SHARED_DRIVES_ID, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rebuild_dir (GVfsBackendGoogle *self,
|
rebuild_dir (GVfsBackendGoogle *self,
|
||||||
GDataEntry *parent,
|
GDataEntry *parent,
|
||||||
|
@ -902,11 +987,20 @@ rebuild_dir (GVfsBackendGoogle *self,
|
||||||
gchar *search;
|
gchar *search;
|
||||||
gchar *parent_id;
|
gchar *parent_id;
|
||||||
|
|
||||||
|
if (parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
rebuild_shared_drives_dir (self, cancellable, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
||||||
parent_id = g_strdup (gdata_entry_get_id (parent));
|
parent_id = g_strdup (gdata_entry_get_id (parent));
|
||||||
|
|
||||||
search = g_strdup_printf ("'%s' in parents", parent_id);
|
if (parent == self->shared_with_me_dir)
|
||||||
query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
|
search = g_strdup ("sharedWithMe");
|
||||||
|
else
|
||||||
|
search = g_strdup_printf ("'%s' in parents", parent_id);
|
||||||
|
query = gdata_documents_query_new_with_limits (search, 1, G_MAXUINT);
|
||||||
gdata_documents_query_set_show_folders (query, TRUE);
|
gdata_documents_query_set_show_folders (query, TRUE);
|
||||||
g_free (search);
|
g_free (search);
|
||||||
|
|
||||||
|
@ -972,10 +1066,16 @@ resolve_child (GVfsBackendGoogle *self,
|
||||||
GDataEntry *entry;
|
GDataEntry *entry;
|
||||||
const gchar *parent_id;
|
const gchar *parent_id;
|
||||||
GError *local_error = NULL;
|
GError *local_error = NULL;
|
||||||
|
gboolean is_shared_with_me_dir = (parent == self->shared_with_me_dir);
|
||||||
|
|
||||||
parent_id = gdata_entry_get_id (parent);
|
parent_id = gdata_entry_get_id (parent);
|
||||||
k = dir_entries_key_new (basename, parent_id);
|
k = dir_entries_key_new (basename, parent_id);
|
||||||
entry = g_hash_table_lookup (self->dir_entries, k);
|
|
||||||
|
if (is_shared_with_me_dir)
|
||||||
|
entry = g_hash_table_lookup (self->entries, basename);
|
||||||
|
else
|
||||||
|
entry = g_hash_table_lookup (self->dir_entries, k);
|
||||||
|
|
||||||
if ((entry == NULL && !is_dir_listing_valid (self, parent)) ||
|
if ((entry == NULL && !is_dir_listing_valid (self, parent)) ||
|
||||||
(entry != NULL && !is_entry_valid (entry)))
|
(entry != NULL && !is_entry_valid (entry)))
|
||||||
{
|
{
|
||||||
|
@ -986,7 +1086,10 @@ resolve_child (GVfsBackendGoogle *self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = g_hash_table_lookup (self->dir_entries, k);
|
if (is_shared_with_me_dir)
|
||||||
|
entry = g_hash_table_lookup (self->entries, basename);
|
||||||
|
else
|
||||||
|
entry = g_hash_table_lookup (self->dir_entries, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
|
@ -1036,8 +1139,26 @@ resolve (GVfsBackendGoogle *self,
|
||||||
ret_val = resolve_child (self, parent, basename, cancellable, &local_error);
|
ret_val = resolve_child (self, parent, basename, cancellable, &local_error);
|
||||||
if (ret_val == NULL)
|
if (ret_val == NULL)
|
||||||
{
|
{
|
||||||
g_propagate_error (error, local_error);
|
/* This fallback provides volatile entries for URIs which was used
|
||||||
goto out;
|
* before My Drive folder was added in the root. */
|
||||||
|
if (parent == self->root)
|
||||||
|
{
|
||||||
|
g_clear_error (&local_error);
|
||||||
|
ret_val = resolve_child (self, self->home, basename, cancellable, &local_error);
|
||||||
|
if (ret_val != NULL && out_path != NULL)
|
||||||
|
{
|
||||||
|
gchar *tmp;
|
||||||
|
tmp = g_build_path ("/", *out_path, gdata_entry_get_id (self->home), NULL);
|
||||||
|
g_free (*out_path);
|
||||||
|
*out_path = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_val == NULL)
|
||||||
|
{
|
||||||
|
g_propagate_error (error, local_error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_path != NULL)
|
if (out_path != NULL)
|
||||||
|
@ -1213,6 +1334,10 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
gint64 ctime;
|
gint64 ctime;
|
||||||
gint64 mtime;
|
gint64 mtime;
|
||||||
gsize i;
|
gsize i;
|
||||||
|
gboolean is_shared_with_me_dir = (entry == self->shared_with_me_dir);
|
||||||
|
gboolean is_home = (entry == self->home);
|
||||||
|
gboolean is_shared_drives_dir = (entry == self->shared_drives_dir);
|
||||||
|
gboolean can_edit;
|
||||||
|
|
||||||
if (GDATA_IS_DOCUMENTS_FOLDER (entry))
|
if (GDATA_IS_DOCUMENTS_FOLDER (entry))
|
||||||
is_folder = TRUE;
|
is_folder = TRUE;
|
||||||
|
@ -1226,7 +1351,11 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
symlink_name = g_path_get_basename (filename);
|
symlink_name = g_path_get_basename (filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, !is_root);
|
/* TODO: It is not always possible to rename, delete, or list children.
|
||||||
|
* However, the proper implementation of gdata_documents_entry_can_rename/
|
||||||
|
* _delete/_list_children would require port to Google Drive API v3. */
|
||||||
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME,
|
||||||
|
!is_root && !is_home && !is_shared_with_me_dir && !is_shared_drives_dir);
|
||||||
|
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder);
|
||||||
|
|
||||||
|
@ -1234,7 +1363,13 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE, is_symlink);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE, is_symlink);
|
||||||
|
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, !is_root);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
|
||||||
|
!is_root && !is_home && !is_shared_with_me_dir && !is_shared_drives_dir);
|
||||||
|
|
||||||
|
can_edit = gdata_documents_entry_can_edit (GDATA_DOCUMENTS_ENTRY (entry));
|
||||||
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
|
||||||
|
!is_root && !is_shared_with_me_dir && !is_shared_drives_dir && can_edit);
|
||||||
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
|
||||||
|
|
||||||
if (is_folder)
|
if (is_folder)
|
||||||
{
|
{
|
||||||
|
@ -1286,10 +1421,28 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
g_file_info_set_content_type (info, content_type);
|
g_file_info_set_content_type (info, content_type);
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, content_type);
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, content_type);
|
||||||
|
|
||||||
icon = g_content_type_get_icon (content_type);
|
if (is_home)
|
||||||
g_file_info_set_icon (info, icon);
|
{
|
||||||
|
icon = g_themed_icon_new_with_default_fallbacks ("user-home");
|
||||||
|
symbolic_icon = g_themed_icon_new_with_default_fallbacks ("user-home-symbolic");
|
||||||
|
}
|
||||||
|
else if (is_shared_with_me_dir)
|
||||||
|
{
|
||||||
|
icon = g_themed_icon_new_with_default_fallbacks ("folder-publicshare");
|
||||||
|
symbolic_icon = g_themed_icon_new_with_default_fallbacks ("folder-publicshare-symbolic");
|
||||||
|
}
|
||||||
|
else if (is_shared_drives_dir)
|
||||||
|
{
|
||||||
|
icon = g_themed_icon_new_with_default_fallbacks ("folder-remote");
|
||||||
|
symbolic_icon = g_themed_icon_new_with_default_fallbacks ("folder-remote-symbolic");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
icon = g_content_type_get_icon (content_type);
|
||||||
|
symbolic_icon = g_content_type_get_symbolic_icon (content_type);
|
||||||
|
}
|
||||||
|
|
||||||
symbolic_icon = g_content_type_get_symbolic_icon (content_type);
|
g_file_info_set_icon (info, icon);
|
||||||
g_file_info_set_symbolic_icon (info, symbolic_icon);
|
g_file_info_set_symbolic_icon (info, symbolic_icon);
|
||||||
|
|
||||||
g_object_unref (icon);
|
g_object_unref (icon);
|
||||||
|
@ -1298,13 +1451,12 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
|
|
||||||
g_file_info_set_file_type (info, file_type);
|
g_file_info_set_file_type (info, file_type);
|
||||||
|
|
||||||
if (is_root)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
id = gdata_entry_get_id (entry);
|
id = gdata_entry_get_id (entry);
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, id);
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, id);
|
||||||
|
|
||||||
if (is_symlink)
|
if (is_root)
|
||||||
|
name = "/";
|
||||||
|
else if (is_symlink)
|
||||||
name = symlink_name;
|
name = symlink_name;
|
||||||
else
|
else
|
||||||
name = id;
|
name = id;
|
||||||
|
@ -1315,6 +1467,9 @@ build_file_info (GVfsBackendGoogle *self,
|
||||||
g_file_info_set_display_name (info, title);
|
g_file_info_set_display_name (info, title);
|
||||||
g_file_info_set_edit_name (info, title);
|
g_file_info_set_edit_name (info, title);
|
||||||
|
|
||||||
|
if (is_root || is_home || is_shared_with_me_dir || is_shared_drives_dir)
|
||||||
|
goto out;
|
||||||
|
|
||||||
copy_name = generate_copy_name (self, entry, entry_path);
|
copy_name = generate_copy_name (self, entry, entry_path);
|
||||||
|
|
||||||
/* Sanitize copy-name by replacing slashes with dashes. This is
|
/* Sanitize copy-name by replacing slashes with dashes. This is
|
||||||
|
@ -1461,6 +1616,14 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source_entry == self->root || source_parent == self->root || source_parent == self->shared_drives_dir ||
|
||||||
|
destination_parent == self->root || destination_parent == self->shared_with_me_dir ||
|
||||||
|
destination_parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
id = gdata_entry_get_id (source_entry);
|
id = gdata_entry_get_id (source_entry);
|
||||||
title = gdata_entry_get_title (source_entry);
|
title = gdata_entry_get_title (source_entry);
|
||||||
source_parent_id = gdata_entry_get_id (source_parent);
|
source_parent_id = gdata_entry_get_id (source_parent);
|
||||||
|
@ -1875,6 +2038,14 @@ g_vfs_backend_google_move (GVfsBackend *_self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source_entry == self->root || source_parent == self->root || source_parent == self->shared_drives_dir ||
|
||||||
|
destination_parent == self->root || destination_parent == self->shared_with_me_dir ||
|
||||||
|
destination_parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
source_id = gdata_entry_get_id (source_entry);
|
source_id = gdata_entry_get_id (source_entry);
|
||||||
source_parent_id = gdata_entry_get_id (source_parent);
|
source_parent_id = gdata_entry_get_id (source_parent);
|
||||||
destination_parent_id = gdata_entry_get_id (destination_parent);
|
destination_parent_id = gdata_entry_get_id (destination_parent);
|
||||||
|
@ -2288,7 +2459,18 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
|
||||||
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
||||||
id = g_strdup (gdata_entry_get_id (entry));
|
id = g_strdup (gdata_entry_get_id (entry));
|
||||||
|
|
||||||
if (GDATA_IS_DOCUMENTS_FOLDER (entry))
|
parent = resolve_dir (self, filename, cancellable, NULL, NULL, &error);
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||||
|
g_error_free (error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The G_IO_ERROR_NOT_EMPTY error is not intentionally returned for folders in
|
||||||
|
* Shared with me folder, because the recursive delete would not work, or could
|
||||||
|
* really remove the files from the original folder also for the owner... */
|
||||||
|
if (GDATA_IS_DOCUMENTS_FOLDER (entry) && parent != self->shared_with_me_dir)
|
||||||
{
|
{
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
DirEntriesKey *key;
|
DirEntriesKey *key;
|
||||||
|
@ -2318,17 +2500,10 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = resolve_dir (self, filename, cancellable, NULL, NULL, &error);
|
|
||||||
if (error != NULL)
|
|
||||||
{
|
|
||||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
|
||||||
g_error_free (error);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug (" entry path: %s\n", entry_path);
|
g_debug (" entry path: %s\n", entry_path);
|
||||||
|
|
||||||
if (entry == self->root)
|
if (entry == self->root || entry == self->home || entry == self->shared_with_me_dir ||
|
||||||
|
entry == self->shared_drives_dir || parent == self->shared_drives_dir)
|
||||||
{
|
{
|
||||||
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2342,7 +2517,45 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
|
||||||
|
|
||||||
parent_ids = get_parent_ids (self, entry);
|
parent_ids = get_parent_ids (self, entry);
|
||||||
parent_ids_len = g_list_length (parent_ids);
|
parent_ids_len = g_list_length (parent_ids);
|
||||||
if (parent_ids_len > 1 || !is_owner (self, GDATA_ENTRY (entry)))
|
|
||||||
|
/* The files in Shared with me folder doesn't have a parent and also we don't
|
||||||
|
* have enough permissions to physically delete them. But they can be removed
|
||||||
|
* by removal of our permissions... */
|
||||||
|
if (parent == self->shared_with_me_dir)
|
||||||
|
{
|
||||||
|
GDataFeed *acl_feed;
|
||||||
|
|
||||||
|
acl_feed = gdata_access_handler_get_rules (GDATA_ACCESS_HANDLER (entry),
|
||||||
|
GDATA_SERVICE (self->service),
|
||||||
|
cancellable,
|
||||||
|
NULL, NULL, &error);
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
GDataGoaAuthorizer *goa_authorizer;
|
||||||
|
GoaAccount *account;
|
||||||
|
const gchar *account_identity;
|
||||||
|
GDataAuthorizationDomain *auth_domain;
|
||||||
|
GList *entries;
|
||||||
|
|
||||||
|
goa_authorizer = GDATA_GOA_AUTHORIZER (gdata_service_get_authorizer (GDATA_SERVICE (self->service)));
|
||||||
|
account = goa_object_peek_account (gdata_goa_authorizer_get_goa_object (goa_authorizer));
|
||||||
|
account_identity = goa_account_get_identity (account);
|
||||||
|
auth_domain = gdata_documents_service_get_primary_authorization_domain ();
|
||||||
|
|
||||||
|
for (entries = gdata_feed_get_entries (acl_feed); entries != NULL; entries = entries->next)
|
||||||
|
{
|
||||||
|
const gchar *scope_value = NULL;
|
||||||
|
GDataAccessRule *rule = GDATA_ACCESS_RULE (entries->data);
|
||||||
|
|
||||||
|
gdata_access_rule_get_scope (rule, NULL, &scope_value);
|
||||||
|
if (g_strcmp0 (scope_value, account_identity) == 0)
|
||||||
|
gdata_service_delete_entry (GDATA_SERVICE (self->service), auth_domain, GDATA_ENTRY (rule), NULL, &error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (acl_feed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parent_ids_len > 1 || !is_owner (self, GDATA_ENTRY (entry)))
|
||||||
{
|
{
|
||||||
/* gdata_documents_service_remove_entry_from_folder () returns the
|
/* gdata_documents_service_remove_entry_from_folder () returns the
|
||||||
* updated entry variable provided as argument with an increased ref.
|
* updated entry variable provided as argument with an increased ref.
|
||||||
|
@ -2400,10 +2613,12 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self,
|
||||||
GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self);
|
GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self);
|
||||||
GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
|
GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
|
||||||
GDataEntry *entry;
|
GDataEntry *entry;
|
||||||
|
GDataEntry *child;
|
||||||
GError *error;
|
GError *error;
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
char *parent_path;
|
char *parent_path;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
|
gboolean is_shared_with_me_dir;
|
||||||
|
|
||||||
g_rec_mutex_lock (&self->mutex);
|
g_rec_mutex_lock (&self->mutex);
|
||||||
g_debug ("+ enumerate: %s\n", filename);
|
g_debug ("+ enumerate: %s\n", filename);
|
||||||
|
@ -2439,18 +2654,20 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self,
|
||||||
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
||||||
id = g_strdup (gdata_entry_get_id (entry));
|
id = g_strdup (gdata_entry_get_id (entry));
|
||||||
|
|
||||||
|
is_shared_with_me_dir = (entry == self->shared_with_me_dir);
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, self->entries);
|
g_hash_table_iter_init (&iter, self->entries);
|
||||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &child))
|
||||||
{
|
{
|
||||||
DirEntriesKey *k;
|
DirEntriesKey *k;
|
||||||
GDataEntry *child;
|
|
||||||
gchar *child_id;
|
gchar *child_id;
|
||||||
|
|
||||||
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
/* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
|
||||||
child_id = g_strdup (gdata_entry_get_id (entry));
|
child_id = g_strdup (gdata_entry_get_id (child));
|
||||||
|
|
||||||
k = dir_entries_key_new (child_id, id);
|
k = dir_entries_key_new (child_id, id);
|
||||||
if ((child = g_hash_table_lookup (self->dir_entries, k)) != NULL)
|
if ((is_shared_with_me_dir && is_shared_with_me (child)) ||
|
||||||
|
(!is_shared_with_me_dir && g_hash_table_lookup (self->dir_entries, k) != NULL))
|
||||||
{
|
{
|
||||||
GFileInfo *info;
|
GFileInfo *info;
|
||||||
gchar *entry_path;
|
gchar *entry_path;
|
||||||
|
@ -2468,7 +2685,7 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self,
|
||||||
info = g_file_info_new ();
|
info = g_file_info_new ();
|
||||||
entry_path = g_build_path ("/", parent_path, child_id, NULL);
|
entry_path = g_build_path ("/", parent_path, child_id, NULL);
|
||||||
child_filename = g_build_filename (filename, child_id, NULL);
|
child_filename = g_build_filename (filename, child_id, NULL);
|
||||||
build_file_info (self, entry, flags, info, matcher, child_filename, entry_path, NULL);
|
build_file_info (self, child, flags, info, matcher, child_filename, entry_path, NULL);
|
||||||
g_vfs_job_enumerate_add_info (job, info);
|
g_vfs_job_enumerate_add_info (job, info);
|
||||||
g_object_unref (info);
|
g_object_unref (info);
|
||||||
g_free (entry_path);
|
g_free (entry_path);
|
||||||
|
@ -2619,6 +2836,48 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self,
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static GList *
|
||||||
|
query_shared_drives (GVfsBackendGoogle *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GDataDocumentsDriveQuery *query;
|
||||||
|
GList *shared_drives = NULL;
|
||||||
|
|
||||||
|
query = gdata_documents_drive_query_new (NULL);
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
GDataDocumentsFeed *feed;
|
||||||
|
GList *entries;
|
||||||
|
|
||||||
|
feed = gdata_documents_service_query_drives (self->service,
|
||||||
|
query,
|
||||||
|
cancellable,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
error);
|
||||||
|
if (feed == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
entries = gdata_feed_get_entries (GDATA_FEED (feed));
|
||||||
|
if (entries == NULL)
|
||||||
|
{
|
||||||
|
g_object_unref (feed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_drives = g_list_concat (shared_drives,
|
||||||
|
g_list_copy_deep (entries, (GCopyFunc) g_object_ref, NULL));
|
||||||
|
|
||||||
|
gdata_query_next_page (GDATA_QUERY (query));
|
||||||
|
g_object_unref (feed);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&query);
|
||||||
|
|
||||||
|
return shared_drives;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_vfs_backend_google_mount (GVfsBackend *_self,
|
g_vfs_backend_google_mount (GVfsBackend *_self,
|
||||||
GVfsJobMount *job,
|
GVfsJobMount *job,
|
||||||
|
@ -2687,8 +2946,11 @@ g_vfs_backend_google_mount (GVfsBackend *_self,
|
||||||
|
|
||||||
auth_domain = gdata_documents_service_get_primary_authorization_domain ();
|
auth_domain = gdata_documents_service_get_primary_authorization_domain ();
|
||||||
|
|
||||||
|
self->root = GDATA_ENTRY (gdata_documents_folder_new (ROOT_ID));
|
||||||
|
gdata_entry_set_title (self->root, self->account_identity);
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
self->root = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
|
self->home = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
|
||||||
auth_domain,
|
auth_domain,
|
||||||
"root",
|
"root",
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -2702,6 +2964,32 @@ g_vfs_backend_google_mount (GVfsBackend *_self,
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
insert_custom_entry (self, self->home, ROOT_ID);
|
||||||
|
|
||||||
|
self->shared_with_me_dir = GDATA_ENTRY (gdata_documents_folder_new (SHARED_WITH_ME_ID));
|
||||||
|
/* Translators: This is the "Shared with me" folder on https://drive.google.com. */
|
||||||
|
gdata_entry_set_title (self->shared_with_me_dir, _("Shared with me"));
|
||||||
|
insert_custom_entry (self, self->shared_with_me_dir, ROOT_ID);
|
||||||
|
|
||||||
|
self->shared_drives = query_shared_drives (self, cancellable, &error);
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
sanitize_error (&error);
|
||||||
|
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||||
|
g_error_free (error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->shared_drives)
|
||||||
|
{
|
||||||
|
self->shared_drives_dir = GDATA_ENTRY (gdata_documents_folder_new (SHARED_DRIVES_ID));
|
||||||
|
/* Translators: This is the "Shared drives" folder on https://drive.google.com. */
|
||||||
|
gdata_entry_set_title (self->shared_drives_dir, _("Shared drives"));
|
||||||
|
insert_custom_entry (self, self->shared_drives_dir, ROOT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Make it work with GOA volume monitor resp. shadow mounts. */
|
||||||
|
g_vfs_backend_set_default_location (_self, gdata_entry_get_id (self->home));
|
||||||
|
|
||||||
g_vfs_backend_set_mount_spec (_self, spec);
|
g_vfs_backend_set_mount_spec (_self, spec);
|
||||||
g_vfs_backend_set_display_name (_self, self->account_identity);
|
g_vfs_backend_set_display_name (_self, self->account_identity);
|
||||||
|
@ -2772,11 +3060,16 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
||||||
gchar *entry_path = NULL;
|
gchar *entry_path = NULL;
|
||||||
gchar *parent_path = NULL;
|
gchar *parent_path = NULL;
|
||||||
gchar *local_file_title = NULL;
|
gchar *local_file_title = NULL;
|
||||||
goffset size;
|
|
||||||
|
|
||||||
g_rec_mutex_lock (&self->mutex);
|
g_rec_mutex_lock (&self->mutex);
|
||||||
g_debug ("+ push: %s -> %s, %d\n", local_path, destination, flags);
|
g_debug ("+ push: %s -> %s, %d\n", local_path, destination, flags);
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & G_FILE_COPY_BACKUP)
|
if (flags & G_FILE_COPY_BACKUP)
|
||||||
{
|
{
|
||||||
/* Return G_IO_ERROR_NOT_SUPPORTED instead of
|
/* Return G_IO_ERROR_NOT_SUPPORTED instead of
|
||||||
|
@ -2793,7 +3086,8 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
||||||
info = g_file_query_info (local_file,
|
info = g_file_query_info (local_file,
|
||||||
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
|
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
|
||||||
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME","
|
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME","
|
||||||
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
G_FILE_ATTRIBUTE_STANDARD_TYPE","
|
||||||
|
G_FILE_ATTRIBUTE_STANDARD_SIZE,
|
||||||
G_FILE_QUERY_INFO_NONE,
|
G_FILE_QUERY_INFO_NONE,
|
||||||
cancellable,
|
cancellable,
|
||||||
&error);
|
&error);
|
||||||
|
@ -2815,6 +3109,12 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (destination_parent == self->root || destination_parent == self->shared_with_me_dir || destination_parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL);
|
existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL);
|
||||||
if (existing_entry != NULL)
|
if (existing_entry != NULL)
|
||||||
{
|
{
|
||||||
|
@ -2969,11 +3269,14 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
||||||
}
|
}
|
||||||
|
|
||||||
error = NULL;
|
error = NULL;
|
||||||
g_output_stream_splice (G_OUTPUT_STREAM (ostream),
|
gvfs_output_stream_splice (G_OUTPUT_STREAM (ostream),
|
||||||
G_INPUT_STREAM (istream),
|
G_INPUT_STREAM (istream),
|
||||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||||
cancellable,
|
g_file_info_get_size (info),
|
||||||
&error);
|
progress_callback,
|
||||||
|
progress_callback_data,
|
||||||
|
cancellable,
|
||||||
|
&error);
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
{
|
{
|
||||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||||
|
@ -3012,8 +3315,6 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size = gdata_documents_entry_get_file_size (GDATA_DOCUMENTS_ENTRY (new_document));
|
|
||||||
g_vfs_job_progress_callback (size, size, job);
|
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -3089,6 +3390,7 @@ g_vfs_backend_google_query_fs_info (GVfsBackend *_self,
|
||||||
type = g_mount_spec_get_type (spec);
|
type = g_mount_spec_get_type (spec);
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, type);
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, type);
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
||||||
g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_FREE) ||
|
g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_FREE) ||
|
||||||
|
@ -3441,6 +3743,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self,
|
||||||
GDataAuthorizationDomain *auth_domain;
|
GDataAuthorizationDomain *auth_domain;
|
||||||
GDataEntry *entry;
|
GDataEntry *entry;
|
||||||
GDataEntry *new_entry = NULL;
|
GDataEntry *new_entry = NULL;
|
||||||
|
GDataEntry *parent;
|
||||||
GError *error;
|
GError *error;
|
||||||
gchar *entry_path = NULL;
|
gchar *entry_path = NULL;
|
||||||
|
|
||||||
|
@ -3458,7 +3761,15 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self,
|
||||||
|
|
||||||
g_debug (" entry path: %s\n", entry_path);
|
g_debug (" entry path: %s\n", entry_path);
|
||||||
|
|
||||||
if (entry == self->root)
|
parent = resolve_dir (self, filename, cancellable, NULL, NULL, &error);
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||||
|
g_error_free (error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == self->root || entry == self->home || entry == self->shared_with_me_dir || parent == self->shared_drives_dir)
|
||||||
{
|
{
|
||||||
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3536,6 +3847,12 @@ g_vfs_backend_google_create (GVfsBackend *_self,
|
||||||
|
|
||||||
g_debug (" parent path: %s\n", parent_path);
|
g_debug (" parent path: %s\n", parent_path);
|
||||||
|
|
||||||
|
if (parent == self->root || parent == self->shared_with_me_dir || parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
|
existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
|
||||||
if (existing_entry != NULL)
|
if (existing_entry != NULL)
|
||||||
{
|
{
|
||||||
|
@ -3645,6 +3962,12 @@ g_vfs_backend_google_replace (GVfsBackend *_self,
|
||||||
|
|
||||||
g_debug (" parent path: %s\n", parent_path);
|
g_debug (" parent path: %s\n", parent_path);
|
||||||
|
|
||||||
|
if (parent == self->root || parent == self->shared_with_me_dir || parent == self->shared_drives_dir)
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
|
existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
|
||||||
if (existing_entry != NULL)
|
if (existing_entry != NULL)
|
||||||
{
|
{
|
||||||
|
@ -3875,6 +4198,10 @@ g_vfs_backend_google_dispose (GObject *_self)
|
||||||
|
|
||||||
g_clear_object (&self->service);
|
g_clear_object (&self->service);
|
||||||
g_clear_object (&self->root);
|
g_clear_object (&self->root);
|
||||||
|
g_clear_object (&self->home);
|
||||||
|
g_clear_object (&self->shared_with_me_dir);
|
||||||
|
g_clear_object (&self->shared_drives_dir);
|
||||||
|
g_clear_list (&self->shared_drives, g_object_unref);
|
||||||
g_clear_object (&self->client);
|
g_clear_object (&self->client);
|
||||||
g_clear_pointer (&self->entries, g_hash_table_unref);
|
g_clear_pointer (&self->entries, g_hash_table_unref);
|
||||||
g_clear_pointer (&self->dir_entries, g_hash_table_unref);
|
g_clear_pointer (&self->dir_entries, g_hash_table_unref);
|
||||||
|
|
|
@ -3243,6 +3243,14 @@ do_pull (GVfsBackend *backend,
|
||||||
|
|
||||||
split_filename_with_ignore_prefix (gphoto2_backend, source, &dir, &name);
|
split_filename_with_ignore_prefix (gphoto2_backend, source, &dir, &name);
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (remove_source && !gphoto2_backend->can_delete)
|
if (remove_source && !gphoto2_backend->can_delete)
|
||||||
{
|
{
|
||||||
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
|
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* GIO - GLib Input, Output and Streaming Library
|
/* GIO - GLib Input, Output and Streaming Library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008 Red Hat, Inc.
|
* Copyright (C) 2008 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2021 Igalia S.L.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
#include "gvfsdaemonprotocol.h"
|
#include "gvfsdaemonprotocol.h"
|
||||||
#include "gvfsdaemonutils.h"
|
#include "gvfsdaemonutils.h"
|
||||||
|
|
||||||
static SoupSession *the_session;
|
static SoupSession *the_session = NULL;
|
||||||
|
|
||||||
G_DEFINE_TYPE (GVfsBackendHttp, g_vfs_backend_http, G_VFS_TYPE_BACKEND)
|
G_DEFINE_TYPE (GVfsBackendHttp, g_vfs_backend_http, G_VFS_TYPE_BACKEND)
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ g_vfs_backend_http_finalize (GObject *object)
|
||||||
backend = G_VFS_BACKEND_HTTP (object);
|
backend = G_VFS_BACKEND_HTTP (object);
|
||||||
|
|
||||||
if (backend->mount_base)
|
if (backend->mount_base)
|
||||||
soup_uri_free (backend->mount_base);
|
g_uri_unref (backend->mount_base);
|
||||||
|
|
||||||
g_object_unref (backend->session);
|
g_object_unref (backend->session);
|
||||||
|
|
||||||
|
@ -77,18 +78,89 @@ g_vfs_backend_http_init (GVfsBackendHttp *backend)
|
||||||
{
|
{
|
||||||
g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE);
|
g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE);
|
||||||
|
|
||||||
backend->session = g_object_ref (the_session);
|
/* attempt to use libsoup's default values */
|
||||||
|
backend->session = g_object_ref (http_try_init_session (-1, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
/* public utility functions */
|
/* public utility functions */
|
||||||
|
|
||||||
SoupURI *
|
GUri *
|
||||||
http_backend_get_mount_base (GVfsBackend *backend)
|
http_backend_get_mount_base (GVfsBackend *backend)
|
||||||
{
|
{
|
||||||
return G_VFS_BACKEND_HTTP (backend)->mount_base;
|
return G_VFS_BACKEND_HTTP (backend)->mount_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024)
|
||||||
|
|
||||||
|
/* initializes the session singleton; if max_conns is lower than 0, the
|
||||||
|
* libsoup defaults are used for max-conns and max-conns-per-host, this
|
||||||
|
* is called in the instance constructor, so if they are to be overridden,
|
||||||
|
* all one has to do is make sure to call it with the desired values before
|
||||||
|
* any instance is created (most likely in the class constructor of the
|
||||||
|
* derived class, see dav backend)
|
||||||
|
*/
|
||||||
|
SoupSession *
|
||||||
|
http_try_init_session (gint max_conns, gint max_conns_per_host)
|
||||||
|
{
|
||||||
|
const char *debug;
|
||||||
|
SoupSessionFeature *cookie_jar;
|
||||||
|
|
||||||
|
if (the_session)
|
||||||
|
return the_session;
|
||||||
|
|
||||||
|
/* Initialize the SoupSession, common to all backend instances */
|
||||||
|
if (max_conns < 0)
|
||||||
|
the_session = soup_session_new_with_options ("user-agent",
|
||||||
|
"gvfs/" VERSION, NULL);
|
||||||
|
else
|
||||||
|
the_session = soup_session_new_with_options ("user-agent",
|
||||||
|
"gvfs/" VERSION,
|
||||||
|
"max-conns",
|
||||||
|
max_conns,
|
||||||
|
"max-conns-per-host",
|
||||||
|
max_conns_per_host,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Cookie handling - stored temporarlly in memory, mostly useful for
|
||||||
|
* authentication in WebDAV. */
|
||||||
|
cookie_jar = g_object_new (SOUP_TYPE_COOKIE_JAR, NULL);
|
||||||
|
soup_session_add_feature (the_session, cookie_jar);
|
||||||
|
g_object_unref (cookie_jar);
|
||||||
|
|
||||||
|
/* Send Accept-Language header (see bug 166795) */
|
||||||
|
soup_session_set_accept_language_auto (the_session, TRUE);
|
||||||
|
|
||||||
|
/* Prevent connection timeouts during long operations like COPY. */
|
||||||
|
soup_session_set_timeout (the_session, 0);
|
||||||
|
|
||||||
|
/* Logging */
|
||||||
|
debug = g_getenv ("GVFS_HTTP_DEBUG");
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
SoupLogger *logger;
|
||||||
|
SoupLoggerLogLevel level;
|
||||||
|
|
||||||
|
if (g_ascii_strcasecmp (debug, "all") == 0 ||
|
||||||
|
g_ascii_strcasecmp (debug, "body") == 0)
|
||||||
|
level = SOUP_LOGGER_LOG_BODY;
|
||||||
|
else if (g_ascii_strcasecmp (debug, "header") == 0)
|
||||||
|
level = SOUP_LOGGER_LOG_HEADERS;
|
||||||
|
else
|
||||||
|
level = SOUP_LOGGER_LOG_MINIMAL;
|
||||||
|
|
||||||
|
logger = soup_logger_new (level);
|
||||||
|
g_object_set (G_OBJECT (logger),
|
||||||
|
"max-body-size",
|
||||||
|
DEBUG_MAX_BODY_SIZE,
|
||||||
|
NULL);
|
||||||
|
soup_session_add_feature (the_session, SOUP_SESSION_FEATURE (logger));
|
||||||
|
g_object_unref (logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
return the_session;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
http_path_get_basename (const char *path)
|
http_path_get_basename (const char *path)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +210,7 @@ http_uri_get_basename (const char *uri_str)
|
||||||
|
|
||||||
basename = http_path_get_basename (uri_str);
|
basename = http_path_get_basename (uri_str);
|
||||||
|
|
||||||
decoded = soup_uri_decode (basename);
|
decoded = g_uri_unescape_string (basename, NULL);
|
||||||
g_free (basename);
|
g_free (basename);
|
||||||
|
|
||||||
return decoded;
|
return decoded;
|
||||||
|
@ -149,13 +221,6 @@ http_error_code_from_status (guint status)
|
||||||
{
|
{
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
|
||||||
case SOUP_STATUS_CANT_RESOLVE:
|
|
||||||
case SOUP_STATUS_CANT_RESOLVE_PROXY:
|
|
||||||
return G_IO_ERROR_HOST_NOT_FOUND;
|
|
||||||
|
|
||||||
case SOUP_STATUS_CANCELLED:
|
|
||||||
return G_IO_ERROR_CANCELLED;
|
|
||||||
|
|
||||||
case SOUP_STATUS_UNAUTHORIZED:
|
case SOUP_STATUS_UNAUTHORIZED:
|
||||||
case SOUP_STATUS_PAYMENT_REQUIRED:
|
case SOUP_STATUS_PAYMENT_REQUIRED:
|
||||||
case SOUP_STATUS_FORBIDDEN:
|
case SOUP_STATUS_FORBIDDEN:
|
||||||
|
@ -184,45 +249,27 @@ http_error_code_from_status (guint status)
|
||||||
void
|
void
|
||||||
http_job_failed (GVfsJob *job, SoupMessage *msg)
|
http_job_failed (GVfsJob *job, SoupMessage *msg)
|
||||||
{
|
{
|
||||||
switch (msg->status_code) {
|
switch (soup_message_get_status(msg)) {
|
||||||
|
|
||||||
case SOUP_STATUS_NOT_FOUND:
|
case SOUP_STATUS_NOT_FOUND:
|
||||||
g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||||
msg->reason_phrase);
|
soup_message_get_reason_phrase(msg));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOUP_STATUS_UNAUTHORIZED:
|
case SOUP_STATUS_UNAUTHORIZED:
|
||||||
case SOUP_STATUS_PAYMENT_REQUIRED:
|
case SOUP_STATUS_PAYMENT_REQUIRED:
|
||||||
case SOUP_STATUS_FORBIDDEN:
|
case SOUP_STATUS_FORBIDDEN:
|
||||||
g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
||||||
_("HTTP Client Error: %s"), msg->reason_phrase);
|
_("HTTP Client Error: %s"),
|
||||||
|
soup_message_get_reason_phrase(msg));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
_("HTTP Error: %s"), msg->reason_phrase);
|
_("HTTP Error: %s"),
|
||||||
|
soup_message_get_reason_phrase(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guint
|
|
||||||
http_backend_send_message (GVfsBackend *backend,
|
|
||||||
SoupMessage *msg)
|
|
||||||
{
|
|
||||||
GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
|
|
||||||
|
|
||||||
return soup_session_send_message (op_backend->session, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
http_backend_queue_message (GVfsBackend *backend,
|
|
||||||
SoupMessage *msg,
|
|
||||||
SoupSessionCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
|
|
||||||
|
|
||||||
soup_session_queue_message (op_backend->session, msg,
|
|
||||||
callback, user_data);
|
|
||||||
}
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
/* virtual functions overrides */
|
/* virtual functions overrides */
|
||||||
|
|
||||||
|
@ -235,8 +282,8 @@ try_mount (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
GVfsBackendHttp *op_backend;
|
GVfsBackendHttp *op_backend;
|
||||||
const char *uri_str;
|
const char *uri_str;
|
||||||
char *path;
|
const char *path;
|
||||||
SoupURI *uri;
|
GUri *uri;
|
||||||
GMountSpec *real_mount_spec;
|
GMountSpec *real_mount_spec;
|
||||||
|
|
||||||
op_backend = G_VFS_BACKEND_HTTP (backend);
|
op_backend = G_VFS_BACKEND_HTTP (backend);
|
||||||
|
@ -245,7 +292,7 @@ try_mount (GVfsBackend *backend,
|
||||||
uri_str = g_mount_spec_get (mount_spec, "uri");
|
uri_str = g_mount_spec_get (mount_spec, "uri");
|
||||||
|
|
||||||
if (uri_str)
|
if (uri_str)
|
||||||
uri = soup_uri_new (uri_str);
|
uri = g_uri_parse (uri_str, SOUP_HTTP_URI_FLAGS, NULL);
|
||||||
|
|
||||||
g_debug ("+ try_mount: %s\n", uri_str ? uri_str : "(null)");
|
g_debug ("+ try_mount: %s\n", uri_str ? uri_str : "(null)");
|
||||||
|
|
||||||
|
@ -260,12 +307,11 @@ try_mount (GVfsBackend *backend,
|
||||||
real_mount_spec = g_mount_spec_new ("http");
|
real_mount_spec = g_mount_spec_new ("http");
|
||||||
g_mount_spec_set (real_mount_spec, "uri", uri_str);
|
g_mount_spec_set (real_mount_spec, "uri", uri_str);
|
||||||
|
|
||||||
if (uri->path != NULL)
|
path = g_uri_unescape_string (g_uri_get_path (uri), "/");
|
||||||
|
if (path[0])
|
||||||
{
|
{
|
||||||
path = g_uri_unescape_string (uri->path, "/");
|
|
||||||
g_free (real_mount_spec->mount_prefix);
|
g_free (real_mount_spec->mount_prefix);
|
||||||
real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path);
|
real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path);
|
||||||
g_free (path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_vfs_backend_set_mount_spec (backend, real_mount_spec);
|
g_vfs_backend_set_mount_spec (backend, real_mount_spec);
|
||||||
|
@ -309,7 +355,7 @@ open_for_read_ready (GObject *source_object,
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = g_vfs_http_input_stream_get_message (stream);
|
msg = g_vfs_http_input_stream_get_message (stream);
|
||||||
if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
|
if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
|
||||||
{
|
{
|
||||||
http_job_failed (G_VFS_JOB (job), msg);
|
http_job_failed (G_VFS_JOB (job), msg);
|
||||||
g_object_unref (msg);
|
g_object_unref (msg);
|
||||||
|
@ -330,7 +376,7 @@ try_open_for_read (GVfsBackend *backend,
|
||||||
GVfsJobOpenForRead *job,
|
GVfsJobOpenForRead *job,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
{
|
{
|
||||||
SoupURI *uri;
|
GUri *uri;
|
||||||
|
|
||||||
uri = http_backend_get_mount_base (backend);
|
uri = http_backend_get_mount_base (backend);
|
||||||
http_backend_open_for_read (backend, G_VFS_JOB (job), uri);
|
http_backend_open_for_read (backend, G_VFS_JOB (job), uri);
|
||||||
|
@ -341,7 +387,7 @@ try_open_for_read (GVfsBackend *backend,
|
||||||
void
|
void
|
||||||
http_backend_open_for_read (GVfsBackend *backend,
|
http_backend_open_for_read (GVfsBackend *backend,
|
||||||
GVfsJob *job,
|
GVfsJob *job,
|
||||||
SoupURI *uri)
|
GUri *uri)
|
||||||
{
|
{
|
||||||
GVfsBackendHttp *op_backend;
|
GVfsBackendHttp *op_backend;
|
||||||
GInputStream *stream;
|
GInputStream *stream;
|
||||||
|
@ -507,7 +553,7 @@ file_info_from_message (SoupMessage *msg,
|
||||||
|
|
||||||
/* prefer the filename from the Content-Disposition (rfc2183) header
|
/* prefer the filename from the Content-Disposition (rfc2183) header
|
||||||
if one if present. See bug 551298. */
|
if one if present. See bug 551298. */
|
||||||
if (soup_message_headers_get_content_disposition (msg->response_headers,
|
if (soup_message_headers_get_content_disposition (soup_message_get_response_headers (msg),
|
||||||
NULL, ¶ms))
|
NULL, ¶ms))
|
||||||
{
|
{
|
||||||
const char *name = g_hash_table_lookup (params, "filename");
|
const char *name = g_hash_table_lookup (params, "filename");
|
||||||
|
@ -520,10 +566,10 @@ file_info_from_message (SoupMessage *msg,
|
||||||
|
|
||||||
if (basename == NULL)
|
if (basename == NULL)
|
||||||
{
|
{
|
||||||
const SoupURI *uri;
|
GUri *uri;
|
||||||
|
|
||||||
uri = soup_message_get_uri (msg);
|
uri = soup_message_get_uri (msg);
|
||||||
basename = http_uri_get_basename (uri->path);
|
basename = http_uri_get_basename (g_uri_get_path (uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
g_debug ("basename:%s\n", basename);
|
g_debug ("basename:%s\n", basename);
|
||||||
|
@ -540,12 +586,12 @@ file_info_from_message (SoupMessage *msg,
|
||||||
g_free (basename);
|
g_free (basename);
|
||||||
g_free (ed_name);
|
g_free (ed_name);
|
||||||
|
|
||||||
if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_CONTENT_LENGTH)
|
if (soup_message_headers_get_encoding (soup_message_get_response_headers (msg)) == SOUP_ENCODING_CONTENT_LENGTH)
|
||||||
{
|
{
|
||||||
goffset start, end, length;
|
goffset start, end, length;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
ret = soup_message_headers_get_content_range (msg->response_headers,
|
ret = soup_message_headers_get_content_range (soup_message_get_response_headers (msg),
|
||||||
&start, &end, &length);
|
&start, &end, &length);
|
||||||
if (ret && length != -1)
|
if (ret && length != -1)
|
||||||
{
|
{
|
||||||
|
@ -553,14 +599,14 @@ file_info_from_message (SoupMessage *msg,
|
||||||
}
|
}
|
||||||
else if (!ret)
|
else if (!ret)
|
||||||
{
|
{
|
||||||
length = soup_message_headers_get_content_length (msg->response_headers);
|
length = soup_message_headers_get_content_length (soup_message_get_response_headers (msg));
|
||||||
g_file_info_set_size (info, length);
|
g_file_info_set_size (info, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
|
g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
|
||||||
|
|
||||||
text = soup_message_headers_get_content_type (msg->response_headers, NULL);
|
text = soup_message_headers_get_content_type (soup_message_get_response_headers (msg), NULL);
|
||||||
if (text)
|
if (text)
|
||||||
{
|
{
|
||||||
GIcon *icon;
|
GIcon *icon;
|
||||||
|
@ -578,23 +624,25 @@ file_info_from_message (SoupMessage *msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
text = soup_message_headers_get_one (msg->response_headers,
|
text = soup_message_headers_get_one (soup_message_get_response_headers (msg),
|
||||||
"Last-Modified");
|
"Last-Modified");
|
||||||
if (text)
|
if (text)
|
||||||
{
|
{
|
||||||
SoupDate *sd;
|
GDateTime *gd;
|
||||||
|
|
||||||
sd = soup_date_new_from_string(text);
|
gd = soup_date_time_new_from_http_string (text);
|
||||||
if (sd)
|
if (gd)
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, soup_date_to_time_t (sd));
|
g_file_info_set_attribute_uint64 (info,
|
||||||
|
G_FILE_ATTRIBUTE_TIME_MODIFIED,
|
||||||
|
g_date_time_to_unix (gd));
|
||||||
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
|
||||||
soup_date_free (sd);
|
g_date_time_unref (gd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
text = soup_message_headers_get_one (msg->response_headers,
|
text = soup_message_headers_get_one (soup_message_get_response_headers (msg),
|
||||||
"ETag");
|
"ETag");
|
||||||
if (text)
|
if (text)
|
||||||
{
|
{
|
||||||
|
@ -605,19 +653,25 @@ file_info_from_message (SoupMessage *msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
query_info_ready (SoupSession *session,
|
query_info_ready (GObject *object,
|
||||||
SoupMessage *msg,
|
GAsyncResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GFileAttributeMatcher *matcher;
|
GVfsJobQueryInfo *job = G_VFS_JOB_QUERY_INFO (user_data);
|
||||||
GVfsJobQueryInfo *job;
|
GFileAttributeMatcher *matcher = job->attribute_matcher;
|
||||||
GFileInfo *info;
|
GFileInfo *info = job->file_info;
|
||||||
|
GInputStream *res;
|
||||||
|
GError *error = NULL;
|
||||||
|
SoupMessage *msg = G_VFS_JOB (job)->backend_data;
|
||||||
|
|
||||||
job = G_VFS_JOB_QUERY_INFO (user_data);
|
res = soup_session_send_finish (SOUP_SESSION (object), result, &error);
|
||||||
info = job->file_info;
|
if (!res)
|
||||||
matcher = job->attribute_matcher;
|
{
|
||||||
|
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (! SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
|
if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg)))
|
||||||
{
|
{
|
||||||
http_job_failed (G_VFS_JOB (job), msg);
|
http_job_failed (G_VFS_JOB (job), msg);
|
||||||
return;
|
return;
|
||||||
|
@ -625,10 +679,11 @@ query_info_ready (SoupSession *session,
|
||||||
|
|
||||||
file_info_from_message (msg, info, matcher);
|
file_info_from_message (msg, info, matcher);
|
||||||
|
|
||||||
|
g_object_unref (res);
|
||||||
|
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
try_query_info (GVfsBackend *backend,
|
try_query_info (GVfsBackend *backend,
|
||||||
GVfsJobQueryInfo *job,
|
GVfsJobQueryInfo *job,
|
||||||
|
@ -637,8 +692,9 @@ try_query_info (GVfsBackend *backend,
|
||||||
GFileInfo *info,
|
GFileInfo *info,
|
||||||
GFileAttributeMatcher *attribute_matcher)
|
GFileAttributeMatcher *attribute_matcher)
|
||||||
{
|
{
|
||||||
|
GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
|
||||||
SoupMessage *msg;
|
SoupMessage *msg;
|
||||||
SoupURI *uri;
|
GUri *uri;
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches_only (attribute_matcher,
|
if (g_file_attribute_matcher_matches_only (attribute_matcher,
|
||||||
G_FILE_ATTRIBUTE_THUMBNAIL_PATH))
|
G_FILE_ATTRIBUTE_THUMBNAIL_PATH))
|
||||||
|
@ -650,7 +706,10 @@ try_query_info (GVfsBackend *backend,
|
||||||
uri = http_backend_get_mount_base (backend);
|
uri = http_backend_get_mount_base (backend);
|
||||||
msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
|
msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
|
||||||
|
|
||||||
http_backend_queue_message (backend, msg, query_info_ready, job);
|
g_vfs_job_set_backend_data (G_VFS_JOB (job), msg, NULL);
|
||||||
|
|
||||||
|
soup_session_send_async (op_backend->session, msg, G_PRIORITY_DEFAULT,
|
||||||
|
NULL, query_info_ready, job);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -682,19 +741,14 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "http");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "http");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024)
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
|
g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
|
||||||
{
|
{
|
||||||
const char *debug;
|
|
||||||
SoupSessionFeature *cookie_jar;
|
|
||||||
|
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
GVfsBackendClass *backend_class;
|
GVfsBackendClass *backend_class;
|
||||||
|
|
||||||
|
@ -710,43 +764,4 @@ g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
|
||||||
backend_class->try_query_info = try_query_info;
|
backend_class->try_query_info = try_query_info;
|
||||||
backend_class->try_query_info_on_read = try_query_info_on_read;
|
backend_class->try_query_info_on_read = try_query_info_on_read;
|
||||||
backend_class->try_query_fs_info = try_query_fs_info;
|
backend_class->try_query_fs_info = try_query_fs_info;
|
||||||
|
|
||||||
/* Initialize the SoupSession, common to all backend instances */
|
|
||||||
the_session = soup_session_new_with_options ("user-agent",
|
|
||||||
"gvfs/" VERSION,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_object_set (the_session, "ssl-strict", FALSE, NULL);
|
|
||||||
|
|
||||||
/* Cookie handling - stored temporarlly in memory, mostly useful for
|
|
||||||
* authentication in WebDAV. */
|
|
||||||
cookie_jar = g_object_new (SOUP_TYPE_COOKIE_JAR, NULL);
|
|
||||||
soup_session_add_feature (the_session, cookie_jar);
|
|
||||||
g_object_unref (cookie_jar);
|
|
||||||
|
|
||||||
/* Send Accept-Language header (see bug 166795) */
|
|
||||||
g_object_set (the_session, "accept-language-auto", TRUE, NULL);
|
|
||||||
|
|
||||||
/* Prevent connection timeouts during long operations like COPY. */
|
|
||||||
g_object_set (the_session, "timeout", 0, NULL);
|
|
||||||
|
|
||||||
/* Logging */
|
|
||||||
debug = g_getenv ("GVFS_HTTP_DEBUG");
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
SoupLogger *logger;
|
|
||||||
SoupLoggerLogLevel level;
|
|
||||||
|
|
||||||
if (g_ascii_strcasecmp (debug, "all") == 0 ||
|
|
||||||
g_ascii_strcasecmp (debug, "body") == 0)
|
|
||||||
level = SOUP_LOGGER_LOG_BODY;
|
|
||||||
else if (g_ascii_strcasecmp (debug, "header") == 0)
|
|
||||||
level = SOUP_LOGGER_LOG_HEADERS;
|
|
||||||
else
|
|
||||||
level = SOUP_LOGGER_LOG_MINIMAL;
|
|
||||||
|
|
||||||
logger = soup_logger_new (level, DEBUG_MAX_BODY_SIZE);
|
|
||||||
soup_session_add_feature (the_session, SOUP_SESSION_FEATURE (logger));
|
|
||||||
g_object_unref (logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* GIO - GLib Input, Output and Streaming Library
|
/* GIO - GLib Input, Output and Streaming Library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008 Red Hat, Inc.
|
* Copyright (C) 2008 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2021 Igalia S.L.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -49,7 +50,7 @@ struct _GVfsBackendHttp
|
||||||
{
|
{
|
||||||
GVfsBackend parent_instance;
|
GVfsBackend parent_instance;
|
||||||
|
|
||||||
SoupURI *mount_base;
|
GUri *mount_base;
|
||||||
SoupSession *session;
|
SoupSession *session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,19 +62,14 @@ char * http_path_get_basename (const char *path_str);
|
||||||
|
|
||||||
int http_error_code_from_status (guint status);
|
int http_error_code_from_status (guint status);
|
||||||
|
|
||||||
SoupURI * http_backend_get_mount_base (GVfsBackend *backend);
|
SoupSession * http_try_init_session (gint max_conns,
|
||||||
|
gint max_conns_per_host);
|
||||||
|
|
||||||
guint http_backend_send_message (GVfsBackend *backend,
|
GUri * http_backend_get_mount_base (GVfsBackend *backend);
|
||||||
SoupMessage *msg);
|
|
||||||
|
|
||||||
void http_backend_queue_message (GVfsBackend *backend,
|
|
||||||
SoupMessage *msg,
|
|
||||||
SoupSessionCallback callback,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
void http_backend_open_for_read (GVfsBackend *backend,
|
void http_backend_open_for_read (GVfsBackend *backend,
|
||||||
GVfsJob *job,
|
GVfsJob *job,
|
||||||
SoupURI *uri);
|
GUri *uri);
|
||||||
|
|
||||||
void http_job_failed (GVfsJob *job,
|
void http_job_failed (GVfsJob *job,
|
||||||
SoupMessage *msg);
|
SoupMessage *msg);
|
||||||
|
|
|
@ -390,6 +390,7 @@ do_query_fs_info (GVfsBackend *backend,
|
||||||
|
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "localtest");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "localtest");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
|
||||||
|
|
||||||
file = get_g_file_from_local (filename, G_VFS_JOB (job));
|
file = get_g_file_from_local (filename, G_VFS_JOB (job));
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,18 @@ handle_event (EventData *data, GVfsBackendMtp *backend);
|
||||||
* Storage name helper
|
* Storage name helper
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create_storage_name:
|
||||||
|
*
|
||||||
|
* Returns a unique, printable storage name for a LIBMTP_devicestorage_t
|
||||||
|
* based on its StorageDescription, appending the storage ID if necessary
|
||||||
|
* to make it unique.
|
||||||
|
*
|
||||||
|
* The caller takes ownership of the returned string.
|
||||||
|
* This function never returns NULL strings.
|
||||||
|
*
|
||||||
|
* The passed-in `storage->StorageDescription` may be NULL.
|
||||||
|
*/
|
||||||
static char *create_storage_name (const LIBMTP_devicestorage_t *storage)
|
static char *create_storage_name (const LIBMTP_devicestorage_t *storage)
|
||||||
{
|
{
|
||||||
/* The optional post-fixing of storage's name with ID requires us to
|
/* The optional post-fixing of storage's name with ID requires us to
|
||||||
|
@ -139,9 +151,15 @@ static char *create_storage_name (const LIBMTP_devicestorage_t *storage)
|
||||||
or not. Since this function is called in several places, it is
|
or not. Since this function is called in several places, it is
|
||||||
safest to perform this check here, each time that storage name needs
|
safest to perform this check here, each time that storage name needs
|
||||||
to be created. */
|
to be created. */
|
||||||
|
/* TODO: The returned name is not unique if suffix-adding happens
|
||||||
|
to introduce a collision with another storage's unsuffixed
|
||||||
|
description; unlikely but possible. */
|
||||||
gboolean is_unique = TRUE;
|
gboolean is_unique = TRUE;
|
||||||
const LIBMTP_devicestorage_t *tmp_storage;
|
const LIBMTP_devicestorage_t *tmp_storage;
|
||||||
|
|
||||||
|
/* `storage->StorageDescription` may be NULL, so we ensure to only use
|
||||||
|
functions that can handle this, like `g_strcmp0()`. */
|
||||||
|
|
||||||
/* Forward search for duplicates */
|
/* Forward search for duplicates */
|
||||||
for (tmp_storage = storage->next; tmp_storage != 0; tmp_storage = tmp_storage->next) {
|
for (tmp_storage = storage->next; tmp_storage != 0; tmp_storage = tmp_storage->next) {
|
||||||
if (!g_strcmp0 (storage->StorageDescription, tmp_storage->StorageDescription)) {
|
if (!g_strcmp0 (storage->StorageDescription, tmp_storage->StorageDescription)) {
|
||||||
|
@ -164,7 +182,17 @@ static char *create_storage_name (const LIBMTP_devicestorage_t *storage)
|
||||||
/* If description is unique, we can use it as storage name; otherwise,
|
/* If description is unique, we can use it as storage name; otherwise,
|
||||||
we add storage ID to it */
|
we add storage ID to it */
|
||||||
if (is_unique) {
|
if (is_unique) {
|
||||||
return g_strdup (storage->StorageDescription);
|
/* Never return a NULL string (`g_strdup` returns NULL on NULL).
|
||||||
|
Use the storage ID on empty strings to avoid duplicate entries
|
||||||
|
for devices with multiple storages without description. */
|
||||||
|
if (storage->StorageDescription && strlen (storage->StorageDescription) > 0) {
|
||||||
|
return g_strdup (storage->StorageDescription);
|
||||||
|
} else {
|
||||||
|
/* Translators: This is shown as the name for MTP devices
|
||||||
|
* without StorageDescription.
|
||||||
|
* The %X is the formatted storage ID. */
|
||||||
|
return g_strdup_printf (_("Storage (%X)"), storage->id);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return g_strdup_printf ("%s (%X)", storage->StorageDescription, storage->id);
|
return g_strdup_printf ("%s (%X)", storage->StorageDescription, storage->id);
|
||||||
}
|
}
|
||||||
|
@ -1217,6 +1245,7 @@ get_storage_info (LIBMTP_devicestorage_t *storage, GFileInfo *info) {
|
||||||
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, storage->FreeSpaceInBytes);
|
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, storage->FreeSpaceInBytes);
|
||||||
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, storage->MaxCapacity);
|
g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, storage->MaxCapacity);
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "mtpfs");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "mtpfs");
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, FALSE);
|
||||||
|
|
||||||
g_debug ("(II) get_storage_info done.\n");
|
g_debug ("(II) get_storage_info done.\n");
|
||||||
|
@ -1711,6 +1740,13 @@ do_pull (GVfsBackend *backend,
|
||||||
GFileInfo *info = NULL;
|
GFileInfo *info = NULL;
|
||||||
guint64 mtime;
|
guint64 mtime;
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE)) {
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job),
|
||||||
|
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
CacheEntry *entry = get_cache_entry (G_VFS_BACKEND_MTP (backend), source);
|
CacheEntry *entry = get_cache_entry (G_VFS_BACKEND_MTP (backend), source);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||||||
|
@ -2005,6 +2041,13 @@ do_push (GVfsBackend *backend,
|
||||||
gchar **elements = g_strsplit_set (destination, "/", -1);
|
gchar **elements = g_strsplit_set (destination, "/", -1);
|
||||||
unsigned int ne = g_strv_length (elements);
|
unsigned int ne = g_strv_length (elements);
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE)) {
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job),
|
||||||
|
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (ne < 3) {
|
if (ne < 3) {
|
||||||
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||||||
G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
|
|
@ -868,6 +868,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "network");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "network");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1607,6 +1607,9 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "nfs");
|
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "nfs");
|
||||||
g_file_info_set_attribute_boolean (info,
|
g_file_info_set_attribute_boolean (info,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info,
|
||||||
|
G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW,
|
||||||
|
G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches (matcher,
|
if (g_file_attribute_matcher_matches (matcher,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
||||||
|
|
|
@ -30,7 +30,7 @@ typedef struct {
|
||||||
char *uri;
|
char *uri;
|
||||||
char *display_name;
|
char *display_name;
|
||||||
GFile *file;
|
GFile *file;
|
||||||
time_t modified;
|
GDateTime *modified;
|
||||||
} RecentItem;
|
} RecentItem;
|
||||||
|
|
||||||
struct OPAQUE_TYPE__GVfsBackendRecent
|
struct OPAQUE_TYPE__GVfsBackendRecent
|
||||||
|
@ -326,7 +326,8 @@ recent_backend_add_info (RecentItem *item,
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|
||||||
/* G_FILE_ATTRIBUTE_RECENT_MODIFIED */
|
/* G_FILE_ATTRIBUTE_RECENT_MODIFIED */
|
||||||
g_file_info_set_attribute_int64 (info, "recent::modified", item->modified);
|
g_file_info_set_attribute_int64 (info, "recent::modified",
|
||||||
|
g_date_time_to_unix (item->modified));
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -375,6 +376,7 @@ recent_item_free (RecentItem *item)
|
||||||
g_free (item->display_name);
|
g_free (item->display_name);
|
||||||
g_free (item->guid);
|
g_free (item->guid);
|
||||||
g_clear_object (&item->file);
|
g_clear_object (&item->file);
|
||||||
|
g_date_time_unref (item->modified);
|
||||||
g_free (item);
|
g_free (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +384,7 @@ static gboolean
|
||||||
recent_item_update (RecentItem *item,
|
recent_item_update (RecentItem *item,
|
||||||
const gchar *uri,
|
const gchar *uri,
|
||||||
const gchar *display_name,
|
const gchar *display_name,
|
||||||
time_t modified)
|
GDateTime *modified)
|
||||||
{
|
{
|
||||||
gboolean changed = FALSE;
|
gboolean changed = FALSE;
|
||||||
|
|
||||||
|
@ -403,10 +405,11 @@ recent_item_update (RecentItem *item,
|
||||||
item->display_name = g_strdup (display_name);
|
item->display_name = g_strdup (display_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->modified != modified)
|
if (!g_date_time_equal (item->modified, modified))
|
||||||
{
|
{
|
||||||
changed = TRUE;
|
changed = TRUE;
|
||||||
item->modified = modified;
|
g_date_time_unref (item->modified);
|
||||||
|
item->modified = g_date_time_ref (modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
@ -415,11 +418,12 @@ recent_item_update (RecentItem *item,
|
||||||
static RecentItem *
|
static RecentItem *
|
||||||
recent_item_new (const gchar *uri,
|
recent_item_new (const gchar *uri,
|
||||||
const gchar *display_name,
|
const gchar *display_name,
|
||||||
time_t modified)
|
GDateTime *modified)
|
||||||
{
|
{
|
||||||
RecentItem *item;
|
RecentItem *item;
|
||||||
item = g_new0 (RecentItem, 1);
|
item = g_new0 (RecentItem, 1);
|
||||||
item->guid = g_dbus_generate_guid ();
|
item->guid = g_dbus_generate_guid ();
|
||||||
|
item->modified = g_date_time_ref (modified);
|
||||||
|
|
||||||
recent_item_update (item, uri, display_name, modified);
|
recent_item_update (item, uri, display_name, modified);
|
||||||
|
|
||||||
|
@ -508,12 +512,12 @@ reload_recent_items (GVfsBackendRecent *backend)
|
||||||
const char *uri = uris[i];
|
const char *uri = uris[i];
|
||||||
const char *guid;
|
const char *guid;
|
||||||
char *display_name;
|
char *display_name;
|
||||||
time_t modified;
|
GDateTime *modified;
|
||||||
|
|
||||||
if (should_include (backend->bookmarks, uri))
|
if (should_include (backend->bookmarks, uri))
|
||||||
{
|
{
|
||||||
display_name = get_display_name (backend->bookmarks, uri);
|
display_name = get_display_name (backend->bookmarks, uri);
|
||||||
modified = g_bookmark_file_get_modified (backend->bookmarks, uri, NULL);
|
modified = g_bookmark_file_get_modified_date_time (backend->bookmarks, uri, NULL);
|
||||||
guid = g_hash_table_lookup (backend->uri_map, uri);
|
guid = g_hash_table_lookup (backend->uri_map, uri);
|
||||||
if (guid)
|
if (guid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -465,7 +465,7 @@ setup_ssh_environment (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static char **
|
static char **
|
||||||
setup_ssh_commandline (GVfsBackend *backend)
|
setup_ssh_commandline (GVfsBackend *backend, const gchar *control_path)
|
||||||
{
|
{
|
||||||
GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
|
GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
|
||||||
guint last_arg;
|
guint last_arg;
|
||||||
|
@ -488,7 +488,8 @@ setup_ssh_commandline (GVfsBackend *backend)
|
||||||
#ifndef USE_PTY
|
#ifndef USE_PTY
|
||||||
args[last_arg++] = g_strdup ("-oBatchMode yes");
|
args[last_arg++] = g_strdup ("-oBatchMode yes");
|
||||||
#endif
|
#endif
|
||||||
|
args[last_arg++] = g_strdup ("-oControlMaster auto");
|
||||||
|
args[last_arg++] = g_strdup_printf ("-oControlPath=%s/%%C", control_path);
|
||||||
}
|
}
|
||||||
else if (op_backend->client_vendor == SFTP_VENDOR_SSH)
|
else if (op_backend->client_vendor == SFTP_VENDOR_SSH)
|
||||||
args[last_arg++] = g_strdup ("-x");
|
args[last_arg++] = g_strdup ("-x");
|
||||||
|
@ -1105,10 +1106,10 @@ handle_login (GVfsBackend *backend,
|
||||||
if (g_str_has_suffix (buffer, "password: ") ||
|
if (g_str_has_suffix (buffer, "password: ") ||
|
||||||
g_str_has_suffix (buffer, "Password: ") ||
|
g_str_has_suffix (buffer, "Password: ") ||
|
||||||
g_str_has_suffix (buffer, "Password:") ||
|
g_str_has_suffix (buffer, "Password:") ||
|
||||||
g_str_has_prefix (buffer, "Password for ") ||
|
strstr (buffer, "Password for ") ||
|
||||||
g_str_has_prefix (buffer, "Enter Kerberos password") ||
|
strstr (buffer, "Enter Kerberos password") ||
|
||||||
g_str_has_prefix (buffer, "Enter passphrase for key") ||
|
strstr (buffer, "Enter passphrase for key") ||
|
||||||
g_str_has_prefix (buffer, "Enter PASSCODE"))
|
strstr (buffer, "Enter PASSCODE"))
|
||||||
{
|
{
|
||||||
gboolean aborted = FALSE;
|
gboolean aborted = FALSE;
|
||||||
gsize bytes_written;
|
gsize bytes_written;
|
||||||
|
@ -1160,17 +1161,17 @@ handle_login (GVfsBackend *backend,
|
||||||
if (op_backend->user_specified)
|
if (op_backend->user_specified)
|
||||||
if (strcmp (authtype, "publickey") == 0)
|
if (strcmp (authtype, "publickey") == 0)
|
||||||
/* Translators: the first %s is the username, the second the host name */
|
/* Translators: the first %s is the username, the second the host name */
|
||||||
prompt = g_strdup_printf (_("Enter passphrase for secure key for %s on %s"), op_backend->user, op_backend->host);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter passphrase for secure key for “%s” on “%s”:"), op_backend->user, op_backend->host);
|
||||||
else
|
else
|
||||||
/* Translators: the first %s is the username, the second the host name */
|
/* Translators: the first %s is the username, the second the host name */
|
||||||
prompt = g_strdup_printf (_("Enter password for %s on %s"), op_backend->user, hostname ? hostname : op_backend->host);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter password for “%s” on “%s”:"), op_backend->user, hostname ? hostname : op_backend->host);
|
||||||
else
|
else
|
||||||
if (strcmp (authtype, "publickey") == 0)
|
if (strcmp (authtype, "publickey") == 0)
|
||||||
/* Translators: %s is the hostname */
|
/* Translators: %s is the hostname */
|
||||||
prompt = g_strdup_printf (_("Enter passphrase for secure key for %s"), op_backend->host);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter passphrase for secure key for “%s”:"), op_backend->host);
|
||||||
else
|
else
|
||||||
/* Translators: %s is the hostname */
|
/* Translators: %s is the hostname */
|
||||||
prompt = g_strdup_printf (_("Enter password for %s"), hostname ? hostname : op_backend->host);
|
prompt = g_strdup_printf (_("Authentication Required\nEnter user and password for “%s”:"), hostname ? hostname : op_backend->host);
|
||||||
|
|
||||||
if (!g_mount_source_ask_password (mount_source,
|
if (!g_mount_source_ask_password (mount_source,
|
||||||
prompt,
|
prompt,
|
||||||
|
@ -1264,6 +1265,55 @@ handle_login (GVfsBackend *backend,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strstr (buffer, "Verification code") ||
|
||||||
|
strstr (buffer, "One-time password"))
|
||||||
|
{
|
||||||
|
gchar *verification_code = NULL;
|
||||||
|
gboolean aborted = FALSE;
|
||||||
|
|
||||||
|
g_debug ("handle_login #%d - asking for verification code...\n", i);
|
||||||
|
|
||||||
|
if (op_backend->user_specified)
|
||||||
|
/* Translators: the first %s is the username, the second the host name */
|
||||||
|
prompt = g_strdup_printf (_("Enter verification code for %s on %s"),
|
||||||
|
op_backend->user, op_backend->host);
|
||||||
|
else
|
||||||
|
/* Translators: %s is the hostname */
|
||||||
|
prompt = g_strdup_printf (_("Enter verification code for %s"),
|
||||||
|
op_backend->host);
|
||||||
|
|
||||||
|
if (!g_mount_source_ask_password (mount_source, prompt,
|
||||||
|
op_backend->user, NULL,
|
||||||
|
G_ASK_PASSWORD_NEED_PASSWORD,
|
||||||
|
&aborted, &verification_code,
|
||||||
|
NULL, NULL, NULL, NULL) ||
|
||||||
|
aborted)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, aborted ?
|
||||||
|
G_IO_ERROR_FAILED_HANDLED :
|
||||||
|
G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
_("Password dialog cancelled"));
|
||||||
|
ret_val = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_free (prompt);
|
||||||
|
|
||||||
|
if (!g_output_stream_write_all (reply_stream, verification_code,
|
||||||
|
strlen (verification_code), NULL,
|
||||||
|
NULL, NULL) ||
|
||||||
|
!g_output_stream_write_all (reply_stream, "\n", 1, NULL, NULL,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
g_free (verification_code);
|
||||||
|
g_set_error_literal (error,
|
||||||
|
G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
_("Can’t send password"));
|
||||||
|
ret_val = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (verification_code);
|
||||||
|
}
|
||||||
else if (g_str_has_prefix (buffer, "The authenticity of host '") ||
|
else if (g_str_has_prefix (buffer, "The authenticity of host '") ||
|
||||||
strstr (buffer, "Key fingerprint:") != NULL)
|
strstr (buffer, "Key fingerprint:") != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1275,8 +1325,10 @@ handle_login (GVfsBackend *backend,
|
||||||
|
|
||||||
get_hostname_and_fingerprint_from_line (buffer, &hostname, &fingerprint);
|
get_hostname_and_fingerprint_from_line (buffer, &hostname, &fingerprint);
|
||||||
|
|
||||||
message = g_strdup_printf (_("Can’t verify the identity of “%s”.\n"
|
/* Translators: the first %s is the hostname, the second the key fingerprint */
|
||||||
"This happens when you log in to a computer the first time.\n\n"
|
message = g_strdup_printf (_("Identity Verification Failed\n"
|
||||||
|
"Verifying the identity of “%s” failed, this happens when "
|
||||||
|
"you log in to a computer the first time.\n\n"
|
||||||
"The identity sent by the remote computer is “%s”. "
|
"The identity sent by the remote computer is “%s”. "
|
||||||
"If you want to be absolutely sure it is safe to continue, "
|
"If you want to be absolutely sure it is safe to continue, "
|
||||||
"contact the system administrator."),
|
"contact the system administrator."),
|
||||||
|
@ -1302,7 +1354,9 @@ handle_login (GVfsBackend *backend,
|
||||||
|
|
||||||
get_hostname_and_ip_address (buffer, &hostname, &ip_address);
|
get_hostname_and_ip_address (buffer, &hostname, &ip_address);
|
||||||
|
|
||||||
message = g_strdup_printf (_("The host key for “%s” differs from the key for the IP address “%s”\n"
|
/* Translators: the first %s is the hostname, the second is an ip address */
|
||||||
|
message = g_strdup_printf (_("Identity Verification Failed\n"
|
||||||
|
"The host key for “%s” differs from the key for the IP address “%s”\n"
|
||||||
"If you want to be absolutely sure it is safe to continue, "
|
"If you want to be absolutely sure it is safe to continue, "
|
||||||
"contact the system administrator."),
|
"contact the system administrator."),
|
||||||
hostname ? hostname : op_backend->host,
|
hostname ? hostname : op_backend->host,
|
||||||
|
@ -1841,8 +1895,13 @@ setup_connection (GVfsBackend *backend,
|
||||||
gboolean res;
|
gboolean res;
|
||||||
char *extension_name, *extension_data;
|
char *extension_name, *extension_data;
|
||||||
int i;
|
int i;
|
||||||
|
gchar *control_path = NULL;
|
||||||
|
|
||||||
args = setup_ssh_commandline (backend);
|
control_path = g_build_filename (g_get_user_runtime_dir (), "gvfsd-sftp", NULL);
|
||||||
|
g_mkdir (control_path, 0700);
|
||||||
|
|
||||||
|
args = setup_ssh_commandline (backend, control_path);
|
||||||
|
g_free (control_path);
|
||||||
|
|
||||||
if (!spawn_ssh (backend,
|
if (!spawn_ssh (backend,
|
||||||
args, &pid,
|
args, &pid,
|
||||||
|
@ -4734,6 +4793,9 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "sftp");
|
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "sftp");
|
||||||
g_file_info_set_attribute_boolean (info,
|
g_file_info_set_attribute_boolean (info,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info,
|
||||||
|
G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW,
|
||||||
|
G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (has_extension (op_backend, SFTP_EXT_OPENSSH_STATVFS) &&
|
if (has_extension (op_backend, SFTP_EXT_OPENSSH_STATVFS) &&
|
||||||
(g_file_attribute_matcher_matches (matcher,
|
(g_file_attribute_matcher_matches (matcher,
|
||||||
|
@ -5491,6 +5553,8 @@ typedef struct {
|
||||||
/* fstat information */
|
/* fstat information */
|
||||||
goffset size;
|
goffset size;
|
||||||
guint32 permissions;
|
guint32 permissions;
|
||||||
|
guint64 mtime;
|
||||||
|
guint64 atime;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
goffset offset;
|
goffset offset;
|
||||||
|
@ -5640,8 +5704,15 @@ push_close_deleted_file (GVfsBackendSftp *backend,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
push_close_delete_or_succeed (SftpPushHandle *handle)
|
push_close_delete_or_succeed (GVfsBackendSftp *backend,
|
||||||
|
int reply_type,
|
||||||
|
GDataInputStream *reply,
|
||||||
|
guint32 len,
|
||||||
|
GVfsJob *job,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
|
SftpPushHandle *handle = user_data;
|
||||||
|
|
||||||
if (handle->tempname)
|
if (handle->tempname)
|
||||||
{
|
{
|
||||||
/* If we wrote to a temp file, do delete then rename. */
|
/* If we wrote to a temp file, do delete then rename. */
|
||||||
|
@ -5662,15 +5733,52 @@ push_close_delete_or_succeed (SftpPushHandle *handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
push_close_restore_permissions (GVfsBackendSftp *backend,
|
push_close_restore_permissions (SftpPushHandle *handle)
|
||||||
int reply_type,
|
|
||||||
GDataInputStream *reply,
|
|
||||||
guint32 len,
|
|
||||||
GVfsJob *job,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
/* We don't care if setting the permissions succeeded or not. */
|
gboolean default_perms = (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS);
|
||||||
push_close_delete_or_succeed (user_data);
|
guint32 flags = SSH_FILEXFER_ATTR_ACMODTIME;
|
||||||
|
|
||||||
|
if (!default_perms)
|
||||||
|
flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
|
||||||
|
|
||||||
|
/* Restore the source file's permissions and timestamps. */
|
||||||
|
GDataOutputStream *command = new_command_stream (handle->backend, SSH_FXP_SETSTAT);
|
||||||
|
put_string (command, handle->tempname ? handle->tempname : handle->op_job->destination);
|
||||||
|
g_data_output_stream_put_uint32 (command, flags, NULL, NULL);
|
||||||
|
if (!default_perms)
|
||||||
|
g_data_output_stream_put_uint32 (command, handle->permissions, NULL, NULL);
|
||||||
|
g_data_output_stream_put_uint32 (command, handle->atime, NULL, NULL);
|
||||||
|
g_data_output_stream_put_uint32 (command, handle->mtime, NULL, NULL);
|
||||||
|
queue_command_stream_and_free (&handle->backend->command_connection, command,
|
||||||
|
push_close_delete_or_succeed,
|
||||||
|
handle->job, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
push_close_stat_reply (GVfsBackendSftp *backend,
|
||||||
|
int reply_type,
|
||||||
|
GDataInputStream *reply,
|
||||||
|
guint32 len,
|
||||||
|
GVfsJob *job,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
SftpPushHandle *handle = user_data;
|
||||||
|
|
||||||
|
if (reply_type == SSH_FXP_ATTRS)
|
||||||
|
{
|
||||||
|
GFileInfo *info = g_file_info_new ();
|
||||||
|
|
||||||
|
parse_attributes (backend, info, NULL, reply, NULL);
|
||||||
|
|
||||||
|
/* Don't fail on error, but fall back to the local atime
|
||||||
|
* (assigned in push_source_fstat_cb). */
|
||||||
|
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS))
|
||||||
|
handle->atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
|
||||||
|
|
||||||
|
g_object_unref (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
push_close_restore_permissions (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -5688,19 +5796,19 @@ push_close_write_reply (GVfsBackendSftp *backend,
|
||||||
guint32 code = read_status_code (reply);
|
guint32 code = read_status_code (reply);
|
||||||
if (code == SSH_FX_OK)
|
if (code == SSH_FX_OK)
|
||||||
{
|
{
|
||||||
if (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
|
/* Atime is COPY_WHEN_MOVED, but not COPY_WITH_FILE. */
|
||||||
push_close_delete_or_succeed (handle);
|
if (!handle->op_job->remove_source &&
|
||||||
else
|
!(handle->op_job->flags & G_FILE_COPY_ALL_METADATA))
|
||||||
{
|
{
|
||||||
/* Restore the source file's permissions. */
|
GDataOutputStream *command = new_command_stream (backend, SSH_FXP_LSTAT);
|
||||||
GDataOutputStream *command = new_command_stream (backend, SSH_FXP_SETSTAT);
|
put_string (command, handle->op_job->destination);
|
||||||
put_string (command, handle->tempname ? handle->tempname : handle->op_job->destination);
|
|
||||||
g_data_output_stream_put_uint32 (command, SSH_FILEXFER_ATTR_PERMISSIONS, NULL, NULL);
|
|
||||||
g_data_output_stream_put_uint32 (command, handle->permissions, NULL, NULL);
|
|
||||||
queue_command_stream_and_free (&backend->command_connection, command,
|
queue_command_stream_and_free (&backend->command_connection, command,
|
||||||
push_close_restore_permissions,
|
push_close_stat_reply,
|
||||||
job, handle);
|
job, handle);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_close_restore_permissions (handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -6070,6 +6178,8 @@ push_source_fstat_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||||
{
|
{
|
||||||
handle->permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777;
|
handle->permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777;
|
||||||
handle->size = g_file_info_get_size (info);
|
handle->size = g_file_info_get_size (info);
|
||||||
|
handle->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
|
handle->atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
|
||||||
|
|
||||||
command = new_command_stream (handle->backend, SSH_FXP_OPEN);
|
command = new_command_stream (handle->backend, SSH_FXP_OPEN);
|
||||||
put_string (command, handle->op_job->destination);
|
put_string (command, handle->op_job->destination);
|
||||||
|
@ -6102,7 +6212,9 @@ push_source_open_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||||
|
|
||||||
g_file_input_stream_query_info_async (fin,
|
g_file_input_stream_query_info_async (fin,
|
||||||
G_FILE_ATTRIBUTE_STANDARD_SIZE ","
|
G_FILE_ATTRIBUTE_STANDARD_SIZE ","
|
||||||
G_FILE_ATTRIBUTE_UNIX_MODE,
|
G_FILE_ATTRIBUTE_UNIX_MODE ","
|
||||||
|
G_FILE_ATTRIBUTE_TIME_MODIFIED ","
|
||||||
|
G_FILE_ATTRIBUTE_TIME_ACCESS,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
push_source_fstat_cb, handle);
|
push_source_fstat_cb, handle);
|
||||||
}
|
}
|
||||||
|
@ -6166,6 +6278,14 @@ try_push (GVfsBackend *backend,
|
||||||
GFile *source;
|
GFile *source;
|
||||||
SftpPushHandle *handle;
|
SftpPushHandle *handle;
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (op_job),
|
||||||
|
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!connection_is_usable (&op_backend->data_connection))
|
if (!connection_is_usable (&op_backend->data_connection))
|
||||||
{
|
{
|
||||||
g_vfs_job_failed (G_VFS_JOB (op_job),
|
g_vfs_job_failed (G_VFS_JOB (op_job),
|
||||||
|
@ -6211,6 +6331,8 @@ typedef struct {
|
||||||
/* fstat information */
|
/* fstat information */
|
||||||
goffset size;
|
goffset size;
|
||||||
guint32 mode;
|
guint32 mode;
|
||||||
|
guint64 mtime;
|
||||||
|
guint64 atime;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
goffset offset;
|
goffset offset;
|
||||||
|
@ -6317,12 +6439,22 @@ pull_close_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||||
{
|
{
|
||||||
g_vfs_job_progress_callback (handle->n_written, handle->n_written, handle->job);
|
g_vfs_job_progress_callback (handle->n_written, handle->n_written, handle->job);
|
||||||
|
|
||||||
if (handle->size >= 0 && !(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS))
|
if (handle->size >= 0)
|
||||||
{
|
{
|
||||||
GFileInfo *info = g_file_info_new ();
|
GFileInfo *info = g_file_info_new ();
|
||||||
g_file_info_set_attribute_uint32 (info,
|
if (!(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS))
|
||||||
G_FILE_ATTRIBUTE_UNIX_MODE,
|
g_file_info_set_attribute_uint32 (info,
|
||||||
handle->mode);
|
G_FILE_ATTRIBUTE_UNIX_MODE,
|
||||||
|
handle->mode);
|
||||||
|
g_file_info_set_attribute_uint64 (info,
|
||||||
|
G_FILE_ATTRIBUTE_TIME_MODIFIED,
|
||||||
|
handle->mtime);
|
||||||
|
/* Atime is COPY_WHEN_MOVED, but not COPY_WITH_FILE. */
|
||||||
|
if (handle->op_job->remove_source ||
|
||||||
|
(handle->op_job->flags & G_FILE_COPY_ALL_METADATA))
|
||||||
|
g_file_info_set_attribute_uint64 (info,
|
||||||
|
G_FILE_ATTRIBUTE_TIME_ACCESS,
|
||||||
|
handle->atime);
|
||||||
g_file_set_attributes_async (handle->dest,
|
g_file_set_attributes_async (handle->dest,
|
||||||
info,
|
info,
|
||||||
G_FILE_QUERY_INFO_NONE,
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
@ -6573,6 +6705,10 @@ pull_fstat_reply (GVfsBackendSftp *backend,
|
||||||
handle->size = g_file_info_get_size (info);
|
handle->size = g_file_info_get_size (info);
|
||||||
handle->mode = g_file_info_get_attribute_uint32 (info,
|
handle->mode = g_file_info_get_attribute_uint32 (info,
|
||||||
G_FILE_ATTRIBUTE_UNIX_MODE);
|
G_FILE_ATTRIBUTE_UNIX_MODE);
|
||||||
|
handle->mtime = g_file_info_get_attribute_uint64 (info,
|
||||||
|
G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
|
handle->atime = g_file_info_get_attribute_uint64 (info,
|
||||||
|
G_FILE_ATTRIBUTE_TIME_ACCESS);
|
||||||
g_object_unref (info);
|
g_object_unref (info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -6699,6 +6835,14 @@ try_pull (GVfsBackend *backend,
|
||||||
SftpPullHandle *handle;
|
SftpPullHandle *handle;
|
||||||
Command commands[2];
|
Command commands[2];
|
||||||
|
|
||||||
|
if (remove_source && (flags & G_FILE_COPY_NO_FALLBACK_FOR_MOVE))
|
||||||
|
{
|
||||||
|
g_vfs_job_failed (G_VFS_JOB (job),
|
||||||
|
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Operation not supported"));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!connection_is_usable (&op_backend->data_connection))
|
if (!connection_is_usable (&op_backend->data_connection))
|
||||||
{
|
{
|
||||||
g_vfs_job_failed (G_VFS_JOB (job),
|
g_vfs_job_failed (G_VFS_JOB (job),
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "gvfsjobqueryfsinfo.h"
|
#include "gvfsjobqueryfsinfo.h"
|
||||||
#include "gvfsjobqueryattributes.h"
|
#include "gvfsjobqueryattributes.h"
|
||||||
#include "gvfsjobenumerate.h"
|
#include "gvfsjobenumerate.h"
|
||||||
|
#include "gvfsjobmove.h"
|
||||||
#include "gvfsdaemonprotocol.h"
|
#include "gvfsdaemonprotocol.h"
|
||||||
#include "gvfsdaemonutils.h"
|
#include "gvfsdaemonutils.h"
|
||||||
#include "gvfsutils.h"
|
#include "gvfsutils.h"
|
||||||
|
@ -77,9 +78,7 @@ struct _GVfsBackendSmb
|
||||||
|
|
||||||
GMountSource *mount_source; /* Only used/set during mount */
|
GMountSource *mount_source; /* Only used/set during mount */
|
||||||
int mount_try;
|
int mount_try;
|
||||||
gboolean mount_try_again;
|
|
||||||
gboolean mount_cancelled;
|
gboolean mount_cancelled;
|
||||||
gboolean use_anonymous;
|
|
||||||
|
|
||||||
gboolean password_in_keyring;
|
gboolean password_in_keyring;
|
||||||
GPasswordSave password_save;
|
GPasswordSave password_save;
|
||||||
|
@ -202,25 +201,14 @@ auth_callback (SMBCCTX *context,
|
||||||
backend->user == NULL &&
|
backend->user == NULL &&
|
||||||
backend->domain == NULL)
|
backend->domain == NULL)
|
||||||
{
|
{
|
||||||
/* Try again if kerberos login fails */
|
|
||||||
backend->mount_try_again = TRUE;
|
|
||||||
g_debug ("auth_callback - kerberos pass\n");
|
g_debug ("auth_callback - kerberos pass\n");
|
||||||
}
|
}
|
||||||
else if (backend->mount_try == 1 &&
|
else if (backend->mount_try == 1 &&
|
||||||
backend->user == NULL &&
|
backend->user == NULL &&
|
||||||
backend->domain == NULL)
|
backend->domain == NULL)
|
||||||
{
|
{
|
||||||
/* Try again if ccache login fails */
|
|
||||||
backend->mount_try_again = TRUE;
|
|
||||||
g_debug ("auth_callback - ccache pass\n");
|
g_debug ("auth_callback - ccache pass\n");
|
||||||
}
|
}
|
||||||
else if (backend->use_anonymous)
|
|
||||||
{
|
|
||||||
/* Try again if anonymous login fails */
|
|
||||||
backend->use_anonymous = FALSE;
|
|
||||||
backend->mount_try_again = TRUE;
|
|
||||||
g_debug ("auth_callback - anonymous login pass\n");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gboolean in_keyring = FALSE;
|
gboolean in_keyring = FALSE;
|
||||||
|
@ -263,9 +251,19 @@ auth_callback (SMBCCTX *context,
|
||||||
|
|
||||||
g_debug ("auth_callback - asking for password...\n");
|
g_debug ("auth_callback - asking for password...\n");
|
||||||
|
|
||||||
/* translators: First %s is a share name, second is a server name */
|
if (backend->user)
|
||||||
message = g_strdup_printf (_("Password required for share %s on %s"),
|
{
|
||||||
share_name, server_name);
|
/* Translators: First %s is a share name, second is a server name */
|
||||||
|
message = g_strdup_printf (_("Authentication Required\nEnter password for share “%s” on “%s”:"),
|
||||||
|
share_name, server_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Translators: First %s is a share name, second is a server name */
|
||||||
|
message = g_strdup_printf (_("Authentication Required\nEnter user and password for share “%s” on “%s”:"),
|
||||||
|
share_name, server_name);
|
||||||
|
}
|
||||||
|
|
||||||
handled = g_mount_source_ask_password (backend->mount_source,
|
handled = g_mount_source_ask_password (backend->mount_source,
|
||||||
message,
|
message,
|
||||||
username_out,
|
username_out,
|
||||||
|
@ -290,13 +288,13 @@ auth_callback (SMBCCTX *context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try again if this fails */
|
smbc_setOptionNoAutoAnonymousLogin (backend->smb_context,
|
||||||
backend->mount_try_again = TRUE;
|
!anonymous);
|
||||||
|
|
||||||
if (anonymous)
|
if (anonymous)
|
||||||
{
|
{
|
||||||
backend->use_anonymous = TRUE;
|
|
||||||
backend->password_save = FALSE;
|
backend->password_save = FALSE;
|
||||||
|
g_debug ("auth_callback - anonymous enabled\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -486,7 +484,6 @@ do_mount (GVfsBackend *backend,
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
op_backend->mount_try_again = FALSE;
|
|
||||||
op_backend->mount_cancelled = FALSE;
|
op_backend->mount_cancelled = FALSE;
|
||||||
|
|
||||||
g_debug ("do_mount - try #%d \n", op_backend->mount_try);
|
g_debug ("do_mount - try #%d \n", op_backend->mount_try);
|
||||||
|
@ -502,7 +499,13 @@ do_mount (GVfsBackend *backend,
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM))
|
if (errsv == EINVAL && op_backend->mount_try <= 1 && op_backend->user == NULL)
|
||||||
|
{
|
||||||
|
/* EINVAL is "expected" when kerberos/ccache is misconfigured, see:
|
||||||
|
* https://gitlab.gnome.org/GNOME/gvfs/-/issues/611
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM))
|
||||||
{
|
{
|
||||||
g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled);
|
g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled);
|
||||||
break;
|
break;
|
||||||
|
@ -518,15 +521,9 @@ do_mount (GVfsBackend *backend,
|
||||||
smbc_setOptionFallbackAfterKerberos (op_backend->smb_context, 1);
|
smbc_setOptionFallbackAfterKerberos (op_backend->smb_context, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the AskPassword reply requested anonymous login, enable the
|
|
||||||
* anonymous fallback and try again.
|
|
||||||
*/
|
|
||||||
smbc_setOptionNoAutoAnonymousLogin (op_backend->smb_context,
|
|
||||||
!op_backend->use_anonymous);
|
|
||||||
|
|
||||||
op_backend->mount_try ++;
|
op_backend->mount_try ++;
|
||||||
}
|
}
|
||||||
while (op_backend->mount_try_again);
|
while (TRUE);
|
||||||
|
|
||||||
g_free (uri);
|
g_free (uri);
|
||||||
|
|
||||||
|
@ -1434,6 +1431,8 @@ set_info_from_stat (GVfsBackendSmb *backend,
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches (matcher,
|
if (g_file_attribute_matcher_matches (matcher,
|
||||||
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) ||
|
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE) ||
|
||||||
|
g_file_attribute_matcher_matches (matcher,
|
||||||
|
G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE) ||
|
||||||
g_file_attribute_matcher_matches (matcher,
|
g_file_attribute_matcher_matches (matcher,
|
||||||
G_FILE_ATTRIBUTE_STANDARD_ICON) ||
|
G_FILE_ATTRIBUTE_STANDARD_ICON) ||
|
||||||
g_file_attribute_matcher_matches (matcher,
|
g_file_attribute_matcher_matches (matcher,
|
||||||
|
@ -1587,6 +1586,7 @@ do_query_fs_info (GVfsBackend *backend,
|
||||||
|
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "cifs");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "cifs");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_ALWAYS);
|
||||||
|
|
||||||
if (g_file_attribute_matcher_matches (attribute_matcher,
|
if (g_file_attribute_matcher_matches (attribute_matcher,
|
||||||
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
||||||
|
@ -2041,6 +2041,7 @@ do_move (GVfsBackend *backend,
|
||||||
smbc_stat_fn smbc_stat;
|
smbc_stat_fn smbc_stat;
|
||||||
smbc_rename_fn smbc_rename;
|
smbc_rename_fn smbc_rename;
|
||||||
smbc_unlink_fn smbc_unlink;
|
smbc_unlink_fn smbc_unlink;
|
||||||
|
goffset size;
|
||||||
|
|
||||||
|
|
||||||
source_uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, source);
|
source_uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, source);
|
||||||
|
@ -2062,8 +2063,9 @@ do_move (GVfsBackend *backend,
|
||||||
g_free (source_uri);
|
g_free (source_uri);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
source_is_dir = S_ISDIR (statbuf.st_mode);
|
source_is_dir = S_ISDIR (statbuf.st_mode);
|
||||||
|
size = statbuf.st_size;
|
||||||
|
|
||||||
dest_uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, destination);
|
dest_uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, destination);
|
||||||
|
|
||||||
|
@ -2158,7 +2160,10 @@ do_move (GVfsBackend *backend,
|
||||||
g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
|
g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
{
|
||||||
|
g_vfs_job_progress_callback (size, size, job);
|
||||||
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -367,9 +367,19 @@ auth_callback (SMBCCTX *context,
|
||||||
|
|
||||||
g_debug ("auth_callback - asking for password...\n");
|
g_debug ("auth_callback - asking for password...\n");
|
||||||
|
|
||||||
/* translators: %s is a server name */
|
if (backend->user)
|
||||||
message = g_strdup_printf (_("Password required for %s"),
|
{
|
||||||
server_name);
|
/* Translators: %s is a server name */
|
||||||
|
message = g_strdup_printf (_("Authentication Required\nEnter password for “%s”:"),
|
||||||
|
server_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Translators: %s is a server name */
|
||||||
|
message = g_strdup_printf (_("Authentication Required\nEnter user and password for “%s”:"),
|
||||||
|
server_name);
|
||||||
|
}
|
||||||
|
|
||||||
handled = g_mount_source_ask_password (backend->mount_source,
|
handled = g_mount_source_ask_password (backend->mount_source,
|
||||||
message,
|
message,
|
||||||
username_out,
|
username_out,
|
||||||
|
@ -957,8 +967,14 @@ do_mount (GVfsBackend *backend,
|
||||||
uri, op_backend->mount_try, dir, op_backend->mount_cancelled,
|
uri, op_backend->mount_try, dir, op_backend->mount_cancelled,
|
||||||
errsv, g_strerror (errsv));
|
errsv, g_strerror (errsv));
|
||||||
|
|
||||||
if (dir == NULL &&
|
if (errsv == EINVAL && op_backend->mount_try == 0 && op_backend->user == NULL)
|
||||||
(op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES)))
|
{
|
||||||
|
/* EINVAL is "expected" when kerberos is misconfigured, see:
|
||||||
|
* https://gitlab.gnome.org/GNOME/gvfs/-/issues/611
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (dir == NULL &&
|
||||||
|
(op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES)))
|
||||||
{
|
{
|
||||||
g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled);
|
g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled);
|
||||||
break;
|
break;
|
||||||
|
@ -1496,6 +1512,7 @@ try_query_fs_info (GVfsBackend *backend,
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "cifs");
|
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "cifs");
|
||||||
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, TRUE);
|
||||||
|
g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
|
||||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -612,8 +612,7 @@ send_reply_cb (GObject *source_object,
|
||||||
|
|
||||||
job = channel->priv->current_job;
|
job = channel->priv->current_job;
|
||||||
channel->priv->current_job = NULL;
|
channel->priv->current_job = NULL;
|
||||||
if (job)
|
g_vfs_job_emit_finished (job);
|
||||||
g_vfs_job_emit_finished (job);
|
|
||||||
|
|
||||||
class = G_VFS_CHANNEL_GET_CLASS (channel);
|
class = G_VFS_CHANNEL_GET_CLASS (channel);
|
||||||
|
|
||||||
|
@ -634,7 +633,7 @@ send_reply_cb (GObject *source_object,
|
||||||
}
|
}
|
||||||
/* Start queued request or readahead */
|
/* Start queued request or readahead */
|
||||||
else if (!start_queued_request (channel) &&
|
else if (!start_queued_request (channel) &&
|
||||||
class->readahead && job)
|
class->readahead)
|
||||||
{
|
{
|
||||||
/* No queued requests, maybe we want to do a readahead call */
|
/* No queued requests, maybe we want to do a readahead call */
|
||||||
channel->priv->current_job = class->readahead (channel, job);
|
channel->priv->current_job = class->readahead (channel, job);
|
||||||
|
@ -644,7 +643,6 @@ send_reply_cb (GObject *source_object,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (job);
|
g_object_unref (job);
|
||||||
g_object_unref (channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Might be called on an i/o thread */
|
/* Might be called on an i/o thread */
|
||||||
|
@ -668,7 +666,7 @@ g_vfs_channel_send_reply (GVfsChannel *channel,
|
||||||
channel->priv->reply_buffer,
|
channel->priv->reply_buffer,
|
||||||
G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SIZE,
|
G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SIZE,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
send_reply_cb, g_object_ref (channel));
|
send_reply_cb, channel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -677,7 +675,7 @@ g_vfs_channel_send_reply (GVfsChannel *channel,
|
||||||
channel->priv->output_data,
|
channel->priv->output_data,
|
||||||
channel->priv->output_data_size,
|
channel->priv->output_data_size,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
send_reply_cb, g_object_ref (channel));
|
send_reply_cb, channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,14 +87,6 @@ struct _GVfsDaemon
|
||||||
gboolean lost_main_daemon;
|
gboolean lost_main_daemon;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GVfsDaemon *daemon;
|
|
||||||
char *socket_dir;
|
|
||||||
GDBusServer *server;
|
|
||||||
|
|
||||||
GDBusConnection *conn;
|
|
||||||
} NewConnectionData;
|
|
||||||
|
|
||||||
static guint signals[LAST_SIGNAL] = { 0 };
|
static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
static void g_vfs_daemon_get_property (GObject *object,
|
static void g_vfs_daemon_get_property (GObject *object,
|
||||||
|
@ -209,7 +201,6 @@ job_handler_callback (gpointer data,
|
||||||
GVfsJob *job = G_VFS_JOB (data);
|
GVfsJob *job = G_VFS_JOB (data);
|
||||||
|
|
||||||
g_vfs_job_run (job);
|
g_vfs_job_run (job);
|
||||||
g_object_unref (job);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -649,30 +640,10 @@ g_vfs_daemon_queue_job (GVfsDaemon *daemon,
|
||||||
if (!g_vfs_job_try (job))
|
if (!g_vfs_job_try (job))
|
||||||
{
|
{
|
||||||
/* Couldn't finish / run async, queue worker thread */
|
/* Couldn't finish / run async, queue worker thread */
|
||||||
if (!g_thread_pool_push (daemon->thread_pool, g_object_ref (job), NULL)) /* TODO: Check error */
|
g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
|
||||||
g_object_unref (job);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
new_connection_data_free (void *memory)
|
|
||||||
{
|
|
||||||
NewConnectionData *data = memory;
|
|
||||||
gchar *socket;
|
|
||||||
|
|
||||||
/* Remove the socket and dir after connected */
|
|
||||||
if (data->socket_dir)
|
|
||||||
{
|
|
||||||
socket = g_strdup_printf ("%s/socket", data->socket_dir);
|
|
||||||
g_unlink (socket);
|
|
||||||
g_free (socket);
|
|
||||||
rmdir (data->socket_dir);
|
|
||||||
g_free (data->socket_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
peer_unregister_skeleton (const gchar *obj_path,
|
peer_unregister_skeleton (const gchar *obj_path,
|
||||||
RegisteredPath *reg_path,
|
RegisteredPath *reg_path,
|
||||||
|
@ -723,21 +694,19 @@ peer_connection_closed (GDBusConnection *connection,
|
||||||
daemon_skeleton = g_object_get_data (G_OBJECT (connection), "daemon_skeleton");
|
daemon_skeleton = g_object_get_data (G_OBJECT (connection), "daemon_skeleton");
|
||||||
/* daemon_skeleton should be always valid in this case */
|
/* daemon_skeleton should be always valid in this case */
|
||||||
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon_skeleton));
|
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon_skeleton));
|
||||||
|
|
||||||
g_hash_table_remove (daemon->client_connections, connection);
|
|
||||||
|
|
||||||
/* Unexport the registered interface skeletons */
|
/* Unexport the registered interface skeletons */
|
||||||
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_unregister_skeleton, connection);
|
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_unregister_skeleton, connection);
|
||||||
|
|
||||||
/* The peer-to-peer connection was disconnected */
|
/* The peer-to-peer connection was disconnected */
|
||||||
g_signal_handlers_disconnect_by_data (connection, user_data);
|
g_signal_handlers_disconnect_by_data (connection, user_data);
|
||||||
g_object_unref (connection);
|
|
||||||
|
g_hash_table_remove (daemon->client_connections, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
daemon_peer_connection_setup (GVfsDaemon *daemon,
|
daemon_peer_connection_setup (GVfsDaemon *daemon,
|
||||||
GDBusConnection *dbus_conn,
|
GDBusConnection *dbus_conn)
|
||||||
NewConnectionData *data)
|
|
||||||
{
|
{
|
||||||
GVfsDBusDaemon *daemon_skeleton;
|
GVfsDBusDaemon *daemon_skeleton;
|
||||||
GError *error;
|
GError *error;
|
||||||
|
@ -754,133 +723,34 @@ daemon_peer_connection_setup (GVfsDaemon *daemon,
|
||||||
g_warning ("Failed to accept client: %s, %s (%s, %d)", "object registration failed",
|
g_warning ("Failed to accept client: %s, %s (%s, %d)", "object registration failed",
|
||||||
error->message, g_quark_to_string (error->domain), error->code);
|
error->message, g_quark_to_string (error->domain), error->code);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
g_object_unref (data->conn);
|
return;
|
||||||
goto error_out;
|
|
||||||
}
|
}
|
||||||
g_object_set_data_full (G_OBJECT (data->conn), "daemon_skeleton", daemon_skeleton, (GDestroyNotify) g_object_unref);
|
g_object_set_data_full (G_OBJECT (dbus_conn), "daemon_skeleton",
|
||||||
|
daemon_skeleton, (GDestroyNotify) g_object_unref);
|
||||||
|
|
||||||
/* Export registered interface skeletons on this new connection */
|
/* Export registered interface skeletons on this new connection */
|
||||||
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_register_skeleton, dbus_conn);
|
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_register_skeleton, dbus_conn);
|
||||||
|
|
||||||
g_hash_table_insert (daemon->client_connections, g_object_ref (dbus_conn), NULL);
|
g_hash_table_insert (daemon->client_connections, g_object_ref (dbus_conn), NULL);
|
||||||
|
|
||||||
g_signal_connect (data->conn, "closed", G_CALLBACK (peer_connection_closed), data->daemon);
|
g_signal_connect (dbus_conn, "closed", G_CALLBACK (peer_connection_closed), daemon);
|
||||||
|
|
||||||
error_out:
|
|
||||||
new_connection_data_free (data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#define USE_ABSTRACT_SOCKETS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USE_ABSTRACT_SOCKETS
|
|
||||||
static gboolean
|
|
||||||
test_safe_socket_dir (const char *dirname)
|
|
||||||
{
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
if (g_stat (dirname, &statbuf) != 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
#ifndef G_PLATFORM_WIN32
|
|
||||||
if (statbuf.st_uid != getuid ())
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) ||
|
|
||||||
!S_ISDIR (statbuf.st_mode))
|
|
||||||
return FALSE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static char *
|
|
||||||
create_socket_dir (void)
|
|
||||||
{
|
|
||||||
char *dirname;
|
|
||||||
long iteration = 0;
|
|
||||||
char *safe_dir;
|
|
||||||
gchar tmp[9];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
safe_dir = NULL;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
g_free (safe_dir);
|
|
||||||
|
|
||||||
gvfs_randomize_string (tmp, 8);
|
|
||||||
tmp[8] = '\0';
|
|
||||||
|
|
||||||
dirname = g_strdup_printf ("gvfs-%s-%s",
|
|
||||||
g_get_user_name (), tmp);
|
|
||||||
safe_dir = g_build_filename (g_get_tmp_dir (), dirname, NULL);
|
|
||||||
g_free (dirname);
|
|
||||||
|
|
||||||
if (g_mkdir (safe_dir, 0700) < 0)
|
|
||||||
{
|
|
||||||
switch (errno)
|
|
||||||
{
|
|
||||||
case EACCES:
|
|
||||||
g_error ("I can't write to '%s', daemon init failed",
|
|
||||||
safe_dir);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ENAMETOOLONG:
|
|
||||||
g_error ("Name '%s' too long your system is broken",
|
|
||||||
safe_dir);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ENOMEM:
|
|
||||||
#ifdef ELOOP
|
|
||||||
case ELOOP:
|
|
||||||
#endif
|
|
||||||
case ENOSPC:
|
|
||||||
case ENOTDIR:
|
|
||||||
case ENOENT:
|
|
||||||
g_error ("Resource problem creating '%s'", safe_dir);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: /* carry on going */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Possible race - so we re-scan. */
|
|
||||||
|
|
||||||
if (iteration++ == 1000)
|
|
||||||
g_error ("Cannot find a safe socket path in '%s'", g_get_tmp_dir ());
|
|
||||||
}
|
|
||||||
while (!test_safe_socket_dir (safe_dir));
|
|
||||||
|
|
||||||
return safe_dir;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
generate_address (char **address,
|
generate_address (gchar **address, gchar **socket_path)
|
||||||
char **folder)
|
|
||||||
{
|
{
|
||||||
*address = NULL;
|
gchar tmp[16] = "socket-";
|
||||||
*folder = NULL;
|
gchar *socket_dir;
|
||||||
|
|
||||||
#ifdef USE_ABSTRACT_SOCKETS
|
gvfs_randomize_string (tmp + 7, 8);
|
||||||
{
|
tmp[15] = '\0';
|
||||||
gchar tmp[9];
|
|
||||||
|
|
||||||
gvfs_randomize_string (tmp, 8);
|
socket_dir = gvfs_get_socket_dir ();
|
||||||
tmp[8] = '\0';
|
|
||||||
*address = g_strdup_printf ("unix:abstract=/dbus-vfs-daemon/socket-%s", tmp);
|
*socket_path = g_build_filename (socket_dir, tmp, NULL);
|
||||||
}
|
*address = g_strdup_printf ("unix:path=%s", *socket_path);
|
||||||
#else
|
|
||||||
{
|
g_free (socket_dir);
|
||||||
char *dir;
|
|
||||||
|
|
||||||
dir = create_socket_dir ();
|
|
||||||
*address = g_strdup_printf ("unix:path=%s/socket", dir);
|
|
||||||
*folder = dir;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -888,14 +758,9 @@ daemon_new_connection_func (GDBusServer *server,
|
||||||
GDBusConnection *connection,
|
GDBusConnection *connection,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
NewConnectionData *data;
|
GVfsDaemon *daemon = user_data;
|
||||||
|
|
||||||
data = user_data;
|
daemon_peer_connection_setup (daemon, connection);
|
||||||
|
|
||||||
/* Take ownership */
|
|
||||||
data->conn = g_object_ref (connection);
|
|
||||||
|
|
||||||
daemon_peer_connection_setup (data->daemon, data->conn, data);
|
|
||||||
|
|
||||||
/* Kill the server, no more need for it */
|
/* Kill the server, no more need for it */
|
||||||
g_dbus_server_stop (server);
|
g_dbus_server_stop (server);
|
||||||
|
@ -913,16 +778,11 @@ handle_get_connection (GVfsDBusDaemon *object,
|
||||||
GDBusServer *server;
|
GDBusServer *server;
|
||||||
GError *error;
|
GError *error;
|
||||||
gchar *address1;
|
gchar *address1;
|
||||||
NewConnectionData *data;
|
gchar *socket_path;
|
||||||
char *socket_dir;
|
|
||||||
gchar *guid;
|
gchar *guid;
|
||||||
|
const char *pkexec_uid;
|
||||||
generate_address (&address1, &socket_dir);
|
|
||||||
|
|
||||||
data = g_new (NewConnectionData, 1);
|
generate_address (&address1, &socket_path);
|
||||||
data->daemon = daemon;
|
|
||||||
data->socket_dir = socket_dir;
|
|
||||||
data->conn = NULL;
|
|
||||||
|
|
||||||
guid = g_dbus_generate_guid ();
|
guid = g_dbus_generate_guid ();
|
||||||
error = NULL;
|
error = NULL;
|
||||||
|
@ -943,21 +803,34 @@ handle_get_connection (GVfsDBusDaemon *object,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dbus_server_start (server);
|
g_dbus_server_start (server);
|
||||||
data->server = server;
|
|
||||||
|
|
||||||
g_signal_connect (server, "new-connection", G_CALLBACK (daemon_new_connection_func), data);
|
/* This is needed for gvfsd-admin to ensure correct ownership. */
|
||||||
|
pkexec_uid = g_getenv ("PKEXEC_UID");
|
||||||
|
if (pkexec_uid != NULL)
|
||||||
|
{
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
uid = strtol (pkexec_uid, NULL, 10);
|
||||||
|
if (uid != 0)
|
||||||
|
if (chown (socket_path, uid, (gid_t)-1) < 0)
|
||||||
|
g_warning ("Failed to change socket ownership: %s", g_strerror (errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect (server, "new-connection", G_CALLBACK (daemon_new_connection_func), daemon);
|
||||||
|
|
||||||
gvfs_dbus_daemon_complete_get_connection (object,
|
gvfs_dbus_daemon_complete_get_connection (object,
|
||||||
invocation,
|
invocation,
|
||||||
address1,
|
address1,
|
||||||
"");
|
"");
|
||||||
|
|
||||||
g_free (address1);
|
g_free (address1);
|
||||||
|
g_free (socket_path);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error_out:
|
error_out:
|
||||||
new_connection_data_free (data);
|
|
||||||
g_free (address1);
|
g_free (address1);
|
||||||
|
g_unlink (socket_path);
|
||||||
|
g_free (socket_path);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1171,8 +1044,7 @@ void
|
||||||
g_vfs_daemon_run_job_in_thread (GVfsDaemon *daemon,
|
g_vfs_daemon_run_job_in_thread (GVfsDaemon *daemon,
|
||||||
GVfsJob *job)
|
GVfsJob *job)
|
||||||
{
|
{
|
||||||
if (!g_thread_pool_push (daemon->thread_pool, g_object_ref (job), NULL)) /* TODO: Check error */
|
g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
|
||||||
g_object_unref (job);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -332,7 +332,9 @@ gvfs_accept_certificate (GMountSource *mount_source,
|
||||||
|
|
||||||
certificate_str = certificate_to_string (certificate);
|
certificate_str = certificate_to_string (certificate);
|
||||||
reason = certificate_flags_to_string (errors);
|
reason = certificate_flags_to_string (errors);
|
||||||
message = g_strdup_printf (_("The site’s identity can’t be verified:"
|
|
||||||
|
/* Translators: The first %s is the reason why verification failed, the second a certificate */
|
||||||
|
message = g_strdup_printf (_("Identity Verification Failed\n"
|
||||||
"%s\n\n"
|
"%s\n\n"
|
||||||
"%s\n\n"
|
"%s\n\n"
|
||||||
"Are you really sure you would like to continue?"),
|
"Are you really sure you would like to continue?"),
|
||||||
|
@ -361,3 +363,77 @@ gvfs_accept_certificate (GMountSource *mount_source,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
gssize
|
||||||
|
gvfs_output_stream_splice (GOutputStream *stream,
|
||||||
|
GInputStream *source,
|
||||||
|
GOutputStreamSpliceFlags flags,
|
||||||
|
goffset total_size,
|
||||||
|
GFileProgressCallback progress_callback,
|
||||||
|
gpointer progress_callback_data,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gssize n_read, n_written;
|
||||||
|
gsize bytes_copied;
|
||||||
|
char buffer[8192], *p;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
bytes_copied = 0;
|
||||||
|
res = TRUE;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n_read = g_input_stream_read (source, buffer, sizeof (buffer), cancellable, error);
|
||||||
|
if (n_read == -1)
|
||||||
|
{
|
||||||
|
res = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_read == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = buffer;
|
||||||
|
while (n_read > 0)
|
||||||
|
{
|
||||||
|
n_written = g_output_stream_write (stream, p, n_read, cancellable, error);
|
||||||
|
if (n_written == -1)
|
||||||
|
{
|
||||||
|
res = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += n_written;
|
||||||
|
n_read -= n_written;
|
||||||
|
bytes_copied += n_written;
|
||||||
|
|
||||||
|
if (progress_callback)
|
||||||
|
progress_callback (bytes_copied, total_size, progress_callback_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_copied > G_MAXSSIZE)
|
||||||
|
bytes_copied = G_MAXSSIZE;
|
||||||
|
}
|
||||||
|
while (res);
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
error = NULL; /* Ignore further errors */
|
||||||
|
|
||||||
|
if (flags & G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE)
|
||||||
|
{
|
||||||
|
/* Don't care about errors in source here */
|
||||||
|
g_input_stream_close (source, cancellable, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET)
|
||||||
|
{
|
||||||
|
/* But write errors on close are bad! */
|
||||||
|
if (!g_output_stream_close (stream, cancellable, error))
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
return bytes_copied;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,15 @@ gboolean gvfs_accept_certificate (GMountSource *mount_source,
|
||||||
GTlsCertificate *certificate,
|
GTlsCertificate *certificate,
|
||||||
GTlsCertificateFlags errors);
|
GTlsCertificateFlags errors);
|
||||||
|
|
||||||
|
gssize gvfs_output_stream_splice (GOutputStream *stream,
|
||||||
|
GInputStream *source,
|
||||||
|
GOutputStreamSpliceFlags flags,
|
||||||
|
goffset total_size,
|
||||||
|
GFileProgressCallback progress_callback,
|
||||||
|
gpointer progress_callback_data,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __G_VFS_DAEMON_UTILS_H__ */
|
#endif /* __G_VFS_DAEMON_UTILS_H__ */
|
||||||
|
|
|
@ -231,6 +231,7 @@ g_vfs_ftp_task_acquire_connection (GVfsFtpTask *task)
|
||||||
if (g_vfs_ftp_connection_is_usable (task->conn))
|
if (g_vfs_ftp_connection_is_usable (task->conn))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
ftp->connections--;
|
||||||
g_vfs_ftp_connection_free (task->conn);
|
g_vfs_ftp_connection_free (task->conn);
|
||||||
task->conn = NULL;
|
task->conn = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* gvfshttpinputstream.c: seekable wrapper around SoupRequestHTTP
|
/* gvfshttpinputstream.c: seekable wrapper around SoupRequestHTTP
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
|
* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2021 Igalia S.L.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -29,13 +30,13 @@
|
||||||
#include <libsoup/soup.h>
|
#include <libsoup/soup.h>
|
||||||
|
|
||||||
#include "gvfshttpinputstream.h"
|
#include "gvfshttpinputstream.h"
|
||||||
|
#include "gvfsbackendhttp.h"
|
||||||
|
|
||||||
static void g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
|
static void g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
|
||||||
|
|
||||||
struct GVfsHttpInputStreamPrivate {
|
struct GVfsHttpInputStreamPrivate {
|
||||||
SoupURI *uri;
|
GUri *uri;
|
||||||
SoupSession *session;
|
SoupSession *session;
|
||||||
SoupRequest *req;
|
|
||||||
SoupMessage *msg;
|
SoupMessage *msg;
|
||||||
GInputStream *stream;
|
GInputStream *stream;
|
||||||
|
|
||||||
|
@ -61,9 +62,8 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
||||||
GVfsHttpInputStream *stream = G_VFS_HTTP_INPUT_STREAM (object);
|
GVfsHttpInputStream *stream = G_VFS_HTTP_INPUT_STREAM (object);
|
||||||
GVfsHttpInputStreamPrivate *priv = stream->priv;
|
GVfsHttpInputStreamPrivate *priv = stream->priv;
|
||||||
|
|
||||||
g_clear_pointer (&priv->uri, soup_uri_free);
|
g_clear_pointer (&priv->uri, g_uri_unref);
|
||||||
g_clear_object (&priv->session);
|
g_clear_object (&priv->session);
|
||||||
g_clear_object (&priv->req);
|
|
||||||
g_clear_object (&priv->msg);
|
g_clear_object (&priv->msg);
|
||||||
g_clear_object (&priv->stream);
|
g_clear_object (&priv->stream);
|
||||||
g_free (priv->range);
|
g_free (priv->range);
|
||||||
|
@ -74,7 +74,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
||||||
/**
|
/**
|
||||||
* g_vfs_http_input_stream_new:
|
* g_vfs_http_input_stream_new:
|
||||||
* @session: a #SoupSession
|
* @session: a #SoupSession
|
||||||
* @uri: a #SoupURI
|
* @uri: a #GUri
|
||||||
*
|
*
|
||||||
* Prepares to send a GET request for @uri on @session, and returns a
|
* Prepares to send a GET request for @uri on @session, and returns a
|
||||||
* #GInputStream that can be used to read the response.
|
* #GInputStream that can be used to read the response.
|
||||||
|
@ -89,7 +89,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
||||||
**/
|
**/
|
||||||
GInputStream *
|
GInputStream *
|
||||||
g_vfs_http_input_stream_new (SoupSession *session,
|
g_vfs_http_input_stream_new (SoupSession *session,
|
||||||
SoupURI *uri)
|
GUri *uri)
|
||||||
{
|
{
|
||||||
GVfsHttpInputStream *stream;
|
GVfsHttpInputStream *stream;
|
||||||
GVfsHttpInputStreamPrivate *priv;
|
GVfsHttpInputStreamPrivate *priv;
|
||||||
|
@ -98,30 +98,27 @@ g_vfs_http_input_stream_new (SoupSession *session,
|
||||||
priv = stream->priv;
|
priv = stream->priv;
|
||||||
|
|
||||||
priv->session = g_object_ref (session);
|
priv->session = g_object_ref (session);
|
||||||
priv->uri = soup_uri_copy (uri);
|
priv->uri = g_uri_ref (uri);
|
||||||
|
|
||||||
return G_INPUT_STREAM (stream);
|
return G_INPUT_STREAM (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoupRequest *
|
static SoupMessage *
|
||||||
g_vfs_http_input_stream_ensure_request (GInputStream *stream)
|
g_vfs_http_input_stream_ensure_msg (GInputStream *stream)
|
||||||
{
|
{
|
||||||
GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
|
GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
|
||||||
|
|
||||||
if (!priv->req)
|
if (!priv->msg)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
priv->msg = soup_message_new_from_uri (SOUP_METHOD_GET, priv->uri);
|
||||||
|
|
||||||
priv->req = soup_session_request_uri (priv->session, priv->uri, &error);
|
|
||||||
g_assert_no_error (error);
|
|
||||||
priv->msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (priv->req));
|
|
||||||
priv->offset = 0;
|
priv->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->range)
|
if (priv->range)
|
||||||
soup_message_headers_replace (priv->msg->request_headers, "Range", priv->range);
|
soup_message_headers_replace (soup_message_get_request_headers (priv->msg),
|
||||||
|
"Range", priv->range);
|
||||||
|
|
||||||
return priv->req;
|
return priv->msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -136,7 +133,7 @@ send_callback (GObject *object,
|
||||||
|
|
||||||
g_input_stream_clear_pending (http_stream);
|
g_input_stream_clear_pending (http_stream);
|
||||||
|
|
||||||
priv->stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error);
|
priv->stream = soup_session_send_finish (SOUP_SESSION (object), result, &error);
|
||||||
if (priv->stream)
|
if (priv->stream)
|
||||||
g_task_return_boolean (task, TRUE);
|
g_task_return_boolean (task, TRUE);
|
||||||
else
|
else
|
||||||
|
@ -188,9 +185,9 @@ g_vfs_http_input_stream_send_async (GInputStream *stream,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_vfs_http_input_stream_ensure_request (stream);
|
g_vfs_http_input_stream_ensure_msg (stream);
|
||||||
soup_request_send_async (priv->req, cancellable,
|
soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
|
||||||
send_callback, task);
|
cancellable, send_callback, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,16 +250,16 @@ read_send_callback (GObject *object,
|
||||||
ReadAfterSendData *rasd = g_task_get_task_data (task);
|
ReadAfterSendData *rasd = g_task_get_task_data (task);
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
priv->stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error);
|
priv->stream = soup_session_send_finish (SOUP_SESSION (object), result, &error);
|
||||||
if (!priv->stream)
|
if (!priv->stream)
|
||||||
{
|
{
|
||||||
g_task_return_error (task, error);
|
g_task_return_error (task, error);
|
||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!SOUP_STATUS_IS_SUCCESSFUL (priv->msg->status_code))
|
if (!SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (priv->msg)))
|
||||||
{
|
{
|
||||||
if (priv->msg->status_code == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
|
if (soup_message_get_status (priv->msg) == SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE)
|
||||||
{
|
{
|
||||||
g_input_stream_close (priv->stream, NULL, NULL);
|
g_input_stream_close (priv->stream, NULL, NULL);
|
||||||
g_task_return_int (task, 0);
|
g_task_return_int (task, 0);
|
||||||
|
@ -271,9 +268,9 @@ read_send_callback (GObject *object,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_task_return_new_error (task,
|
g_task_return_new_error (task,
|
||||||
SOUP_HTTP_ERROR,
|
G_IO_ERROR,
|
||||||
priv->msg->status_code,
|
http_error_code_from_status (soup_message_get_status (priv->msg)),
|
||||||
"%s", priv->msg->reason_phrase);
|
_("HTTP Error: %s"), soup_message_get_reason_phrase (priv->msg));
|
||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +279,7 @@ read_send_callback (GObject *object,
|
||||||
gboolean status;
|
gboolean status;
|
||||||
goffset start, end;
|
goffset start, end;
|
||||||
|
|
||||||
status = soup_message_headers_get_content_range (priv->msg->response_headers,
|
status = soup_message_headers_get_content_range (soup_message_get_response_headers (priv->msg),
|
||||||
&start, &end, NULL);
|
&start, &end, NULL);
|
||||||
if (!status || start != priv->request_offset)
|
if (!status || start != priv->request_offset)
|
||||||
{
|
{
|
||||||
|
@ -325,9 +322,9 @@ g_vfs_http_input_stream_read_async (GInputStream *stream,
|
||||||
rasd->count = count;
|
rasd->count = count;
|
||||||
g_task_set_task_data (task, rasd, g_free);
|
g_task_set_task_data (task, rasd, g_free);
|
||||||
|
|
||||||
g_vfs_http_input_stream_ensure_request (stream);
|
g_vfs_http_input_stream_ensure_msg (stream);
|
||||||
soup_request_send_async (priv->req, cancellable,
|
soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
|
||||||
read_send_callback, task);
|
cancellable, read_send_callback, task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +416,7 @@ g_vfs_http_input_stream_seek (GSeekable *seekable,
|
||||||
|
|
||||||
if (type == G_SEEK_END && priv->msg)
|
if (type == G_SEEK_END && priv->msg)
|
||||||
{
|
{
|
||||||
goffset content_length = soup_message_headers_get_content_length (priv->msg->response_headers);
|
goffset content_length = soup_message_headers_get_content_length (soup_message_get_response_headers (priv->msg));
|
||||||
|
|
||||||
if (content_length)
|
if (content_length)
|
||||||
{
|
{
|
||||||
|
@ -498,7 +495,7 @@ g_vfs_http_input_stream_get_message (GInputStream *stream)
|
||||||
{
|
{
|
||||||
GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
|
GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
|
||||||
|
|
||||||
g_vfs_http_input_stream_ensure_request (stream);
|
g_vfs_http_input_stream_ensure_msg (stream);
|
||||||
return g_object_ref (priv->msg);
|
return g_object_ref (priv->msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
|
/* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2021 Igalia S.L.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -57,7 +58,7 @@ struct GVfsHttpInputStreamClass
|
||||||
GType g_vfs_http_input_stream_get_type (void) G_GNUC_CONST;
|
GType g_vfs_http_input_stream_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
GInputStream *g_vfs_http_input_stream_new (SoupSession *session,
|
GInputStream *g_vfs_http_input_stream_new (SoupSession *session,
|
||||||
SoupURI *uri);
|
GUri *uri);
|
||||||
|
|
||||||
void g_vfs_http_input_stream_send_async (GInputStream *stream,
|
void g_vfs_http_input_stream_send_async (GInputStream *stream,
|
||||||
int io_priority,
|
int io_priority,
|
||||||
|
|
|
@ -36,7 +36,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||||
GType
|
GType
|
||||||
g_vfs_job_source_get_type (void)
|
g_vfs_job_source_get_type (void)
|
||||||
{
|
{
|
||||||
static volatile gsize g_define_type_id__volatile = 0;
|
static gsize g_define_type_id__volatile = 0;
|
||||||
|
|
||||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,9 +96,7 @@ on_name_acquired (GDBusConnection *connection,
|
||||||
argv2[0] = LIBEXEC_DIR "/gvfsd-fuse";
|
argv2[0] = LIBEXEC_DIR "/gvfsd-fuse";
|
||||||
argv2[1] = fuse_path;
|
argv2[1] = fuse_path;
|
||||||
argv2[2] = "-f";
|
argv2[2] = "-f";
|
||||||
argv2[3] = "-o";
|
argv2[3] = NULL;
|
||||||
argv2[4] = "big_writes";
|
|
||||||
argv2[5] = NULL;
|
|
||||||
|
|
||||||
g_spawn_async (NULL,
|
g_spawn_async (NULL,
|
||||||
argv2,
|
argv2,
|
||||||
|
@ -145,6 +143,7 @@ main (int argc, char *argv[])
|
||||||
guint name_owner_id;
|
guint name_owner_id;
|
||||||
GBusNameOwnerFlags flags;
|
GBusNameOwnerFlags flags;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
|
gchar *socket_dir;
|
||||||
const GOptionEntry options[] = {
|
const GOptionEntry options[] = {
|
||||||
{ "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, N_("Replace old daemon."), NULL },
|
{ "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, N_("Replace old daemon."), NULL },
|
||||||
{ "no-fuse", 0, 0, G_OPTION_ARG_NONE, &no_fuse, N_("Don’t start fuse."), NULL },
|
{ "no-fuse", 0, 0, G_OPTION_ARG_NONE, &no_fuse, N_("Don’t start fuse."), NULL },
|
||||||
|
@ -214,6 +213,11 @@ main (int argc, char *argv[])
|
||||||
if (daemon == NULL)
|
if (daemon == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* This is needed for gvfsd-admin to ensure correct ownership. */
|
||||||
|
socket_dir = gvfs_get_socket_dir ();
|
||||||
|
g_mkdir (socket_dir, 0700);
|
||||||
|
g_free (socket_dir);
|
||||||
|
|
||||||
g_signal_connect (daemon, "shutdown",
|
g_signal_connect (daemon, "shutdown",
|
||||||
G_CALLBACK (daemon_shutdown), loop);
|
G_CALLBACK (daemon_shutdown), loop);
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ libgvfsdaemon = shared_library(
|
||||||
)
|
)
|
||||||
|
|
||||||
libgvfsdaemon_dep = declare_dependency(
|
libgvfsdaemon_dep = declare_dependency(
|
||||||
include_directories: include_directories('.'),
|
include_directories: '.',
|
||||||
dependencies: libgvfscommon_dep,
|
dependencies: libgvfscommon_dep,
|
||||||
compile_args: cflags,
|
compile_args: cflags,
|
||||||
link_with: libgvfsdaemon,
|
link_with: libgvfsdaemon,
|
||||||
|
@ -154,7 +154,7 @@ daemon_main_sources = files(
|
||||||
'daemon-main-generic.c',
|
'daemon-main-generic.c',
|
||||||
)
|
)
|
||||||
|
|
||||||
programs = []
|
programs = {}
|
||||||
mounts = []
|
mounts = []
|
||||||
schema_data = []
|
schema_data = []
|
||||||
convert_data = []
|
convert_data = []
|
||||||
|
@ -165,7 +165,7 @@ cflags = [
|
||||||
'-DBACKEND_TYPES="localtest", G_VFS_TYPE_BACKEND_LOCALTEST,',
|
'-DBACKEND_TYPES="localtest", G_VFS_TYPE_BACKEND_LOCALTEST,',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-localtest', {'sources': files('gvfsbackendlocaltest.c'), 'c_args': cflags}]]
|
programs += {'gvfsd-localtest': {'sources': files('gvfsbackendlocaltest.c'), 'c_args': cflags}}
|
||||||
mounts += ['localtest']
|
mounts += ['localtest']
|
||||||
|
|
||||||
sources = files(
|
sources = files(
|
||||||
|
@ -184,7 +184,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=10',
|
'-DMAX_JOB_THREADS=10',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-ftp', {'sources': sources, 'c_args': cflags}]]
|
programs += {'gvfsd-ftp': {'sources': sources, 'c_args': cflags}}
|
||||||
mounts += ['ftp', 'ftps', 'ftpis']
|
mounts += ['ftp', 'ftps', 'ftpis']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -194,7 +194,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=10',
|
'-DMAX_JOB_THREADS=10',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-trash', {'sources': files('gvfsbackendtrash.c'), 'dependencies': [libtrash_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-trash': {'sources': files('gvfsbackendtrash.c'), 'dependencies': [libtrash_dep], 'c_args': cflags}}
|
||||||
mounts += ['trash']
|
mounts += ['trash']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -205,7 +205,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=10',
|
'-DMAX_JOB_THREADS=10',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-recent', {'sources': files('gvfsbackendrecent.c'), 'c_args': cflags}]]
|
programs += {'gvfsd-recent': {'sources': files('gvfsbackendrecent.c'), 'c_args': cflags}}
|
||||||
mounts += ['recent']
|
mounts += ['recent']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -216,7 +216,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-computer', {'sources': files('gvfsbackendcomputer.c'), 'dependencies': [gio_unix_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-computer': {'sources': files('gvfsbackendcomputer.c'), 'dependencies': [gio_unix_dep], 'c_args': cflags}}
|
||||||
mounts += ['computer']
|
mounts += ['computer']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -227,7 +227,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-network', {'sources': files('gvfsbackendnetwork.c'), 'c_args': cflags}]]
|
programs += {'gvfsd-network': {'sources': files('gvfsbackendnetwork.c'), 'c_args': cflags}}
|
||||||
mounts += ['network']
|
mounts += ['network']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -237,7 +237,7 @@ cflags = [
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-burn', {'sources': files('gvfsbackendburn.c'), 'dependencies': [gio_unix_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-burn': {'sources': files('gvfsbackendburn.c'), 'dependencies': [gio_unix_dep], 'c_args': cflags}}
|
||||||
mounts += ['burn']
|
mounts += ['burn']
|
||||||
|
|
||||||
if enable_sftp
|
if enable_sftp
|
||||||
|
@ -256,10 +256,10 @@ if enable_sftp
|
||||||
'-DDEFAULT_BACKEND_TYPE=sftp',
|
'-DDEFAULT_BACKEND_TYPE=sftp',
|
||||||
'-DBACKEND_TYPES="sftp", G_VFS_TYPE_BACKEND_SFTP,',
|
'-DBACKEND_TYPES="sftp", G_VFS_TYPE_BACKEND_SFTP,',
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
'-DSSH_PROGRAM="@0@"'.format(ssh.path()),
|
'-DSSH_PROGRAM="ssh"',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-sftp', {'sources': sources, 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-sftp': {'sources': sources, 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['sftp']
|
mounts += ['sftp']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -273,7 +273,7 @@ if enable_samba
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-smb', {'sources': sources, 'dependencies': [smbclient_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-smb': {'sources': sources, 'dependencies': [smbclient_dep], 'c_args': cflags}}
|
||||||
mounts += ['smb']
|
mounts += ['smb']
|
||||||
schema_data += files('org.gnome.system.smb.gschema.xml')
|
schema_data += files('org.gnome.system.smb.gschema.xml')
|
||||||
convert_data += files('gvfs-smb.convert')
|
convert_data += files('gvfs-smb.convert')
|
||||||
|
@ -286,7 +286,7 @@ if enable_samba
|
||||||
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_smb_browse',
|
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_smb_browse',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-smb-browse', {'sources': sources + files('gvfsbackendsmbbrowse.c'), 'dependencies': [smbclient_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-smb-browse': {'sources': sources + files('gvfsbackendsmbbrowse.c'), 'dependencies': [smbclient_dep], 'c_args': cflags}}
|
||||||
mounts += ['smb-browse']
|
mounts += ['smb-browse']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ if enable_dnssd
|
||||||
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_dnssd',
|
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_dnssd',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-dnssd', {'sources': files('gvfsbackenddnssd.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-dnssd': {'sources': files('gvfsbackenddnssd.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['dns-sd']
|
mounts += ['dns-sd']
|
||||||
schema_data += files('org.gnome.system.dns_sd.gschema.xml')
|
schema_data += files('org.gnome.system.dns_sd.gschema.xml')
|
||||||
convert_data += files('gvfs-dns-sd.convert')
|
convert_data += files('gvfs-dns-sd.convert')
|
||||||
|
@ -320,7 +320,7 @@ if enable_archive
|
||||||
'-DBACKEND_USES_GVFS=1',
|
'-DBACKEND_USES_GVFS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-archive', {'sources': files('gvfsbackendarchive.c'), 'dependencies': [libarchive_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-archive': {'sources': files('gvfsbackendarchive.c'), 'dependencies': [libarchive_dep], 'c_args': cflags}}
|
||||||
mounts += ['archive']
|
mounts += ['archive']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ if enable_cdda
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-cdda', {'sources': files('gvfsbackendcdda.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-cdda': {'sources': files('gvfsbackendcdda.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['cdda']
|
mounts += ['cdda']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -354,27 +354,27 @@ if enable_admin
|
||||||
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_admin',
|
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_admin',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-admin', {'sources': files('gvfsbackendadmin.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-admin': {'sources': files('gvfsbackendadmin.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['admin']
|
mounts += ['admin']
|
||||||
|
|
||||||
policy = gvfs_namespace + '.file-operations.policy'
|
policy = gvfs_namespace + '.file-operations.policy'
|
||||||
|
|
||||||
policy_in = configure_file(
|
|
||||||
input: policy + '.in.in',
|
|
||||||
output: '@BASENAME@',
|
|
||||||
configuration: service_conf,
|
|
||||||
)
|
|
||||||
|
|
||||||
i18n.merge_file(
|
i18n.merge_file(
|
||||||
input: policy_in,
|
input: configure_file(
|
||||||
|
input: policy + '.in.in',
|
||||||
|
output: '@BASENAME@',
|
||||||
|
configuration: service_conf,
|
||||||
|
),
|
||||||
output: '@BASENAME@',
|
output: '@BASENAME@',
|
||||||
po_dir: po_dir,
|
po_dir: po_dir,
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: gvfs_datadir / 'polkit-1/actions',
|
install_dir: gvfs_datadir / 'polkit-1/actions',
|
||||||
)
|
)
|
||||||
|
|
||||||
install_data(
|
configure_file(
|
||||||
gvfs_namespace + '.file-operations.rules',
|
input: gvfs_namespace + '.file-operations.rules.in',
|
||||||
|
output: '@BASENAME@',
|
||||||
|
configuration: {'PRIVILEGED_GROUP': privileged_group},
|
||||||
install_dir: gvfs_datadir / 'polkit-1/rules.d',
|
install_dir: gvfs_datadir / 'polkit-1/rules.d',
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
@ -391,7 +391,7 @@ if enable_google
|
||||||
'-DBACKEND_TYPES="google-drive", G_VFS_TYPE_BACKEND_GOOGLE,',
|
'-DBACKEND_TYPES="google-drive", G_VFS_TYPE_BACKEND_GOOGLE,',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-google', {'sources': files('gvfsbackendgoogle.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-google': {'sources': files('gvfsbackendgoogle.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['google']
|
mounts += ['google']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ if enable_gphoto2
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-gphoto2', {'sources': files('gvfsbackendgphoto2.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-gphoto2': {'sources': files('gvfsbackendgphoto2.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['gphoto2']
|
mounts += ['gphoto2']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -430,7 +430,7 @@ if enable_mtp
|
||||||
deps += libusb_dep
|
deps += libusb_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
programs += [['gvfsd-mtp', {'sources': files('gvfsbackendmtp.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-mtp': {'sources': files('gvfsbackendmtp.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['mtp']
|
mounts += ['mtp']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ if enable_http
|
||||||
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_http',
|
'-DMOUNTABLE_DBUS_NAME=' + gvfs_namespace + '.mountpoint_http',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-http', {'sources': sources, 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-http': {'sources': sources, 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['http']
|
mounts += ['http']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -472,7 +472,7 @@ if enable_http
|
||||||
cflags += '-DBACKEND_TYPES="dav", G_VFS_TYPE_BACKEND_DAV,'
|
cflags += '-DBACKEND_TYPES="dav", G_VFS_TYPE_BACKEND_DAV,'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
programs += [['gvfsd-dav', {'sources': sources + files('gvfsbackenddav.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-dav': {'sources': sources + files('gvfsbackenddav.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['dav']
|
mounts += ['dav']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -490,7 +490,7 @@ if enable_afc
|
||||||
'-DBACKEND_USES_GVFS=1',
|
'-DBACKEND_USES_GVFS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-afc', {'sources': files('gvfsbackendafc.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-afc': {'sources': files('gvfsbackendafc.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['afc']
|
mounts += ['afc']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ if enable_afp
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-afp', {'sources': common_sources + files('gvfsbackendafp.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-afp': {'sources': common_sources + files('gvfsbackendafp.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['afp']
|
mounts += ['afp']
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -525,7 +525,7 @@ if enable_afp
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-afp-browse', {'sources': common_sources + files('gvfsbackendafpbrowse.c'), 'dependencies': deps, 'c_args': cflags}]]
|
programs += {'gvfsd-afp-browse': {'sources': common_sources + files('gvfsbackendafpbrowse.c'), 'dependencies': deps, 'c_args': cflags}}
|
||||||
mounts += ['afp-browse']
|
mounts += ['afp-browse']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -537,12 +537,11 @@ if enable_nfs
|
||||||
'-DMAX_JOB_THREADS=1',
|
'-DMAX_JOB_THREADS=1',
|
||||||
]
|
]
|
||||||
|
|
||||||
programs += [['gvfsd-nfs', {'sources': files('gvfsbackendnfs.c'), 'dependencies': [libnfs_dep], 'c_args': cflags}]]
|
programs += {'gvfsd-nfs': {'sources': files('gvfsbackendnfs.c'), 'dependencies': [libnfs_dep], 'c_args': cflags}}
|
||||||
mounts += ['nfs']
|
mounts += ['nfs']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
foreach program: programs
|
foreach program, options: programs
|
||||||
options = program[1]
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'sources': daemon_main_sources + options.get('sources', []),
|
'sources': daemon_main_sources + options.get('sources', []),
|
||||||
'dependencies': [libgvfsdaemon_dep] + options.get('dependencies', []),
|
'dependencies': [libgvfsdaemon_dep] + options.get('dependencies', []),
|
||||||
|
@ -550,7 +549,7 @@ foreach program: programs
|
||||||
}
|
}
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
program[0],
|
program,
|
||||||
include_directories: top_inc,
|
include_directories: top_inc,
|
||||||
kwargs: kwargs,
|
kwargs: kwargs,
|
||||||
install: true,
|
install: true,
|
||||||
|
|
|
@ -415,6 +415,30 @@ child_watch_cb (GPid pid,
|
||||||
gint status,
|
gint status,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
|
MountData *data = user_data;
|
||||||
|
GError *error = NULL;
|
||||||
|
gint code = 0;
|
||||||
|
|
||||||
|
if (!g_spawn_check_wait_status (status, &error))
|
||||||
|
{
|
||||||
|
if (error->domain == G_SPAWN_EXIT_ERROR)
|
||||||
|
code = error->code;
|
||||||
|
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GVfs daemons always exit with 0, but gvfsd-admin is spawned over pkexec,
|
||||||
|
* which can fail when the authentication dialog is dismissed for example.
|
||||||
|
*/
|
||||||
|
if (code == 126 || code == 127)
|
||||||
|
{
|
||||||
|
error = g_error_new_literal (G_IO_ERROR,
|
||||||
|
G_IO_ERROR_PERMISSION_DENIED,
|
||||||
|
_("Permission denied"));
|
||||||
|
mount_finish (data, error);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
|
||||||
g_spawn_close_pid (pid);
|
g_spawn_close_pid (pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +509,7 @@ spawn_mount (MountData *data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_child_watch_add (pid, child_watch_cb, NULL);
|
g_child_watch_add (pid, child_watch_cb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_strfreev (argv);
|
g_strfreev (argv);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Allows users belonging to wheel group to start gvfsd-admin without
|
// Allows users belonging to privileged group to start gvfsd-admin without
|
||||||
// authorization. This prevents redundant password prompt when starting
|
// authorization. This prevents redundant password prompt when starting
|
||||||
// gvfsd-admin. The gvfsd-admin causes another password prompts to be shown
|
// gvfsd-admin. The gvfsd-admin causes another password prompt to be shown
|
||||||
// for each client process using the different action id and for the subject
|
// for each client process using the different action id and for the subject
|
||||||
// based on the client process.
|
// based on the client process.
|
||||||
polkit.addRule(function(action, subject) {
|
polkit.addRule(function(action, subject) {
|
||||||
if ((action.id == "org.gtk.vfs.file-operations-helper") &&
|
if ((action.id == "org.gtk.vfs.file-operations-helper") &&
|
||||||
subject.local &&
|
subject.local &&
|
||||||
subject.active &&
|
subject.active &&
|
||||||
subject.isInGroup ("sudo")) {
|
subject.isInGroup ("@PRIVILEGED_GROUP@")) {
|
||||||
return polkit.Result.YES;
|
return polkit.Result.YES;
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -272,10 +272,10 @@ dir_watch_free (DirWatch *watch)
|
||||||
if (watch != NULL)
|
if (watch != NULL)
|
||||||
{
|
{
|
||||||
if (watch->parent_monitor)
|
if (watch->parent_monitor)
|
||||||
{
|
{
|
||||||
g_file_monitor_cancel (watch->parent_monitor);
|
g_file_monitor_cancel (watch->parent_monitor);
|
||||||
g_object_unref (watch->parent_monitor);
|
g_object_unref (watch->parent_monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (watch->directory);
|
g_object_unref (watch->directory);
|
||||||
g_object_unref (watch->topdir);
|
g_object_unref (watch->topdir);
|
||||||
|
|
|
@ -211,6 +211,34 @@ trash_mount_remove (TrashMount **mount_ptr)
|
||||||
g_slice_free (TrashMount, mount);
|
g_slice_free (TrashMount, mount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
ignore_trash_mount (GUnixMountEntry *mount)
|
||||||
|
{
|
||||||
|
GUnixMountPoint *mount_point = NULL;
|
||||||
|
const gchar *mount_options;
|
||||||
|
gboolean retval = TRUE;
|
||||||
|
|
||||||
|
if (g_unix_mount_is_system_internal (mount))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
mount_options = g_unix_mount_get_options (mount);
|
||||||
|
if (mount_options == NULL)
|
||||||
|
{
|
||||||
|
mount_point = g_unix_mount_point_at (g_unix_mount_get_mount_path (mount),
|
||||||
|
NULL);
|
||||||
|
if (mount_point != NULL)
|
||||||
|
mount_options = g_unix_mount_point_get_options (mount_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount_options == NULL ||
|
||||||
|
strstr (mount_options, "x-gvfs-notrash") == NULL)
|
||||||
|
retval = FALSE;
|
||||||
|
|
||||||
|
g_clear_pointer (&mount_point, g_unix_mount_point_free);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
trash_watcher_remount (TrashWatcher *watcher)
|
trash_watcher_remount (TrashWatcher *watcher)
|
||||||
{
|
{
|
||||||
|
@ -229,7 +257,7 @@ trash_watcher_remount (TrashWatcher *watcher)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (new && g_unix_mount_is_system_internal (new->data))
|
if (new && ignore_trash_mount (new->data))
|
||||||
{
|
{
|
||||||
g_unix_mount_free (new->data);
|
g_unix_mount_free (new->data);
|
||||||
new = new->next;
|
new = new->next;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
gvfs (1.44.1-ok6) yangtze; urgency=medium
|
gvfs (1.50.3-ok1~0407) yangtze; urgency=medium
|
||||||
|
|
||||||
* update version info
|
* New upstream release.
|
||||||
|
|
||||||
-- luzhiping <luzhiping@kylinos.cn> Mon, 22 Aug 2022 13:58:48 +0800
|
-- Yue Lan <lanyue@kylinos.cn> Fri, 07 Apr 2023 11:40:43 +0800
|
||||||
|
|
||||||
gvfs (1.44.1-ok5~0629) yangtze; urgency=medium
|
gvfs (1.44.1-ok5~0629) yangtze; urgency=medium
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Source: gvfs
|
Source: gvfs
|
||||||
Section: gnome
|
Section: gnome
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Openkylin Developers <packaging@lists.openkylin.top>
|
Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
|
||||||
Uploaders: Iain Lane <laney@debian.org>, Jeremy Bicha <jbicha@debian.org>, Laurent Bigonville <bigon@debian.org>
|
Uploaders: Iain Lane <laney@debian.org>, Jeremy Bicha <jbicha@debian.org>, Laurent Bigonville <bigon@debian.org>
|
||||||
Build-Depends: debhelper-compat (= 12),
|
Build-Depends: debhelper-compat (= 12),
|
||||||
dh-exec (>= 0.13),
|
dh-exec (>= 0.13),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<description xml:lang="en">GVfs is a userspace virtual filesystem implementation for GIO (a library available in GLib). GVfs comes with a set of backends, including trash support, SFTP, SMB, HTTP, DAV, and many others. GVfs also contains modules for GIO that implement volume monitors and persistent metadata storage. There is also FUSE support that provides limited access to the GVfs filesystems for applications not using GIO.</description>
|
<description xml:lang="en">GVfs is a userspace virtual filesystem implementation for GIO (a library available in GLib). GVfs comes with a set of backends, including trash support, SFTP, SMB, HTTP, DAV, and many others. GVfs also contains modules for GIO that implement volume monitors and persistent metadata storage. There is also FUSE support that provides limited access to the GVfs filesystems for applications not using GIO.</description>
|
||||||
|
|
||||||
<homepage rdf:resource="https://wiki.gnome.org/Projects/gvfs" />
|
<homepage rdf:resource="https://wiki.gnome.org/Projects/gvfs" />
|
||||||
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gvfs-list" />
|
<mailing-list rdf:resource="https://discourse.gnome.org" />
|
||||||
<download-page rdf:resource="http://download.gnome.org/sources/gvfs/" />
|
<download-page rdf:resource="http://download.gnome.org/sources/gvfs/" />
|
||||||
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gvfs/issues/" />
|
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gvfs/issues/" />
|
||||||
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<maintainer>
|
<maintainer>
|
||||||
<foaf:Person>
|
<foaf:Person>
|
||||||
<foaf:name>Ondrej Holy</foaf:name>
|
<foaf:name>Ondrej Holy</foaf:name>
|
||||||
<foaf:mbox rdf:resource="mailto:oholy@redhat.com" />
|
<foaf:mbox rdf:resource="mailto:oholy@gnome.org" />
|
||||||
<gnome:userid>oholy</gnome:userid>
|
<gnome:userid>oholy</gnome:userid>
|
||||||
</foaf:Person>
|
</foaf:Person>
|
||||||
</maintainer>
|
</maintainer>
|
||||||
|
|
|
@ -14,20 +14,20 @@ xsltproc_cmd = [
|
||||||
'@INPUT@',
|
'@INPUT@',
|
||||||
]
|
]
|
||||||
|
|
||||||
mans = [
|
mans = {
|
||||||
['gvfs', '7'],
|
'gvfs': '7',
|
||||||
['gvfsd', '1'],
|
'gvfsd': '1',
|
||||||
['gvfsd-fuse', '1'],
|
'gvfsd-fuse': '1',
|
||||||
['gvfsd-metadata', '1'],
|
'gvfsd-metadata': '1',
|
||||||
]
|
}
|
||||||
|
|
||||||
foreach man: mans
|
foreach program, section: mans
|
||||||
custom_target(
|
custom_target(
|
||||||
man[0] + man[1],
|
program + section,
|
||||||
input: man[0] + '.xml',
|
input: program + '.xml',
|
||||||
output: '@BASENAME@.' + man[1],
|
output: '@BASENAME@.' + section,
|
||||||
command: xsltproc_cmd,
|
command: xsltproc_cmd,
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: gvfs_mandir / ('man' + man[1]),
|
install_dir: gvfs_mandir / ('man' + section),
|
||||||
)
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
154
meson.build
154
meson.build
|
@ -1,9 +1,9 @@
|
||||||
project(
|
project(
|
||||||
'gvfs', 'c',
|
'gvfs', 'c',
|
||||||
version: '1.44.1',
|
version: '1.50.3',
|
||||||
license: 'LGPL2+',
|
license: 'LGPL2+',
|
||||||
default_options: 'buildtype=debugoptimized',
|
default_options: 'buildtype=debugoptimized',
|
||||||
meson_version: '>= 0.50.0',
|
meson_version: '>= 0.56.0',
|
||||||
)
|
)
|
||||||
|
|
||||||
gvfs_name = meson.project_name()
|
gvfs_name = meson.project_name()
|
||||||
|
@ -44,16 +44,16 @@ cc = meson.get_compiler('c')
|
||||||
config_h = configuration_data()
|
config_h = configuration_data()
|
||||||
|
|
||||||
# defines
|
# defines
|
||||||
set_defines = [
|
set_defines = {
|
||||||
# package
|
# package
|
||||||
['PACKAGE_STRING', '@0@ @1@'.format(gvfs_name, gvfs_version)],
|
'PACKAGE_STRING': '@0@ @1@'.format(gvfs_name, gvfs_version),
|
||||||
['VERSION', gvfs_version],
|
'VERSION': gvfs_version,
|
||||||
# i18n
|
# i18n
|
||||||
['GETTEXT_PACKAGE', gvfs_name],
|
'GETTEXT_PACKAGE': gvfs_name,
|
||||||
]
|
}
|
||||||
|
|
||||||
foreach define: set_defines
|
foreach define, value: set_defines
|
||||||
config_h.set_quoted(define[0], define[1])
|
config_h.set_quoted(define, value)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
# Globally define_GNU_SOURCE and therefore enable the GNU extensions
|
# Globally define_GNU_SOURCE and therefore enable the GNU extensions
|
||||||
|
@ -179,17 +179,17 @@ foreach name: ['mkdev', 'sysmacros']
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
# types
|
# types
|
||||||
check_types = [
|
check_types = {
|
||||||
# type, fallback type
|
# type, fallback type
|
||||||
['gid_t', 'int'],
|
'gid_t': 'int',
|
||||||
['pid_t', 'int'],
|
'pid_t': 'int',
|
||||||
['size_t', 'unsigned int'],
|
'size_t': 'unsigned int',
|
||||||
['uid_t', 'int'],
|
'uid_t': 'int',
|
||||||
]
|
}
|
||||||
|
|
||||||
foreach type: check_types
|
foreach type, value: check_types
|
||||||
if not cc.has_type(type[0], prefix: '#include<sys/types.h>')
|
if not cc.has_type(type, prefix: '#include<sys/types.h>')
|
||||||
config_h.set(type[0], type[1])
|
config_h.set(type, value)
|
||||||
endif
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ have_version_script = cc.has_link_argument('@0@,@1@'.format(version_script_ldfla
|
||||||
|
|
||||||
gio_dep = dependency('gio-2.0')
|
gio_dep = dependency('gio-2.0')
|
||||||
gio_unix_dep = dependency('gio-unix-2.0')
|
gio_unix_dep = dependency('gio-unix-2.0')
|
||||||
glib_dep = dependency('glib-2.0', version: '>= 2.57.2')
|
glib_dep = dependency('glib-2.0', version: '>= 2.70.0')
|
||||||
gobject_dep = dependency('gobject-2.0')
|
gobject_dep = dependency('gobject-2.0')
|
||||||
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.33.0')
|
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.33.0')
|
||||||
|
|
||||||
|
@ -249,23 +249,23 @@ endif
|
||||||
config_h.set('HAVE_GCRYPT', enable_gcrypt)
|
config_h.set('HAVE_GCRYPT', enable_gcrypt)
|
||||||
|
|
||||||
# *** Check for dbus service dir ***
|
# *** Check for dbus service dir ***
|
||||||
dbus_session_bus_services_dir = dependency('dbus-1').get_pkgconfig_variable(
|
dbus_session_bus_services_dir = dependency('dbus-1').get_variable(
|
||||||
'session_bus_services_dir',
|
pkgconfig: 'session_bus_services_dir',
|
||||||
define_variable: ['datadir', gvfs_prefix / gvfs_datadir],
|
pkgconfig_define: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||||
)
|
)
|
||||||
|
|
||||||
dbus_service_in = files('dbus.service.in')
|
dbus_service_in = files('dbus.service.in')
|
||||||
|
|
||||||
# *** Check for giomoduledir and schemasdir ***
|
# *** Check for giomoduledir and schemasdir ***
|
||||||
gio_giomoduledir = gio_dep.get_pkgconfig_variable(
|
gio_giomoduledir = gio_dep.get_variable(
|
||||||
'giomoduledir',
|
pkgconfig: 'giomoduledir',
|
||||||
define_variable: ['libdir', gvfs_prefix / gvfs_libdir],
|
pkgconfig_define: ['libdir', gvfs_prefix / gvfs_libdir],
|
||||||
)
|
)
|
||||||
|
|
||||||
gio_schemasdir = gio_dep.get_pkgconfig_variable(
|
gio_schemasdir = gio_dep.get_variable(
|
||||||
'schemasdir',
|
pkgconfig: 'schemasdir',
|
||||||
define_variable: ['datadir', gvfs_prefix / gvfs_datadir],
|
pkgconfig_define: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||||
default: gvfs_prefix / gvfs_datadir / 'glib-2.0/schemas',
|
default_value: gvfs_prefix / gvfs_datadir / 'glib-2.0/schemas',
|
||||||
)
|
)
|
||||||
|
|
||||||
# *** Check for systemd options ***
|
# *** Check for systemd options ***
|
||||||
|
@ -281,12 +281,12 @@ if install_systemd_systemduserunitdir or install_systemd_tmpfilesdir
|
||||||
|
|
||||||
if install_systemd_systemduserunitdir and systemd_systemduserunitdir == ''
|
if install_systemd_systemduserunitdir and systemd_systemduserunitdir == ''
|
||||||
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user unit dir or disable it')
|
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user unit dir or disable it')
|
||||||
systemd_systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir')
|
systemd_systemduserunitdir = systemd_dep.get_variable(pkgconfig: 'systemduserunitdir', pkgconfig_define: ['prefix', gvfs_prefix])
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if install_systemd_tmpfilesdir and systemd_tmpfilesdir == ''
|
if install_systemd_tmpfilesdir and systemd_tmpfilesdir == ''
|
||||||
assert(systemd_dep.found(), 'systemd not found, if you use opentmpfiles please provide a valid systemd user unit dir or disable it')
|
assert(systemd_dep.found(), 'systemd not found, if you use opentmpfiles please provide a valid systemd user unit dir or disable it')
|
||||||
systemd_tmpfilesdir = systemd_dep.get_pkgconfig_variable('tmpfilesdir')
|
systemd_tmpfilesdir = systemd_dep.get_variable(pkgconfig: 'tmpfilesdir', pkgconfig_define: ['prefix', gvfs_prefix])
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
@ -299,17 +299,18 @@ endif
|
||||||
config_h.set('HAVE_GCR', enable_gcr)
|
config_h.set('HAVE_GCR', enable_gcr)
|
||||||
|
|
||||||
# *** Check if we should build with admin backend ***
|
# *** Check if we should build with admin backend ***
|
||||||
|
privileged_group = get_option('privileged_group')
|
||||||
enable_admin = get_option('admin')
|
enable_admin = get_option('admin')
|
||||||
if enable_admin
|
if enable_admin
|
||||||
libcap_dep = dependency('libcap')
|
libcap_dep = dependency('libcap')
|
||||||
polkit_gobject_dep = dependency('polkit-gobject-1')
|
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# *** Check if we should build with http backend ***
|
# *** Check if we should build with http backend ***
|
||||||
enable_http = get_option('http')
|
enable_http = get_option('http')
|
||||||
if enable_http
|
if enable_http
|
||||||
assert(have_libxml, 'http required but libxml-2.0 not found')
|
assert(have_libxml, 'http required but libxml-2.0 not found')
|
||||||
libsoup_dep = dependency('libsoup-2.4', version: '>= 2.58.0')
|
libsoup_dep = dependency('libsoup-3.0', version: '>= 3.0.0')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# *** Check if we should build with DNS-SD backend ***
|
# *** Check if we should build with DNS-SD backend ***
|
||||||
|
@ -330,7 +331,7 @@ config_h.set('HAVE_GUDEV', enable_gudev)
|
||||||
# *** Check for FUSE ***
|
# *** Check for FUSE ***
|
||||||
enable_fuse = get_option('fuse')
|
enable_fuse = get_option('fuse')
|
||||||
if enable_fuse
|
if enable_fuse
|
||||||
fuse_dep = dependency('fuse', version: '>= 2.8.0')
|
fuse_dep = dependency('fuse3', version: '>= 3.0.0')
|
||||||
endif
|
endif
|
||||||
config_h.set('HAVE_FUSE', enable_fuse)
|
config_h.set('HAVE_FUSE', enable_fuse)
|
||||||
|
|
||||||
|
@ -357,7 +358,10 @@ config_h.set('HAVE_LOGIND', enable_logind)
|
||||||
enable_afc = get_option('afc')
|
enable_afc = get_option('afc')
|
||||||
if enable_afc
|
if enable_afc
|
||||||
libimobiledevice_dep = dependency('libimobiledevice-1.0', version: '>= 1.2')
|
libimobiledevice_dep = dependency('libimobiledevice-1.0', version: '>= 1.2')
|
||||||
libplist_dep = dependency('libplist', version: '>= 0.15')
|
libplist_dep = dependency('libplist-2.0', required: false)
|
||||||
|
if not libplist_dep.found()
|
||||||
|
libplist_dep = dependency('libplist', version: '>= 0.15')
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# *** Check if we should build with GOA volume monitor ***
|
# *** Check if we should build with GOA volume monitor ***
|
||||||
|
@ -416,7 +420,7 @@ enable_google = get_option('google')
|
||||||
if enable_google
|
if enable_google
|
||||||
assert(enable_goa, 'Google backend requested but GOA is required')
|
assert(enable_goa, 'Google backend requested but GOA is required')
|
||||||
|
|
||||||
libgdata_dep = dependency('libgdata', version: '>= 0.17.11')
|
libgdata_dep = dependency('libgdata', version: '>= 0.18.0')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# *** Check for gphoto2 ***
|
# *** Check for gphoto2 ***
|
||||||
|
@ -453,10 +457,6 @@ endif
|
||||||
|
|
||||||
# *** SFTP backend ***
|
# *** SFTP backend ***
|
||||||
enable_sftp = get_option('sftp')
|
enable_sftp = get_option('sftp')
|
||||||
if enable_sftp
|
|
||||||
ssh = find_program('ssh', required: false)
|
|
||||||
assert(ssh.found(), 'SFTP backend requested but a ssh client is required')
|
|
||||||
endif
|
|
||||||
|
|
||||||
# *** Enable development utils ***
|
# *** Enable development utils ***
|
||||||
enable_devel_utils = get_option('devel_utils')
|
enable_devel_utils = get_option('devel_utils')
|
||||||
|
@ -487,37 +487,43 @@ meson.add_install_script(
|
||||||
gio_giomoduledir,
|
gio_giomoduledir,
|
||||||
)
|
)
|
||||||
|
|
||||||
output = gvfs_name + ' ' + gvfs_version + ' configuration summary:\n'
|
summary({
|
||||||
output += '\n'
|
'systemduserunitdir': systemd_systemduserunitdir,
|
||||||
output += ' systemduserunitdir: ' + systemd_systemduserunitdir + '\n'
|
'tmpfilesdir': systemd_tmpfilesdir,
|
||||||
output += ' tmpfilesdir: ' + systemd_tmpfilesdir + '\n'
|
'privileged_group': privileged_group,
|
||||||
output += '\n'
|
}, section: 'Configuration')
|
||||||
output += ' admin: ' + enable_admin.to_string() + '\n'
|
|
||||||
output += ' afc: ' + enable_afc.to_string() + '\n'
|
summary({
|
||||||
output += ' afp: ' + enable_afp.to_string() + '\n'
|
'admin': enable_admin,
|
||||||
output += ' archive: ' + enable_archive.to_string() + '\n'
|
'afc': enable_afc,
|
||||||
output += ' cdda: ' + enable_cdda.to_string() + '\n'
|
'afp': enable_afp,
|
||||||
output += ' dnssd: ' + enable_dnssd.to_string() + '\n'
|
'archive': enable_archive,
|
||||||
output += ' goa: ' + enable_goa.to_string() + '\n'
|
'cdda': enable_cdda,
|
||||||
output += ' google: ' + enable_google.to_string() + '\n'
|
'dnssd': enable_dnssd,
|
||||||
output += ' gphoto2: ' + enable_gphoto2.to_string() + '\n'
|
'goa': enable_goa,
|
||||||
output += ' http: ' + enable_http.to_string() + '\n'
|
'google': enable_google,
|
||||||
output += ' mtp: ' + enable_mtp.to_string() + '\n'
|
'gphoto2': enable_gphoto2,
|
||||||
output += ' nfs: ' + enable_nfs.to_string() + '\n'
|
'http': enable_http,
|
||||||
output += ' sftp: ' + enable_sftp.to_string() + '\n'
|
'mtp': enable_mtp,
|
||||||
output += ' smb: ' + enable_samba.to_string() + '\n'
|
'nfs': enable_nfs,
|
||||||
output += ' udisks2: ' + enable_udisks2.to_string() + '\n'
|
'sftp': enable_sftp,
|
||||||
output += '\n'
|
'smb': enable_samba,
|
||||||
output += ' bluray: ' + enable_bluray.to_string() + '\n'
|
'udisks2': enable_udisks2,
|
||||||
output += ' fuse: ' + enable_fuse.to_string() + '\n'
|
}, section: 'Backends')
|
||||||
output += ' gcr: ' + enable_gcr.to_string() + '\n'
|
|
||||||
output += ' gcrypt: ' + enable_gcrypt.to_string() + '\n'
|
summary({
|
||||||
output += ' gudev: ' + enable_gudev.to_string() + '\n'
|
'bluray': enable_bluray,
|
||||||
output += ' keyring: ' + enable_keyring.to_string() + '\n'
|
'fuse': enable_fuse,
|
||||||
output += ' logind: ' + enable_logind.to_string() + '\n'
|
'gcr': enable_gcr,
|
||||||
output += ' libusb: ' + enable_libusb.to_string() + '\n'
|
'gcrypt': enable_gcrypt,
|
||||||
output += '\n'
|
'gudev': enable_gudev,
|
||||||
output += ' devel_utils: ' + enable_devel_utils.to_string() + '\n'
|
'keyring': enable_keyring,
|
||||||
output += ' installed_tests: ' + enable_installed_tests.to_string() + '\n'
|
'logind': enable_logind,
|
||||||
output += ' man: ' + enable_man.to_string() + '\n'
|
'libusb': enable_libusb,
|
||||||
message(output)
|
}, section: 'Dependencies')
|
||||||
|
|
||||||
|
summary({
|
||||||
|
'devel_utils': enable_devel_utils,
|
||||||
|
'installed_tests': enable_installed_tests,
|
||||||
|
'man': enable_man,
|
||||||
|
})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
option('systemduserunitdir', type: 'string', value: '', description: 'custom directory for systemd user units, or \'no\' to disable')
|
option('systemduserunitdir', type: 'string', value: '', description: 'custom directory for systemd user units, or \'no\' to disable')
|
||||||
option('tmpfilesdir', type: 'string', value: '', description: 'custom directory for tmpfiles.d config files, or \'no\' to disable')
|
option('tmpfilesdir', type: 'string', value: '', description: 'custom directory for tmpfiles.d config files, or \'no\' to disable')
|
||||||
|
option('privileged_group', type: 'string', value: 'wheel', description: 'custom name for group that has elevated permissions')
|
||||||
|
|
||||||
option('admin', type: 'boolean', value: true, description: 'build with admin backend')
|
option('admin', type: 'boolean', value: true, description: 'build with admin backend')
|
||||||
option('afc', type: 'boolean', value: true, description: 'build with afc backend and volume monitor')
|
option('afc', type: 'boolean', value: true, description: 'build with afc backend and volume monitor')
|
||||||
|
|
|
@ -45,6 +45,10 @@
|
||||||
<arg type='u' name='minor' direction='in'/>
|
<arg type='u' name='minor' direction='in'/>
|
||||||
<arg type='s' name='tree' direction='out'/>
|
<arg type='s' name='tree' direction='out'/>
|
||||||
</method>
|
</method>
|
||||||
|
<signal name="AttributeChanged">
|
||||||
|
<arg type='s' name='tree_path'/>
|
||||||
|
<arg type='s' name='file_path'/>
|
||||||
|
</signal>
|
||||||
|
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem metadata service
|
Description=Virtual filesystem metadata service
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfsd-metadata
|
ExecStart=@libexecdir@/gvfsd-metadata
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.Metadata
|
BusName=org.gtk.vfs.Metadata
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -47,6 +47,7 @@ sources = files(
|
||||||
deps = [
|
deps = [
|
||||||
gio_dep,
|
gio_dep,
|
||||||
glib_dep,
|
glib_dep,
|
||||||
|
libgvfscommon_dep,
|
||||||
]
|
]
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
@ -58,7 +59,7 @@ cflags = [
|
||||||
libmetadata = static_library(
|
libmetadata = static_library(
|
||||||
'metadata',
|
'metadata',
|
||||||
sources: sources + [dbus_sources],
|
sources: sources + [dbus_sources],
|
||||||
include_directories: [top_inc, common_inc],
|
include_directories: top_inc,
|
||||||
dependencies: deps + [gio_unix_dep],
|
dependencies: deps + [gio_unix_dep],
|
||||||
c_args: cflags,
|
c_args: cflags,
|
||||||
pic: true,
|
pic: true,
|
||||||
|
@ -71,10 +72,7 @@ libmetadata_dep = declare_dependency(
|
||||||
link_with: libmetadata,
|
link_with: libmetadata,
|
||||||
)
|
)
|
||||||
|
|
||||||
deps = [
|
deps = [libmetadata_dep]
|
||||||
libgvfscommon_dep,
|
|
||||||
libmetadata_dep,
|
|
||||||
]
|
|
||||||
|
|
||||||
if enable_gudev
|
if enable_gudev
|
||||||
deps += gudev_dep
|
deps += gudev_dep
|
||||||
|
@ -104,10 +102,7 @@ if enable_devel_utils
|
||||||
app,
|
app,
|
||||||
app + '.c',
|
app + '.c',
|
||||||
include_directories: top_inc,
|
include_directories: top_inc,
|
||||||
dependencies: [
|
dependencies: libmetadata_dep,
|
||||||
libgvfscommon_dep,
|
|
||||||
libmetadata_dep,
|
|
||||||
],
|
|
||||||
c_args: cflags,
|
c_args: cflags,
|
||||||
)
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#define WRITEOUT_TIMEOUT_SECS 60
|
#define WRITEOUT_TIMEOUT_SECS 60
|
||||||
#define WRITEOUT_TIMEOUT_SECS_NFS 15
|
#define WRITEOUT_TIMEOUT_SECS_NFS 15
|
||||||
|
#define WRITEOUT_TIMEOUT_SECS_DBUS 1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *filename;
|
char *filename;
|
||||||
|
@ -50,11 +51,19 @@ typedef struct {
|
||||||
guint writeout_timeout;
|
guint writeout_timeout;
|
||||||
} TreeInfo;
|
} TreeInfo;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *treefile;
|
||||||
|
gchar *path;
|
||||||
|
GVfsMetadata *object;
|
||||||
|
guint timeout_id;
|
||||||
|
} BusNotificationInfo;
|
||||||
|
|
||||||
static GHashTable *tree_infos = NULL;
|
static GHashTable *tree_infos = NULL;
|
||||||
static GVfsMetadata *skeleton = NULL;
|
static GVfsMetadata *skeleton = NULL;
|
||||||
#ifdef HAVE_GUDEV
|
#ifdef HAVE_GUDEV
|
||||||
static GUdevClient *gudev_client = NULL;
|
static GUdevClient *gudev_client = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
static GList *dbus_notification_list = NULL;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tree_info_free (TreeInfo *info)
|
tree_info_free (TreeInfo *info)
|
||||||
|
@ -105,8 +114,78 @@ flush_single (const gchar *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flush_all ()
|
free_bus_notification_info (BusNotificationInfo *info)
|
||||||
{
|
{
|
||||||
|
dbus_notification_list = g_list_remove (dbus_notification_list,
|
||||||
|
info);
|
||||||
|
g_object_unref (info->object);
|
||||||
|
g_source_remove (info->timeout_id);
|
||||||
|
g_free (info->path);
|
||||||
|
g_free (info->treefile);
|
||||||
|
g_free (info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
notify_attribute_change (gpointer data)
|
||||||
|
{
|
||||||
|
BusNotificationInfo *info;
|
||||||
|
|
||||||
|
info = (BusNotificationInfo *) data;
|
||||||
|
gvfs_metadata_emit_attribute_changed (info->object,
|
||||||
|
info->treefile,
|
||||||
|
info->path);
|
||||||
|
free_bus_notification_info (info);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_attribute_change (GVfsMetadata *object,
|
||||||
|
const gchar *treefile,
|
||||||
|
const gchar *path)
|
||||||
|
{
|
||||||
|
GList *iter;
|
||||||
|
BusNotificationInfo *info;
|
||||||
|
|
||||||
|
for (iter = dbus_notification_list; iter != NULL; iter = iter->next)
|
||||||
|
{
|
||||||
|
info = iter->data;
|
||||||
|
if (g_str_equal (info->treefile, treefile) &&
|
||||||
|
g_str_equal (info->path, path))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iter == NULL)
|
||||||
|
{
|
||||||
|
info = g_new0 (BusNotificationInfo, 1);
|
||||||
|
info->treefile = g_strdup (treefile);
|
||||||
|
info->path = g_strdup (path);
|
||||||
|
info->object = g_object_ref (object);
|
||||||
|
dbus_notification_list = g_list_prepend (dbus_notification_list,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_source_remove (info->timeout_id);
|
||||||
|
}
|
||||||
|
info->timeout_id = g_timeout_add_seconds (WRITEOUT_TIMEOUT_SECS_DBUS,
|
||||||
|
notify_attribute_change,
|
||||||
|
info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
flush_all (gboolean send_pending_notifications)
|
||||||
|
{
|
||||||
|
BusNotificationInfo *info;
|
||||||
|
|
||||||
|
while (dbus_notification_list != NULL)
|
||||||
|
{
|
||||||
|
info = (BusNotificationInfo *) dbus_notification_list->data;
|
||||||
|
if (send_pending_notifications)
|
||||||
|
notify_attribute_change (info);
|
||||||
|
else
|
||||||
|
free_bus_notification_info (info);
|
||||||
|
}
|
||||||
g_hash_table_foreach (tree_infos, (GHFunc) flush_single, NULL);
|
g_hash_table_foreach (tree_infos, (GHFunc) flush_single, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +301,7 @@ handle_set (GVfsMetadata *object,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
emit_attribute_change (object, arg_treefile, arg_path);
|
||||||
gvfs_metadata_complete_set (object, invocation);
|
gvfs_metadata_complete_set (object, invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +337,7 @@ handle_remove (GVfsMetadata *object,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit_attribute_change (object, arg_treefile, arg_path);
|
||||||
tree_info_schedule_writeout (info);
|
tree_info_schedule_writeout (info);
|
||||||
gvfs_metadata_complete_remove (object, invocation);
|
gvfs_metadata_complete_remove (object, invocation);
|
||||||
|
|
||||||
|
@ -297,6 +378,8 @@ handle_move (GVfsMetadata *object,
|
||||||
/* Remove source if copy succeeded (ignoring errors) */
|
/* Remove source if copy succeeded (ignoring errors) */
|
||||||
meta_tree_remove (info->tree, arg_path);
|
meta_tree_remove (info->tree, arg_path);
|
||||||
|
|
||||||
|
emit_attribute_change (object, arg_treefile, arg_path);
|
||||||
|
emit_attribute_change (object, arg_treefile, arg_dest_path);
|
||||||
tree_info_schedule_writeout (info);
|
tree_info_schedule_writeout (info);
|
||||||
gvfs_metadata_complete_move (object, invocation);
|
gvfs_metadata_complete_move (object, invocation);
|
||||||
|
|
||||||
|
@ -344,7 +427,7 @@ on_name_lost (GDBusConnection *connection,
|
||||||
GMainLoop *loop = user_data;
|
GMainLoop *loop = user_data;
|
||||||
|
|
||||||
/* means that someone has claimed our name (we allow replacement) */
|
/* means that someone has claimed our name (we allow replacement) */
|
||||||
flush_all ();
|
flush_all (TRUE);
|
||||||
g_main_loop_quit (loop);
|
g_main_loop_quit (loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +440,7 @@ on_connection_closed (GDBusConnection *connection,
|
||||||
GMainLoop *loop = user_data;
|
GMainLoop *loop = user_data;
|
||||||
|
|
||||||
/* session bus died */
|
/* session bus died */
|
||||||
flush_all ();
|
flush_all (FALSE);
|
||||||
g_main_loop_quit (loop);
|
g_main_loop_quit (loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1234,7 +1234,7 @@ meta_builder_write (MetaBuilder *builder,
|
||||||
|
|
||||||
data = mmap (NULL, RANDOM_TAG_OFFSET + 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
|
data = mmap (NULL, RANDOM_TAG_OFFSET + 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
|
||||||
|
|
||||||
if (data)
|
if (data != MAP_FAILED)
|
||||||
{
|
{
|
||||||
old_tag = GUINT32_FROM_BE (*(guint32 *)(data + RANDOM_TAG_OFFSET));
|
old_tag = GUINT32_FROM_BE (*(guint32 *)(data + RANDOM_TAG_OFFSET));
|
||||||
*(guint32 *)(data + ROTATED_OFFSET) = 0xffffffff;
|
*(guint32 *)(data + ROTATED_OFFSET) = 0xffffffff;
|
||||||
|
|
|
@ -170,7 +170,7 @@ GVfsMetadata *
|
||||||
meta_tree_get_metadata_proxy ()
|
meta_tree_get_metadata_proxy ()
|
||||||
{
|
{
|
||||||
static GVfsMetadata *proxy = NULL;
|
static GVfsMetadata *proxy = NULL;
|
||||||
static volatile gsize initialized = 0;
|
static gsize initialized = 0;
|
||||||
|
|
||||||
if (g_once_init_enter (&initialized))
|
if (g_once_init_enter (&initialized))
|
||||||
{
|
{
|
||||||
|
@ -451,15 +451,7 @@ meta_tree_init (MetaTree *tree)
|
||||||
if (memcmp (tree->header->magic, MAGIC, MAGIC_LEN) != 0)
|
if (memcmp (tree->header->magic, MAGIC, MAGIC_LEN) != 0)
|
||||||
{
|
{
|
||||||
g_warning ("can't init metadata tree %s: wrong magic", tree->filename);
|
g_warning ("can't init metadata tree %s: wrong magic", tree->filename);
|
||||||
if (!tree->for_write)
|
goto err;
|
||||||
goto err;
|
|
||||||
|
|
||||||
meta_tree_clear (tree);
|
|
||||||
|
|
||||||
if (g_unlink (tree->filename) != 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
goto retry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree->header->major != MAJOR_VERSION)
|
if (tree->header->major != MAJOR_VERSION)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service - Apple File Conduit monitor
|
Description=Virtual filesystem service - Apple File Conduit monitor
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfs-afc-volume-monitor
|
ExecStart=@libexecdir@/gvfs-afc-volume-monitor
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.AfcVolumeMonitor
|
BusName=org.gtk.vfs.AfcVolumeMonitor
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -99,8 +99,6 @@ account_attention_needed_cb (GObject *_object, GParamSpec *pspec, gpointer user_
|
||||||
g_clear_object (&self->mount);
|
g_clear_object (&self->mount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
g_volume_mount (G_VOLUME (self), G_MOUNT_MOUNT_NONE, NULL, NULL, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
|
@ -326,7 +326,7 @@ get_goa_client_sync (GError **error)
|
||||||
{
|
{
|
||||||
static GoaClient *client = NULL;
|
static GoaClient *client = NULL;
|
||||||
static GError *_error = NULL;
|
static GError *_error = NULL;
|
||||||
static volatile gsize initialized = 0;
|
static gsize initialized = 0;
|
||||||
|
|
||||||
if (g_once_init_enter (&initialized))
|
if (g_once_init_enter (&initialized))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service - GNOME Online Accounts monitor
|
Description=Virtual filesystem service - GNOME Online Accounts monitor
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfs-goa-volume-monitor
|
ExecStart=@libexecdir@/gvfs-goa-volume-monitor
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.GoaVolumeMonitor
|
BusName=org.gtk.vfs.GoaVolumeMonitor
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service - digital camera monitor
|
Description=Virtual filesystem service - digital camera monitor
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfs-gphoto2-volume-monitor
|
ExecStart=@libexecdir@/gvfs-gphoto2-volume-monitor
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.GPhoto2VolumeMonitor
|
BusName=org.gtk.vfs.GPhoto2VolumeMonitor
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
subdir('proxy')
|
subdir('proxy')
|
||||||
|
|
||||||
# [[service name suffix, install monitor test data]]
|
# [[service name suffix, install monitor test data]]
|
||||||
monitors = []
|
monitors = {}
|
||||||
|
|
||||||
if enable_afc
|
if enable_afc
|
||||||
monitors += [['Afc', true]]
|
monitors += {'Afc': true}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if enable_goa
|
if enable_goa
|
||||||
monitors += [['Goa', false]]
|
monitors += {'Goa': false}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if enable_gphoto2
|
if enable_gphoto2
|
||||||
monitors += [['GPhoto2', true]]
|
monitors += {'GPhoto2': true}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if enable_mtp
|
if enable_mtp
|
||||||
monitors += [['MTP', false]]
|
monitors += {'MTP': false}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if enable_udisks2
|
if enable_udisks2
|
||||||
monitors += [['UDisks2', true]]
|
monitors += {'UDisks2': true}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
monitors_test_data = []
|
monitors_test_data = []
|
||||||
foreach monitor: monitors
|
foreach monitor, monitor_test: monitors
|
||||||
monitor_name = monitor[0].to_lower()
|
monitor_name = monitor.to_lower()
|
||||||
|
|
||||||
dbus_service = '@0@.@1@VolumeMonitor'.format(gvfs_namespace, monitor[0])
|
dbus_service = '@0@.@1@VolumeMonitor'.format(gvfs_namespace, monitor)
|
||||||
dbus_exec = 'gvfs-@0@-volume-monitor'.format(monitor_name)
|
dbus_exec = 'gvfs-@0@-volume-monitor'.format(monitor_name)
|
||||||
dbus_systemd_service = ''
|
dbus_systemd_service = ''
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ foreach monitor: monitors
|
||||||
install_dir: dbus_session_bus_services_dir,
|
install_dir: dbus_session_bus_services_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
if monitor[1]
|
if monitor_test
|
||||||
monitors_test_data += [monitor_data, monitor_service]
|
monitors_test_data += [monitor_data, monitor_service]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service - Media Transfer Protocol monitor
|
Description=Virtual filesystem service - Media Transfer Protocol monitor
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfs-mtp-volume-monitor
|
ExecStart=@libexecdir@/gvfs-mtp-volume-monitor
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.MTPVolumeMonitor
|
BusName=org.gtk.vfs.MTPVolumeMonitor
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Virtual filesystem service - disk device monitor
|
Description=Virtual filesystem service - disk device monitor
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=@libexecdir@/gvfs-udisks2-volume-monitor
|
ExecStart=@libexecdir@/gvfs-udisks2-volume-monitor
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.gtk.vfs.UDisks2VolumeMonitor
|
BusName=org.gtk.vfs.UDisks2VolumeMonitor
|
||||||
|
Slice=session.slice
|
||||||
|
|
|
@ -580,7 +580,6 @@ typedef struct {
|
||||||
GDrive *drive;
|
GDrive *drive;
|
||||||
|
|
||||||
GMountOperation *op;
|
GMountOperation *op;
|
||||||
gboolean op_aborted;
|
|
||||||
gboolean show_processes_up;
|
gboolean show_processes_up;
|
||||||
|
|
||||||
guint unmount_timer_id;
|
guint unmount_timer_id;
|
||||||
|
@ -687,13 +686,6 @@ unmount_notify_op_show_processes (UnmountNotifyData *data)
|
||||||
data->show_processes_up = TRUE;
|
data->show_processes_up = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
unmount_notify_op_aborted (UnmountNotifyData *data)
|
|
||||||
{
|
|
||||||
unmount_notify_stop_timer (data);
|
|
||||||
data->op_aborted = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
unmount_notify_op_reply (UnmountNotifyData *data,
|
unmount_notify_op_reply (UnmountNotifyData *data,
|
||||||
GMountOperationResult result)
|
GMountOperationResult result)
|
||||||
|
@ -704,7 +696,7 @@ unmount_notify_op_reply (UnmountNotifyData *data,
|
||||||
|
|
||||||
if ((result == G_MOUNT_OPERATION_HANDLED && data->show_processes_up && choice == 1) ||
|
if ((result == G_MOUNT_OPERATION_HANDLED && data->show_processes_up && choice == 1) ||
|
||||||
result == G_MOUNT_OPERATION_ABORTED)
|
result == G_MOUNT_OPERATION_ABORTED)
|
||||||
unmount_notify_op_aborted (data);
|
unmount_notify_stop_timer (data);
|
||||||
else if (result == G_MOUNT_OPERATION_HANDLED)
|
else if (result == G_MOUNT_OPERATION_HANDLED)
|
||||||
unmount_notify_ensure_timer (data);
|
unmount_notify_ensure_timer (data);
|
||||||
|
|
||||||
|
@ -748,7 +740,7 @@ unmount_notify_data_for_operation (GMountOperation *op,
|
||||||
unmount_notify_data_free);
|
unmount_notify_data_free);
|
||||||
|
|
||||||
g_signal_connect_swapped (data->op, "aborted",
|
g_signal_connect_swapped (data->op, "aborted",
|
||||||
G_CALLBACK (unmount_notify_op_aborted), data);
|
G_CALLBACK (unmount_notify_stop_timer), data);
|
||||||
g_signal_connect_swapped (data->op, "show-processes",
|
g_signal_connect_swapped (data->op, "show-processes",
|
||||||
G_CALLBACK (unmount_notify_op_show_processes), data);
|
G_CALLBACK (unmount_notify_op_show_processes), data);
|
||||||
g_signal_connect_swapped (data->op, "reply",
|
g_signal_connect_swapped (data->op, "reply",
|
||||||
|
@ -780,7 +772,7 @@ gvfs_udisks2_unmount_notify_stop (GMountOperation *op,
|
||||||
|
|
||||||
unmount_notify_stop_timer (data);
|
unmount_notify_stop_timer (data);
|
||||||
|
|
||||||
if (data->op_aborted || unmount_failed)
|
if (unmount_failed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
name = unmount_notify_get_name (data);
|
name = unmount_notify_get_name (data);
|
||||||
|
|
|
@ -1496,13 +1496,14 @@ do_unlock (GTask *task)
|
||||||
task);
|
task);
|
||||||
if (g_strcmp0 (type, "crypto_unknown") == 0)
|
if (g_strcmp0 (type, "crypto_unknown") == 0)
|
||||||
/* Translators: %s is the description of the volume that is being unlocked */
|
/* Translators: %s is the description of the volume that is being unlocked */
|
||||||
message = g_strdup_printf (_("Enter a passphrase to unlock the volume\n"
|
message = g_strdup_printf (_("Authentication Required\n"
|
||||||
"The volume %s might be a VeraCrypt volume as it contains random data."),
|
"A passphrase is needed to access encrypted data on “%s”.\n"
|
||||||
|
"The volume might be a VeraCrypt volume as it contains random data."),
|
||||||
data->desc_of_encrypted_to_unlock);
|
data->desc_of_encrypted_to_unlock);
|
||||||
else
|
else
|
||||||
/* Translators: %s is the description of the volume that is being unlocked */
|
/* Translators: %s is the description of the volume that is being unlocked */
|
||||||
message = g_strdup_printf (_("Enter a passphrase to unlock the volume\n"
|
message = g_strdup_printf (_("Authentication Required\n"
|
||||||
"The passphrase is needed to access encrypted data on %s."),
|
"A passphrase is needed to access encrypted data on “%s”."),
|
||||||
data->desc_of_encrypted_to_unlock);
|
data->desc_of_encrypted_to_unlock);
|
||||||
|
|
||||||
pw_ask_flags = G_ASK_PASSWORD_NEED_PASSWORD | G_ASK_PASSWORD_SAVING_SUPPORTED;
|
pw_ask_flags = G_ASK_PASSWORD_NEED_PASSWORD | G_ASK_PASSWORD_SAVING_SUPPORTED;
|
||||||
|
|
|
@ -437,7 +437,7 @@ get_udisks_client_sync (GError **error)
|
||||||
{
|
{
|
||||||
static UDisksClient *_client = NULL;
|
static UDisksClient *_client = NULL;
|
||||||
static GError *_error = NULL;
|
static GError *_error = NULL;
|
||||||
static volatile gsize initialized = 0;
|
static gsize initialized = 0;
|
||||||
|
|
||||||
if (g_once_init_enter (&initialized))
|
if (g_once_init_enter (&initialized))
|
||||||
{
|
{
|
||||||
|
@ -606,37 +606,6 @@ update_all (GVfsUDisks2VolumeMonitor *monitor,
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static GUnixMountPoint *
|
|
||||||
get_mount_point_for_mount (GUnixMountEntry *mount_entry)
|
|
||||||
{
|
|
||||||
GUnixMountPoint *ret = NULL;
|
|
||||||
GList *mount_points, *l;
|
|
||||||
|
|
||||||
mount_points = g_unix_mount_points_get (NULL);
|
|
||||||
for (l = mount_points; l != NULL; l = l->next)
|
|
||||||
{
|
|
||||||
GUnixMountPoint *mount_point = l->data;
|
|
||||||
if (g_strcmp0 (g_unix_mount_get_mount_path (mount_entry),
|
|
||||||
g_unix_mount_point_get_mount_path (mount_point)) == 0)
|
|
||||||
{
|
|
||||||
ret = mount_point;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
for (l = mount_points; l != NULL; l = l->next)
|
|
||||||
{
|
|
||||||
GUnixMountPoint *mount_point = l->data;
|
|
||||||
if (G_LIKELY (mount_point != ret))
|
|
||||||
g_unix_mount_point_free (mount_point);
|
|
||||||
}
|
|
||||||
g_list_free (mount_points);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
should_include (const gchar *mount_path,
|
should_include (const gchar *mount_path,
|
||||||
const gchar *options)
|
const gchar *options)
|
||||||
|
@ -739,7 +708,7 @@ should_include_mount (GVfsUDisks2VolumeMonitor *monitor,
|
||||||
* in prior to g_unix_mount_get_options to keep support of "comment=" options,
|
* in prior to g_unix_mount_get_options to keep support of "comment=" options,
|
||||||
* see https://gitlab.gnome.org/GNOME/gvfs/issues/348.
|
* see https://gitlab.gnome.org/GNOME/gvfs/issues/348.
|
||||||
*/
|
*/
|
||||||
mount_point = get_mount_point_for_mount (mount_entry);
|
mount_point = g_unix_mount_point_at (g_unix_mount_get_mount_path (mount_entry), NULL);
|
||||||
if (mount_point != NULL)
|
if (mount_point != NULL)
|
||||||
{
|
{
|
||||||
ret = should_include_mount_point (monitor, mount_point);
|
ret = should_include_mount_point (monitor, mount_point);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# please keep this list sorted alphabetically
|
# please keep this list sorted alphabetically
|
||||||
|
ab
|
||||||
af
|
af
|
||||||
ar
|
ar
|
||||||
as
|
as
|
||||||
|
@ -33,8 +34,10 @@ hr
|
||||||
hu
|
hu
|
||||||
hi
|
hi
|
||||||
id
|
id
|
||||||
|
ie
|
||||||
it
|
it
|
||||||
ja
|
ja
|
||||||
|
ka
|
||||||
kk
|
kk
|
||||||
kn
|
kn
|
||||||
ko
|
ko
|
||||||
|
|
950
po/en_GB.po
950
po/en_GB.po
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue