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
|
||||
|
||||
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,
|
||||
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
|
||||
=======================
|
||||
* 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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
For questions use gvfs mailing list [gvfs-list@gnome.org](mailto:gvfs-list@gnome.org).
|
||||
See https://mail.gnome.org/mailman/listinfo/gvfs-list for subscription info.
|
||||
Alternatively you use irc://irc.gnome.org/nautilus.
|
||||
For questions use [GNOME Discourse](https://discourse.gnome.org/).
|
||||
|
|
|
@ -438,6 +438,17 @@ create_proxy_for_file2 (GFile *file1,
|
|||
}
|
||||
|
||||
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)
|
||||
goto out;
|
||||
|
||||
|
@ -613,8 +624,19 @@ async_got_connection_cb (GDBusConnection *connection,
|
|||
|
||||
if (connection == NULL)
|
||||
{
|
||||
/* TODO: we should probably test if we really want a session bus;
|
||||
* for now, this code is on par with the old dbus code */
|
||||
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_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_task_get_cancellable (data->task),
|
||||
bus_get_cb,
|
||||
|
@ -2689,14 +2711,6 @@ file_transfer (GFile *source,
|
|||
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)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
g_printerr ("Error getting connection for monitoring: %s (%s, %d)\n",
|
||||
|
|
|
@ -315,8 +315,19 @@ async_got_connection_cb (GDBusConnection *connection,
|
|||
|
||||
if (connection == NULL)
|
||||
{
|
||||
/* TODO: we should probably test if we really want a session bus;
|
||||
* for now, this code is on par with the old dbus code */
|
||||
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 (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_task_get_cancellable (task),
|
||||
bus_get_cb,
|
||||
|
|
|
@ -1434,7 +1434,7 @@ g_daemon_vfs_deserialize_icon (GVfs *vfs,
|
|||
GDBusConnection *
|
||||
_g_daemon_vfs_get_async_bus (void)
|
||||
{
|
||||
return the_vfs ? the_vfs->async_bus : NULL;
|
||||
return the_vfs->async_bus;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
@ -31,12 +31,14 @@
|
|||
#include <errno.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "gvfsdaemondbus.h"
|
||||
#include <gvfsdaemonprotocol.h>
|
||||
#include <gdaemonvfs.h>
|
||||
#include <gvfsdbus.h>
|
||||
#include <gvfsutils.h>
|
||||
|
||||
/* Extra vfs-specific data for GDBusConnections */
|
||||
typedef struct {
|
||||
|
@ -156,6 +158,7 @@ set_connection_for_async (GDBusConnection *connection, const char *dbus_id)
|
|||
typedef struct {
|
||||
char *dbus_id;
|
||||
|
||||
GVfsDBusDaemon *proxy;
|
||||
GDBusConnection *connection;
|
||||
GCancellable *cancellable;
|
||||
|
||||
|
@ -174,6 +177,7 @@ async_call_finish (AsyncDBusCall *async_call)
|
|||
async_call->io_error,
|
||||
async_call->callback_data);
|
||||
|
||||
g_clear_object (&async_call->proxy);
|
||||
g_clear_object (&async_call->connection);
|
||||
g_clear_object (&async_call->cancellable);
|
||||
g_clear_error (&async_call->io_error);
|
||||
|
@ -260,32 +264,67 @@ async_get_connection_response (GVfsDBusDaemon *proxy,
|
|||
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
|
||||
open_connection_async_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVfsDBusDaemon *proxy;
|
||||
AsyncDBusCall *async_call = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
proxy = gvfs_dbus_daemon_proxy_new_finish (res, &error);
|
||||
if (proxy == NULL)
|
||||
g_autofree gchar *socket_dir_path = NULL;
|
||||
g_autoptr (GFile) socket_dir = 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);
|
||||
g_error_free (error);
|
||||
async_call_finish (async_call);
|
||||
return;
|
||||
}
|
||||
|
||||
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_TIMEOUT_MSECS);
|
||||
|
||||
gvfs_dbus_daemon_call_get_connection (proxy,
|
||||
async_call->cancellable,
|
||||
(GAsyncReadyCallback) async_get_connection_response,
|
||||
async_call);
|
||||
|
||||
g_object_unref (proxy);
|
||||
|
||||
/* This is needed to prevent socket leaks. */
|
||||
socket_dir_path = gvfs_get_socket_dir ();
|
||||
socket_dir = g_file_new_for_path (socket_dir_path);
|
||||
g_file_query_info_async (socket_dir,
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
async_call->cancellable,
|
||||
socket_dir_query_info_cb,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -522,6 +561,9 @@ _g_dbus_connection_get_sync (const char *dbus_id,
|
|||
gchar *address1;
|
||||
GVfsDBusDaemon *daemon_proxy;
|
||||
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))
|
||||
return NULL;
|
||||
|
@ -591,6 +633,26 @@ _g_dbus_connection_get_sync (const char *dbus_id,
|
|||
if (daemon_proxy == 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;
|
||||
res = gvfs_dbus_daemon_call_get_connection_sync (daemon_proxy,
|
||||
&address1,
|
||||
|
|
|
@ -43,7 +43,8 @@
|
|||
#include <gvfsdbus.h>
|
||||
#include <gvfsutils.h>
|
||||
|
||||
#define FUSE_USE_VERSION 26
|
||||
#define FUSE_USE_VERSION 30
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
|
||||
|
@ -859,7 +860,7 @@ getattr_for_file_handle (FileHandle *fh, struct stat *sbuf)
|
|||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
if (result < 0)
|
||||
file_handle_unref (fh);
|
||||
|
||||
/* The added reference to the file handle is released in vfs_release() */
|
||||
return result;
|
||||
}
|
||||
|
@ -1581,12 +1585,12 @@ readdir_for_file (GFile *base_file, gpointer buf, fuse_fill_dir_t filler)
|
|||
return result;
|
||||
}
|
||||
|
||||
filler (buf, ".", NULL, 0);
|
||||
filler (buf, "..", NULL, 0);
|
||||
filler (buf, ".", NULL, 0, 0);
|
||||
filler (buf, "..", NULL, 0, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1601,7 @@ readdir_for_file (GFile *base_file, gpointer buf, fuse_fill_dir_t filler)
|
|||
|
||||
static gint
|
||||
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;
|
||||
gint result = 0;
|
||||
|
@ -1610,8 +1614,8 @@ vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offs
|
|||
|
||||
/* Mount list */
|
||||
|
||||
filler (buf, ".", NULL, 0);
|
||||
filler (buf, "..", NULL, 0);
|
||||
filler (buf, ".", NULL, 0, 0);
|
||||
filler (buf, "..", NULL, 0, 0);
|
||||
|
||||
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;
|
||||
|
||||
filler (buf, mount_record->name, NULL, 0);
|
||||
filler (buf, mount_record->name, NULL, 0, 0);
|
||||
}
|
||||
|
||||
mount_list_unlock ();
|
||||
|
@ -1643,13 +1647,21 @@ vfs_readdir (const gchar *path, gpointer buf, fuse_fill_dir_t filler, off_t offs
|
|||
}
|
||||
|
||||
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 *new_file;
|
||||
GFileCopyFlags flags = G_FILE_COPY_OVERWRITE;
|
||||
GError *error = NULL;
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -2072,6 +2084,15 @@ vfs_truncate (const gchar *path, off_t size)
|
|||
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
|
||||
vfs_symlink (const gchar *path_old, const gchar *path_new)
|
||||
{
|
||||
|
@ -2178,7 +2199,7 @@ vfs_access (const gchar *path, gint mode)
|
|||
}
|
||||
|
||||
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;
|
||||
GError *error = NULL;
|
||||
|
@ -2253,7 +2274,7 @@ vfs_utimens (const gchar *path, const struct timespec tv [2])
|
|||
}
|
||||
|
||||
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;
|
||||
GError *error = NULL;
|
||||
|
@ -2376,7 +2397,7 @@ register_fuse_cb (GVfsDBusMountTracker *proxy,
|
|||
}
|
||||
|
||||
static gpointer
|
||||
vfs_init (struct fuse_conn_info *conn)
|
||||
vfs_init (struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||
{
|
||||
GVfsDBusMountTracker *proxy;
|
||||
GError *error;
|
||||
|
@ -2452,11 +2473,7 @@ vfs_init (struct fuse_conn_info *conn)
|
|||
conn->want |= FUSE_CAP_ATOMIC_O_TRUNC;
|
||||
|
||||
/* Prevent out-of-order readahead */
|
||||
conn->async_read = 0;
|
||||
|
||||
/* 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;
|
||||
conn->want &= ~FUSE_CAP_ASYNC_READ;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2503,8 +2520,7 @@ static struct fuse_operations vfs_oper =
|
|||
.unlink = vfs_unlink,
|
||||
.mkdir = vfs_mkdir,
|
||||
.rmdir = vfs_rmdir,
|
||||
.ftruncate = vfs_ftruncate,
|
||||
.truncate = vfs_truncate,
|
||||
.truncate = vfs_truncate_dispatch,
|
||||
.symlink = vfs_symlink,
|
||||
.access = vfs_access,
|
||||
.utimens = vfs_utimens,
|
||||
|
@ -2516,6 +2532,7 @@ static struct fuse_operations vfs_oper =
|
|||
.getxattr = vfs_getxattr,
|
||||
.listxattr = vfs_listxattr,
|
||||
.removexattr = vfs_removexattr,
|
||||
.ftruncate = vfs_ftruncate,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -2537,35 +2554,65 @@ gint
|
|||
main (gint argc, gchar *argv [])
|
||||
{
|
||||
struct fuse *fuse;
|
||||
struct fuse_chan *ch;
|
||||
struct fuse_session *se;
|
||||
char *mountpoint;
|
||||
int multithreaded;
|
||||
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,
|
||||
&multithreaded, NULL /* user data */);
|
||||
if (fuse_opt_parse (&args, NULL, NULL, NULL) == -1)
|
||||
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)
|
||||
return 1;
|
||||
|
||||
if (multithreaded)
|
||||
res = fuse_loop_mt (fuse);
|
||||
else
|
||||
res = fuse_loop (fuse);
|
||||
if (fuse_mount (fuse, opts.mountpoint) != 0)
|
||||
return 1;
|
||||
|
||||
if (fuse_daemonize (opts.foreground) != 0)
|
||||
return 1;
|
||||
|
||||
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 */
|
||||
set_custom_signal_handlers (SIG_IGN);
|
||||
fuse_remove_signal_handlers (se);
|
||||
|
||||
fuse_unmount (mountpoint, ch);
|
||||
fuse_unmount (fuse);
|
||||
fuse_destroy (fuse);
|
||||
free (mountpoint);
|
||||
free (opts.mountpoint);
|
||||
fuse_opt_free_args (&args);
|
||||
|
||||
if (res == -1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,17 @@ create_proxy_for_icon (GVfsIcon *vfs_icon,
|
|||
goto out;
|
||||
|
||||
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)
|
||||
goto out;
|
||||
|
||||
|
@ -196,20 +207,9 @@ async_proxy_new_cb (GObject *source_object,
|
|||
}
|
||||
|
||||
static void
|
||||
async_got_connection_cb (GDBusConnection *connection,
|
||||
GError *io_error,
|
||||
gpointer callback_data)
|
||||
async_construct_proxy (GDBusConnection *connection,
|
||||
AsyncPathCall *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);
|
||||
gvfs_dbus_mount_proxy_new (connection,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
async_got_mount_info (GMountInfo *mount_info,
|
||||
gpointer _data,
|
||||
|
|
|
@ -245,7 +245,21 @@ g_vfs_decode_uri (const char *uri)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ sources = uri_parser_sources + uri_utils + files(
|
|||
|
||||
deps = [
|
||||
gio_unix_dep,
|
||||
libgvfscommon_dep,
|
||||
libmetadata_dep,
|
||||
]
|
||||
|
||||
|
|
|
@ -129,19 +129,16 @@ gvfs_setup_debug_handler (void)
|
|||
gboolean
|
||||
gvfs_is_ipv6 (const char *host)
|
||||
{
|
||||
const char *p = host;
|
||||
|
||||
g_return_val_if_fail (host != NULL, FALSE);
|
||||
|
||||
if (*p != '[')
|
||||
return FALSE;
|
||||
|
||||
while (++p)
|
||||
if (!g_ascii_isxdigit (*p) && *p != ':')
|
||||
break;
|
||||
|
||||
if (*p != ']' || *(p + 1) != '\0')
|
||||
if (*host != '[' || host[strlen (host) - 1] != ']')
|
||||
return FALSE;
|
||||
|
||||
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);
|
||||
|
||||
gboolean gvfs_is_ipv6 (const char *host);
|
||||
gchar * gvfs_get_socket_dir (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[Mount]
|
||||
Type=admin
|
||||
# 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
|
||||
DBusName=org.gtk.vfs.mountpoint_admin
|
||||
MountPerClient=true
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfsd
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.Daemon
|
||||
Slice=session.slice
|
||||
|
|
|
@ -1053,22 +1053,17 @@ g_vfs_afp_server_login (GVfsAfpServer *server,
|
|||
gboolean aborted;
|
||||
|
||||
g_free (prompt);
|
||||
g_clear_error (&err);
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
if (err)
|
||||
{
|
||||
g_string_append_printf (str, "%s\n", err->message);
|
||||
g_clear_error (&err);
|
||||
}
|
||||
|
||||
/* create prompt */
|
||||
if (initial_user)
|
||||
/* translators: %s here is the hostname */
|
||||
g_string_append_printf (str, _("Enter your password for the server “%s”."), server_name);
|
||||
/* Translators: the first %s is the username, the second the host name */
|
||||
g_string_append_printf (str, _("Authentication Required\nEnter password for “%s” on “%s”:"), initial_user, server_name);
|
||||
else
|
||||
/* translators: %s here is the hostname */
|
||||
g_string_append_printf (str, _("Enter your name and password for the server “%s”."), server_name);
|
||||
/* Translators: %s here is the hostname */
|
||||
g_string_append_printf (str, _("Authentication Required\nEnter user and password for “%s”:"), server_name);
|
||||
|
||||
prompt = g_string_free (str, FALSE);
|
||||
|
||||
|
|
|
@ -524,6 +524,8 @@ get_thumbnail_attributes (const char *uri,
|
|||
GChecksum *checksum;
|
||||
char *filename;
|
||||
char *basename;
|
||||
const char *size_dirs[4] = { "xx-large", "x-large", "large", "normal" };
|
||||
gsize i;
|
||||
|
||||
checksum = g_checksum_new (G_CHECKSUM_MD5);
|
||||
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);
|
||||
g_checksum_free (checksum);
|
||||
|
||||
filename = g_build_filename (g_get_user_cache_dir (),
|
||||
"thumbnails", "large", basename,
|
||||
NULL);
|
||||
for (i = 0; i < G_N_ELEMENTS (size_dirs); i++)
|
||||
{
|
||||
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);
|
||||
else
|
||||
{
|
||||
g_free (filename);
|
||||
filename = g_build_filename (g_get_user_cache_dir (),
|
||||
"thumbnails", "normal", basename,
|
||||
"thumbnails", "fail",
|
||||
"gnome-thumbnail-factory",
|
||||
basename,
|
||||
NULL);
|
||||
|
||||
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
||||
g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH, filename);
|
||||
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_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED, TRUE);
|
||||
}
|
||||
|
||||
g_free (basename);
|
||||
g_free (filename);
|
||||
}
|
||||
|
|
|
@ -95,6 +95,15 @@ check_permission (GVfsBackendAdmin *self,
|
|||
invocation = dbus_job->invocation;
|
||||
connection = g_dbus_method_invocation_get_connection (invocation);
|
||||
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);
|
||||
if (error != NULL)
|
||||
|
@ -807,6 +816,36 @@ do_move (GVfsBackend *backend,
|
|||
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
|
||||
do_pull (GVfsBackend *backend,
|
||||
GVfsJobPull *pull_job,
|
||||
|
@ -852,6 +891,40 @@ do_pull (GVfsBackend *backend,
|
|||
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
|
||||
do_query_settable_attributes (GVfsBackend *backend,
|
||||
GVfsJobQueryAttributes *query_job,
|
||||
|
@ -972,7 +1045,9 @@ g_vfs_backend_admin_class_init (GVfsBackendAdminClass * klass)
|
|||
backend_class->set_attribute = do_set_attribute;
|
||||
backend_class->delete = do_delete;
|
||||
backend_class->move = do_move;
|
||||
backend_class->copy = do_copy;
|
||||
backend_class->pull = do_pull;
|
||||
backend_class->push = do_push;
|
||||
backend_class->query_settable_attributes = do_query_settable_attributes;
|
||||
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 *runtime_dir = NULL;
|
||||
static GOptionEntry entries[] = {
|
||||
{ "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 }
|
||||
};
|
||||
|
||||
|
@ -1068,4 +1145,7 @@ g_vfs_backend_admin_pre_setup (int *argc,
|
|||
|
||||
acquire_caps (uid);
|
||||
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:
|
||||
* %s is the device name. 'Try again' is the caption of the button
|
||||
* 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)
|
||||
{
|
||||
|
@ -582,7 +582,7 @@ g_vfs_backend_afc_mount (GVfsBackend *backend,
|
|||
* %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
|
||||
* 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
|
||||
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_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)
|
||||
{
|
||||
|
|
|
@ -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_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))
|
||||
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_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));
|
||||
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_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));
|
||||
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_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));
|
||||
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_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));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -527,10 +527,10 @@ restart:
|
|||
{
|
||||
if (ftp->has_initial_user)
|
||||
/* 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
|
||||
/* translators: %s here is the hostname */
|
||||
prompt = g_strdup_printf (_("Enter password for %s"), ftp->host_display_name);
|
||||
/* Translators: %s here is the hostname */
|
||||
prompt = g_strdup_printf (_("Authentication Required\nEnter user and password for “%s”:"), ftp->host_display_name);
|
||||
}
|
||||
|
||||
flags = G_ASK_PASSWORD_NEED_PASSWORD;
|
||||
|
@ -1533,47 +1533,6 @@ out:
|
|||
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
|
||||
do_pull_improve_error_message (GVfsFtpTask *task,
|
||||
GFile *dest,
|
||||
|
@ -1657,6 +1616,15 @@ do_pull (GVfsBackend * backend,
|
|||
src = g_vfs_ftp_file_new_from_gvfs (ftp, source);
|
||||
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 (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));
|
||||
ftp_output_stream_splice (output,
|
||||
input,
|
||||
total_size,
|
||||
progress_callback,
|
||||
progress_callback_data,
|
||||
task.cancellable,
|
||||
&task.error);
|
||||
gvfs_output_stream_splice (output,
|
||||
input,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
total_size,
|
||||
progress_callback,
|
||||
progress_callback_data,
|
||||
task.cancellable,
|
||||
&task.error);
|
||||
g_vfs_ftp_task_close_data_connection (&task);
|
||||
g_vfs_ftp_task_receive (&task, 0, NULL);
|
||||
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_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_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));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -49,17 +49,22 @@
|
|||
#include "gvfsjobsetdisplayname.h"
|
||||
#include "gvfsjobwrite.h"
|
||||
#include "gvfsmonitor.h"
|
||||
#include "gvfsdaemonutils.h"
|
||||
|
||||
struct _GVfsBackendGoogle
|
||||
{
|
||||
GVfsBackend parent;
|
||||
GDataDocumentsService *service;
|
||||
GDataEntry *root;
|
||||
GDataEntry *home;
|
||||
GDataEntry *shared_with_me_dir;
|
||||
GDataEntry *shared_drives_dir;
|
||||
GHashTable *entries; /* gchar *entry_id -> GDataEntry */
|
||||
GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
|
||||
GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */
|
||||
GHashTable *monitors;
|
||||
GList *dir_collisions;
|
||||
GList *shared_drives;
|
||||
GRecMutex mutex; /* guards cache */
|
||||
GoaClient *client;
|
||||
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 MAX_RESULTS 50
|
||||
|
||||
#define REBUILD_ENTRIES_TIMEOUT 60 /* s */
|
||||
|
||||
#define URI_PREFIX "https://www.googleapis.com/drive/v2/files/"
|
||||
|
||||
#define SOURCE_ID_PROPERTY_KEY "GVfsSourceID"
|
||||
#define PARENT_ID_PROPERTY_KEY "GVfsParentID"
|
||||
|
||||
#define ROOT_ID "GVfsRoot"
|
||||
#define SHARED_WITH_ME_ID "GVfsSharedWithMe"
|
||||
#define SHARED_DRIVES_ID "GVfsSharedDrives"
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct
|
||||
|
@ -441,6 +448,12 @@ is_owner (GVfsBackendGoogle *self, GDataEntry *entry)
|
|||
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 *
|
||||
|
@ -717,6 +730,27 @@ insert_entry (GVfsBackendGoogle *self,
|
|||
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
|
||||
remove_entry_full (GVfsBackendGoogle *self,
|
||||
GDataEntry *entry,
|
||||
|
@ -733,6 +767,9 @@ remove_entry_full (GVfsBackendGoogle *self,
|
|||
|
||||
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);
|
||||
for (ll = parent_ids; ll != NULL; ll = ll->next)
|
||||
{
|
||||
|
@ -875,6 +912,9 @@ is_entry_valid (GDataEntry *entry)
|
|||
gint64 *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);
|
||||
}
|
||||
|
||||
|
@ -883,6 +923,9 @@ is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent)
|
|||
{
|
||||
gint64 *timestamp;
|
||||
|
||||
if (parent == self->root)
|
||||
return TRUE;
|
||||
|
||||
timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent));
|
||||
if (timestamp != NULL)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
rebuild_dir (GVfsBackendGoogle *self,
|
||||
GDataEntry *parent,
|
||||
|
@ -902,11 +987,20 @@ rebuild_dir (GVfsBackendGoogle *self,
|
|||
gchar *search;
|
||||
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() */
|
||||
parent_id = g_strdup (gdata_entry_get_id (parent));
|
||||
|
||||
search = g_strdup_printf ("'%s' in parents", parent_id);
|
||||
query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
|
||||
if (parent == self->shared_with_me_dir)
|
||||
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);
|
||||
g_free (search);
|
||||
|
||||
|
@ -972,10 +1066,16 @@ resolve_child (GVfsBackendGoogle *self,
|
|||
GDataEntry *entry;
|
||||
const gchar *parent_id;
|
||||
GError *local_error = NULL;
|
||||
gboolean is_shared_with_me_dir = (parent == self->shared_with_me_dir);
|
||||
|
||||
parent_id = gdata_entry_get_id (parent);
|
||||
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)) ||
|
||||
(entry != NULL && !is_entry_valid (entry)))
|
||||
{
|
||||
|
@ -986,7 +1086,10 @@ resolve_child (GVfsBackendGoogle *self,
|
|||
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)
|
||||
|
@ -1036,8 +1139,26 @@ resolve (GVfsBackendGoogle *self,
|
|||
ret_val = resolve_child (self, parent, basename, cancellable, &local_error);
|
||||
if (ret_val == NULL)
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
goto out;
|
||||
/* This fallback provides volatile entries for URIs which was used
|
||||
* 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)
|
||||
|
@ -1213,6 +1334,10 @@ build_file_info (GVfsBackendGoogle *self,
|
|||
gint64 ctime;
|
||||
gint64 mtime;
|
||||
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))
|
||||
is_folder = TRUE;
|
||||
|
@ -1226,7 +1351,11 @@ build_file_info (GVfsBackendGoogle *self,
|
|||
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);
|
||||
|
||||
|
@ -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_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)
|
||||
{
|
||||
|
@ -1286,10 +1421,28 @@ build_file_info (GVfsBackendGoogle *self,
|
|||
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);
|
||||
|
||||
icon = g_content_type_get_icon (content_type);
|
||||
g_file_info_set_icon (info, icon);
|
||||
if (is_home)
|
||||
{
|
||||
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_object_unref (icon);
|
||||
|
@ -1298,13 +1451,12 @@ build_file_info (GVfsBackendGoogle *self,
|
|||
|
||||
g_file_info_set_file_type (info, file_type);
|
||||
|
||||
if (is_root)
|
||||
goto out;
|
||||
|
||||
id = gdata_entry_get_id (entry);
|
||||
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;
|
||||
else
|
||||
name = id;
|
||||
|
@ -1315,6 +1467,9 @@ build_file_info (GVfsBackendGoogle *self,
|
|||
g_file_info_set_display_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);
|
||||
|
||||
/* Sanitize copy-name by replacing slashes with dashes. This is
|
||||
|
@ -1461,6 +1616,14 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
|
|||
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);
|
||||
title = gdata_entry_get_title (source_entry);
|
||||
source_parent_id = gdata_entry_get_id (source_parent);
|
||||
|
@ -1875,6 +2038,14 @@ g_vfs_backend_google_move (GVfsBackend *_self,
|
|||
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_parent_id = gdata_entry_get_id (source_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() */
|
||||
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;
|
||||
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);
|
||||
|
||||
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"));
|
||||
goto out;
|
||||
|
@ -2342,7 +2517,45 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
|
|||
|
||||
parent_ids = get_parent_ids (self, entry);
|
||||
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
|
||||
* 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);
|
||||
GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
|
||||
GDataEntry *entry;
|
||||
GDataEntry *child;
|
||||
GError *error;
|
||||
GHashTableIter iter;
|
||||
char *parent_path;
|
||||
char *id = NULL;
|
||||
gboolean is_shared_with_me_dir;
|
||||
|
||||
g_rec_mutex_lock (&self->mutex);
|
||||
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() */
|
||||
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);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &child))
|
||||
{
|
||||
DirEntriesKey *k;
|
||||
GDataEntry *child;
|
||||
gchar *child_id;
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
gchar *entry_path;
|
||||
|
@ -2468,7 +2685,7 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self,
|
|||
info = g_file_info_new ();
|
||||
entry_path = g_build_path ("/", parent_path, 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_object_unref (info);
|
||||
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
|
||||
g_vfs_backend_google_mount (GVfsBackend *_self,
|
||||
GVfsJobMount *job,
|
||||
|
@ -2687,8 +2946,11 @@ g_vfs_backend_google_mount (GVfsBackend *_self,
|
|||
|
||||
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;
|
||||
self->root = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
|
||||
self->home = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
|
||||
auth_domain,
|
||||
"root",
|
||||
NULL,
|
||||
|
@ -2702,6 +2964,32 @@ g_vfs_backend_google_mount (GVfsBackend *_self,
|
|||
g_error_free (error);
|
||||
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_display_name (_self, self->account_identity);
|
||||
|
@ -2772,11 +3060,16 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
|||
gchar *entry_path = NULL;
|
||||
gchar *parent_path = NULL;
|
||||
gchar *local_file_title = NULL;
|
||||
goffset size;
|
||||
|
||||
g_rec_mutex_lock (&self->mutex);
|
||||
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)
|
||||
{
|
||||
/* 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,
|
||||
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","
|
||||
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,
|
||||
cancellable,
|
||||
&error);
|
||||
|
@ -2815,6 +3109,12 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
|||
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);
|
||||
if (existing_entry != NULL)
|
||||
{
|
||||
|
@ -2969,11 +3269,14 @@ g_vfs_backend_google_push (GVfsBackend *_self,
|
|||
}
|
||||
|
||||
error = NULL;
|
||||
g_output_stream_splice (G_OUTPUT_STREAM (ostream),
|
||||
G_INPUT_STREAM (istream),
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
cancellable,
|
||||
&error);
|
||||
gvfs_output_stream_splice (G_OUTPUT_STREAM (ostream),
|
||||
G_INPUT_STREAM (istream),
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
g_file_info_get_size (info),
|
||||
progress_callback,
|
||||
progress_callback_data,
|
||||
cancellable,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
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));
|
||||
|
||||
out:
|
||||
|
@ -3089,6 +3390,7 @@ g_vfs_backend_google_query_fs_info (GVfsBackend *_self,
|
|||
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_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) ||
|
||||
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;
|
||||
GDataEntry *entry;
|
||||
GDataEntry *new_entry = NULL;
|
||||
GDataEntry *parent;
|
||||
GError *error;
|
||||
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);
|
||||
|
||||
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"));
|
||||
goto out;
|
||||
|
@ -3536,6 +3847,12 @@ g_vfs_backend_google_create (GVfsBackend *_self,
|
|||
|
||||
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);
|
||||
if (existing_entry != NULL)
|
||||
{
|
||||
|
@ -3645,6 +3962,12 @@ g_vfs_backend_google_replace (GVfsBackend *_self,
|
|||
|
||||
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);
|
||||
if (existing_entry != NULL)
|
||||
{
|
||||
|
@ -3875,6 +4198,10 @@ g_vfs_backend_google_dispose (GObject *_self)
|
|||
|
||||
g_clear_object (&self->service);
|
||||
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_pointer (&self->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);
|
||||
|
||||
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)
|
||||
{
|
||||
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
* Copyright (C) 2021 Igalia S.L.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -51,7 +52,7 @@
|
|||
#include "gvfsdaemonprotocol.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)
|
||||
|
||||
|
@ -63,7 +64,7 @@ g_vfs_backend_http_finalize (GObject *object)
|
|||
backend = G_VFS_BACKEND_HTTP (object);
|
||||
|
||||
if (backend->mount_base)
|
||||
soup_uri_free (backend->mount_base);
|
||||
g_uri_unref (backend->mount_base);
|
||||
|
||||
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);
|
||||
|
||||
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 */
|
||||
|
||||
SoupURI *
|
||||
GUri *
|
||||
http_backend_get_mount_base (GVfsBackend *backend)
|
||||
{
|
||||
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 *
|
||||
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);
|
||||
|
||||
decoded = soup_uri_decode (basename);
|
||||
decoded = g_uri_unescape_string (basename, NULL);
|
||||
g_free (basename);
|
||||
|
||||
return decoded;
|
||||
|
@ -149,13 +221,6 @@ http_error_code_from_status (guint 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_PAYMENT_REQUIRED:
|
||||
case SOUP_STATUS_FORBIDDEN:
|
||||
|
@ -184,45 +249,27 @@ http_error_code_from_status (guint status)
|
|||
void
|
||||
http_job_failed (GVfsJob *job, SoupMessage *msg)
|
||||
{
|
||||
switch (msg->status_code) {
|
||||
switch (soup_message_get_status(msg)) {
|
||||
|
||||
case SOUP_STATUS_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;
|
||||
|
||||
case SOUP_STATUS_UNAUTHORIZED:
|
||||
case SOUP_STATUS_PAYMENT_REQUIRED:
|
||||
case SOUP_STATUS_FORBIDDEN:
|
||||
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;
|
||||
default:
|
||||
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 */
|
||||
|
||||
|
@ -235,8 +282,8 @@ try_mount (GVfsBackend *backend,
|
|||
{
|
||||
GVfsBackendHttp *op_backend;
|
||||
const char *uri_str;
|
||||
char *path;
|
||||
SoupURI *uri;
|
||||
const char *path;
|
||||
GUri *uri;
|
||||
GMountSpec *real_mount_spec;
|
||||
|
||||
op_backend = G_VFS_BACKEND_HTTP (backend);
|
||||
|
@ -245,7 +292,7 @@ try_mount (GVfsBackend *backend,
|
|||
uri_str = g_mount_spec_get (mount_spec, "uri");
|
||||
|
||||
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)");
|
||||
|
||||
|
@ -260,12 +307,11 @@ try_mount (GVfsBackend *backend,
|
|||
real_mount_spec = g_mount_spec_new ("http");
|
||||
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);
|
||||
real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
g_object_unref (msg);
|
||||
|
@ -330,7 +376,7 @@ try_open_for_read (GVfsBackend *backend,
|
|||
GVfsJobOpenForRead *job,
|
||||
const char *filename)
|
||||
{
|
||||
SoupURI *uri;
|
||||
GUri *uri;
|
||||
|
||||
uri = http_backend_get_mount_base (backend);
|
||||
http_backend_open_for_read (backend, G_VFS_JOB (job), uri);
|
||||
|
@ -341,7 +387,7 @@ try_open_for_read (GVfsBackend *backend,
|
|||
void
|
||||
http_backend_open_for_read (GVfsBackend *backend,
|
||||
GVfsJob *job,
|
||||
SoupURI *uri)
|
||||
GUri *uri)
|
||||
{
|
||||
GVfsBackendHttp *op_backend;
|
||||
GInputStream *stream;
|
||||
|
@ -507,7 +553,7 @@ file_info_from_message (SoupMessage *msg,
|
|||
|
||||
/* prefer the filename from the Content-Disposition (rfc2183) header
|
||||
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))
|
||||
{
|
||||
const char *name = g_hash_table_lookup (params, "filename");
|
||||
|
@ -520,10 +566,10 @@ file_info_from_message (SoupMessage *msg,
|
|||
|
||||
if (basename == NULL)
|
||||
{
|
||||
const SoupURI *uri;
|
||||
GUri *uri;
|
||||
|
||||
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);
|
||||
|
@ -540,12 +586,12 @@ file_info_from_message (SoupMessage *msg,
|
|||
g_free (basename);
|
||||
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;
|
||||
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);
|
||||
if (ret && length != -1)
|
||||
{
|
||||
|
@ -553,14 +599,14 @@ file_info_from_message (SoupMessage *msg,
|
|||
}
|
||||
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_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)
|
||||
{
|
||||
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");
|
||||
if (text)
|
||||
{
|
||||
SoupDate *sd;
|
||||
GDateTime *gd;
|
||||
|
||||
sd = soup_date_new_from_string(text);
|
||||
if (sd)
|
||||
gd = soup_date_time_new_from_http_string (text);
|
||||
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);
|
||||
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");
|
||||
if (text)
|
||||
{
|
||||
|
@ -605,19 +653,25 @@ file_info_from_message (SoupMessage *msg,
|
|||
}
|
||||
|
||||
static void
|
||||
query_info_ready (SoupSession *session,
|
||||
SoupMessage *msg,
|
||||
gpointer user_data)
|
||||
query_info_ready (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GFileAttributeMatcher *matcher;
|
||||
GVfsJobQueryInfo *job;
|
||||
GFileInfo *info;
|
||||
GVfsJobQueryInfo *job = G_VFS_JOB_QUERY_INFO (user_data);
|
||||
GFileAttributeMatcher *matcher = job->attribute_matcher;
|
||||
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);
|
||||
info = job->file_info;
|
||||
matcher = job->attribute_matcher;
|
||||
res = soup_session_send_finish (SOUP_SESSION (object), result, &error);
|
||||
if (!res)
|
||||
{
|
||||
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);
|
||||
return;
|
||||
|
@ -625,10 +679,11 @@ query_info_ready (SoupSession *session,
|
|||
|
||||
file_info_from_message (msg, info, matcher);
|
||||
|
||||
g_object_unref (res);
|
||||
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
try_query_info (GVfsBackend *backend,
|
||||
GVfsJobQueryInfo *job,
|
||||
|
@ -637,8 +692,9 @@ try_query_info (GVfsBackend *backend,
|
|||
GFileInfo *info,
|
||||
GFileAttributeMatcher *attribute_matcher)
|
||||
{
|
||||
GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend);
|
||||
SoupMessage *msg;
|
||||
SoupURI *uri;
|
||||
GUri *uri;
|
||||
|
||||
if (g_file_attribute_matcher_matches_only (attribute_matcher,
|
||||
G_FILE_ATTRIBUTE_THUMBNAIL_PATH))
|
||||
|
@ -650,7 +706,10 @@ try_query_info (GVfsBackend *backend,
|
|||
uri = http_backend_get_mount_base (backend);
|
||||
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;
|
||||
}
|
||||
|
@ -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_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));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024)
|
||||
|
||||
static void
|
||||
g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
|
||||
{
|
||||
const char *debug;
|
||||
SoupSessionFeature *cookie_jar;
|
||||
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
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_on_read = try_query_info_on_read;
|
||||
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
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
* Copyright (C) 2021 Igalia S.L.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -49,7 +50,7 @@ struct _GVfsBackendHttp
|
|||
{
|
||||
GVfsBackend parent_instance;
|
||||
|
||||
SoupURI *mount_base;
|
||||
GUri *mount_base;
|
||||
SoupSession *session;
|
||||
};
|
||||
|
||||
|
@ -61,19 +62,14 @@ char * http_path_get_basename (const char *path_str);
|
|||
|
||||
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,
|
||||
SoupMessage *msg);
|
||||
|
||||
void http_backend_queue_message (GVfsBackend *backend,
|
||||
SoupMessage *msg,
|
||||
SoupSessionCallback callback,
|
||||
gpointer user_data);
|
||||
GUri * http_backend_get_mount_base (GVfsBackend *backend);
|
||||
|
||||
void http_backend_open_for_read (GVfsBackend *backend,
|
||||
GVfsJob *job,
|
||||
SoupURI *uri);
|
||||
GUri *uri);
|
||||
|
||||
void http_job_failed (GVfsJob *job,
|
||||
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_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));
|
||||
|
||||
|
|
|
@ -132,6 +132,18 @@ handle_event (EventData *data, GVfsBackendMtp *backend);
|
|||
* 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)
|
||||
{
|
||||
/* 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
|
||||
safest to perform this check here, each time that storage name needs
|
||||
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;
|
||||
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 */
|
||||
for (tmp_storage = storage->next; tmp_storage != 0; tmp_storage = tmp_storage->next) {
|
||||
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,
|
||||
we add storage ID to it */
|
||||
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 {
|
||||
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_SIZE, storage->MaxCapacity);
|
||||
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_debug ("(II) get_storage_info done.\n");
|
||||
|
@ -1711,6 +1740,13 @@ do_pull (GVfsBackend *backend,
|
|||
GFileInfo *info = NULL;
|
||||
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);
|
||||
if (entry == NULL) {
|
||||
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||||
|
@ -2005,6 +2041,13 @@ do_push (GVfsBackend *backend,
|
|||
gchar **elements = g_strsplit_set (destination, "/", -1);
|
||||
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) {
|
||||
g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||||
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_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));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -1607,6 +1607,9 @@ try_query_fs_info (GVfsBackend *backend,
|
|||
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "nfs");
|
||||
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) ||
|
||||
|
|
|
@ -30,7 +30,7 @@ typedef struct {
|
|||
char *uri;
|
||||
char *display_name;
|
||||
GFile *file;
|
||||
time_t modified;
|
||||
GDateTime *modified;
|
||||
} RecentItem;
|
||||
|
||||
struct OPAQUE_TYPE__GVfsBackendRecent
|
||||
|
@ -326,7 +326,8 @@ recent_backend_add_info (RecentItem *item,
|
|||
TRUE);
|
||||
|
||||
/* 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
|
||||
|
@ -375,6 +376,7 @@ recent_item_free (RecentItem *item)
|
|||
g_free (item->display_name);
|
||||
g_free (item->guid);
|
||||
g_clear_object (&item->file);
|
||||
g_date_time_unref (item->modified);
|
||||
g_free (item);
|
||||
}
|
||||
|
||||
|
@ -382,7 +384,7 @@ static gboolean
|
|||
recent_item_update (RecentItem *item,
|
||||
const gchar *uri,
|
||||
const gchar *display_name,
|
||||
time_t modified)
|
||||
GDateTime *modified)
|
||||
{
|
||||
gboolean changed = FALSE;
|
||||
|
||||
|
@ -403,10 +405,11 @@ recent_item_update (RecentItem *item,
|
|||
item->display_name = g_strdup (display_name);
|
||||
}
|
||||
|
||||
if (item->modified != modified)
|
||||
if (!g_date_time_equal (item->modified, modified))
|
||||
{
|
||||
changed = TRUE;
|
||||
item->modified = modified;
|
||||
g_date_time_unref (item->modified);
|
||||
item->modified = g_date_time_ref (modified);
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
@ -415,11 +418,12 @@ recent_item_update (RecentItem *item,
|
|||
static RecentItem *
|
||||
recent_item_new (const gchar *uri,
|
||||
const gchar *display_name,
|
||||
time_t modified)
|
||||
GDateTime *modified)
|
||||
{
|
||||
RecentItem *item;
|
||||
item = g_new0 (RecentItem, 1);
|
||||
item->guid = g_dbus_generate_guid ();
|
||||
item->modified = g_date_time_ref (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 *guid;
|
||||
char *display_name;
|
||||
time_t modified;
|
||||
GDateTime *modified;
|
||||
|
||||
if (should_include (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);
|
||||
if (guid)
|
||||
{
|
||||
|
|
|
@ -465,7 +465,7 @@ setup_ssh_environment (void)
|
|||
}
|
||||
|
||||
static char **
|
||||
setup_ssh_commandline (GVfsBackend *backend)
|
||||
setup_ssh_commandline (GVfsBackend *backend, const gchar *control_path)
|
||||
{
|
||||
GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
|
||||
guint last_arg;
|
||||
|
@ -488,7 +488,8 @@ setup_ssh_commandline (GVfsBackend *backend)
|
|||
#ifndef USE_PTY
|
||||
args[last_arg++] = g_strdup ("-oBatchMode yes");
|
||||
#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)
|
||||
args[last_arg++] = g_strdup ("-x");
|
||||
|
@ -1105,10 +1106,10 @@ handle_login (GVfsBackend *backend,
|
|||
if (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 ") ||
|
||||
g_str_has_prefix (buffer, "Enter Kerberos password") ||
|
||||
g_str_has_prefix (buffer, "Enter passphrase for key") ||
|
||||
g_str_has_prefix (buffer, "Enter PASSCODE"))
|
||||
strstr (buffer, "Password for ") ||
|
||||
strstr (buffer, "Enter Kerberos password") ||
|
||||
strstr (buffer, "Enter passphrase for key") ||
|
||||
strstr (buffer, "Enter PASSCODE"))
|
||||
{
|
||||
gboolean aborted = FALSE;
|
||||
gsize bytes_written;
|
||||
|
@ -1160,17 +1161,17 @@ handle_login (GVfsBackend *backend,
|
|||
if (op_backend->user_specified)
|
||||
if (strcmp (authtype, "publickey") == 0)
|
||||
/* 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
|
||||
/* 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
|
||||
if (strcmp (authtype, "publickey") == 0)
|
||||
/* 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
|
||||
/* 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,
|
||||
prompt,
|
||||
|
@ -1264,6 +1265,55 @@ handle_login (GVfsBackend *backend,
|
|||
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 '") ||
|
||||
strstr (buffer, "Key fingerprint:") != NULL)
|
||||
{
|
||||
|
@ -1275,8 +1325,10 @@ handle_login (GVfsBackend *backend,
|
|||
|
||||
get_hostname_and_fingerprint_from_line (buffer, &hostname, &fingerprint);
|
||||
|
||||
message = g_strdup_printf (_("Can’t verify the identity of “%s”.\n"
|
||||
"This happens when you log in to a computer the first time.\n\n"
|
||||
/* Translators: the first %s is the hostname, the second the key fingerprint */
|
||||
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”. "
|
||||
"If you want to be absolutely sure it is safe to continue, "
|
||||
"contact the system administrator."),
|
||||
|
@ -1302,7 +1354,9 @@ handle_login (GVfsBackend *backend,
|
|||
|
||||
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, "
|
||||
"contact the system administrator."),
|
||||
hostname ? hostname : op_backend->host,
|
||||
|
@ -1841,8 +1895,13 @@ setup_connection (GVfsBackend *backend,
|
|||
gboolean res;
|
||||
char *extension_name, *extension_data;
|
||||
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,
|
||||
args, &pid,
|
||||
|
@ -4734,6 +4793,9 @@ try_query_fs_info (GVfsBackend *backend,
|
|||
G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "sftp");
|
||||
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 (has_extension (op_backend, SFTP_EXT_OPENSSH_STATVFS) &&
|
||||
(g_file_attribute_matcher_matches (matcher,
|
||||
|
@ -5491,6 +5553,8 @@ typedef struct {
|
|||
/* fstat information */
|
||||
goffset size;
|
||||
guint32 permissions;
|
||||
guint64 mtime;
|
||||
guint64 atime;
|
||||
|
||||
/* state */
|
||||
goffset offset;
|
||||
|
@ -5640,8 +5704,15 @@ push_close_deleted_file (GVfsBackendSftp *backend,
|
|||
}
|
||||
|
||||
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 we wrote to a temp file, do delete then rename. */
|
||||
|
@ -5662,15 +5733,52 @@ push_close_delete_or_succeed (SftpPushHandle *handle)
|
|||
}
|
||||
|
||||
static void
|
||||
push_close_restore_permissions (GVfsBackendSftp *backend,
|
||||
int reply_type,
|
||||
GDataInputStream *reply,
|
||||
guint32 len,
|
||||
GVfsJob *job,
|
||||
gpointer user_data)
|
||||
push_close_restore_permissions (SftpPushHandle *handle)
|
||||
{
|
||||
/* We don't care if setting the permissions succeeded or not. */
|
||||
push_close_delete_or_succeed (user_data);
|
||||
gboolean default_perms = (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS);
|
||||
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
|
||||
|
@ -5688,19 +5796,19 @@ push_close_write_reply (GVfsBackendSftp *backend,
|
|||
guint32 code = read_status_code (reply);
|
||||
if (code == SSH_FX_OK)
|
||||
{
|
||||
if (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
|
||||
push_close_delete_or_succeed (handle);
|
||||
else
|
||||
/* 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))
|
||||
{
|
||||
/* Restore the source file's permissions. */
|
||||
GDataOutputStream *command = new_command_stream (backend, SSH_FXP_SETSTAT);
|
||||
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);
|
||||
GDataOutputStream *command = new_command_stream (backend, SSH_FXP_LSTAT);
|
||||
put_string (command, handle->op_job->destination);
|
||||
queue_command_stream_and_free (&backend->command_connection, command,
|
||||
push_close_restore_permissions,
|
||||
push_close_stat_reply,
|
||||
job, handle);
|
||||
return;
|
||||
}
|
||||
|
||||
push_close_restore_permissions (handle);
|
||||
return;
|
||||
}
|
||||
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->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);
|
||||
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_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,
|
||||
push_source_fstat_cb, handle);
|
||||
}
|
||||
|
@ -6166,6 +6278,14 @@ try_push (GVfsBackend *backend,
|
|||
GFile *source;
|
||||
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))
|
||||
{
|
||||
g_vfs_job_failed (G_VFS_JOB (op_job),
|
||||
|
@ -6211,6 +6331,8 @@ typedef struct {
|
|||
/* fstat information */
|
||||
goffset size;
|
||||
guint32 mode;
|
||||
guint64 mtime;
|
||||
guint64 atime;
|
||||
|
||||
/* state */
|
||||
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);
|
||||
|
||||
if (handle->size >= 0 && !(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS))
|
||||
if (handle->size >= 0)
|
||||
{
|
||||
GFileInfo *info = g_file_info_new ();
|
||||
g_file_info_set_attribute_uint32 (info,
|
||||
G_FILE_ATTRIBUTE_UNIX_MODE,
|
||||
handle->mode);
|
||||
if (!(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS))
|
||||
g_file_info_set_attribute_uint32 (info,
|
||||
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,
|
||||
info,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
|
@ -6573,6 +6705,10 @@ pull_fstat_reply (GVfsBackendSftp *backend,
|
|||
handle->size = g_file_info_get_size (info);
|
||||
handle->mode = g_file_info_get_attribute_uint32 (info,
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
@ -6699,6 +6835,14 @@ try_pull (GVfsBackend *backend,
|
|||
SftpPullHandle *handle;
|
||||
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))
|
||||
{
|
||||
g_vfs_job_failed (G_VFS_JOB (job),
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "gvfsjobqueryfsinfo.h"
|
||||
#include "gvfsjobqueryattributes.h"
|
||||
#include "gvfsjobenumerate.h"
|
||||
#include "gvfsjobmove.h"
|
||||
#include "gvfsdaemonprotocol.h"
|
||||
#include "gvfsdaemonutils.h"
|
||||
#include "gvfsutils.h"
|
||||
|
@ -77,9 +78,7 @@ struct _GVfsBackendSmb
|
|||
|
||||
GMountSource *mount_source; /* Only used/set during mount */
|
||||
int mount_try;
|
||||
gboolean mount_try_again;
|
||||
gboolean mount_cancelled;
|
||||
gboolean use_anonymous;
|
||||
|
||||
gboolean password_in_keyring;
|
||||
GPasswordSave password_save;
|
||||
|
@ -202,25 +201,14 @@ auth_callback (SMBCCTX *context,
|
|||
backend->user == NULL &&
|
||||
backend->domain == NULL)
|
||||
{
|
||||
/* Try again if kerberos login fails */
|
||||
backend->mount_try_again = TRUE;
|
||||
g_debug ("auth_callback - kerberos pass\n");
|
||||
}
|
||||
else if (backend->mount_try == 1 &&
|
||||
backend->user == NULL &&
|
||||
backend->domain == NULL)
|
||||
{
|
||||
/* Try again if ccache login fails */
|
||||
backend->mount_try_again = TRUE;
|
||||
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
|
||||
{
|
||||
gboolean in_keyring = FALSE;
|
||||
|
@ -263,9 +251,19 @@ auth_callback (SMBCCTX *context,
|
|||
|
||||
g_debug ("auth_callback - asking for password...\n");
|
||||
|
||||
/* translators: First %s is a share name, second is a server name */
|
||||
message = g_strdup_printf (_("Password required for share %s on %s"),
|
||||
share_name, server_name);
|
||||
if (backend->user)
|
||||
{
|
||||
/* 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,
|
||||
message,
|
||||
username_out,
|
||||
|
@ -290,13 +288,13 @@ auth_callback (SMBCCTX *context,
|
|||
}
|
||||
}
|
||||
|
||||
/* Try again if this fails */
|
||||
backend->mount_try_again = TRUE;
|
||||
smbc_setOptionNoAutoAnonymousLogin (backend->smb_context,
|
||||
!anonymous);
|
||||
|
||||
if (anonymous)
|
||||
{
|
||||
backend->use_anonymous = TRUE;
|
||||
backend->password_save = FALSE;
|
||||
g_debug ("auth_callback - anonymous enabled\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -486,7 +484,6 @@ do_mount (GVfsBackend *backend,
|
|||
*/
|
||||
do
|
||||
{
|
||||
op_backend->mount_try_again = FALSE;
|
||||
op_backend->mount_cancelled = FALSE;
|
||||
|
||||
g_debug ("do_mount - try #%d \n", op_backend->mount_try);
|
||||
|
@ -502,7 +499,13 @@ do_mount (GVfsBackend *backend,
|
|||
if (res == 0)
|
||||
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);
|
||||
break;
|
||||
|
@ -518,15 +521,9 @@ do_mount (GVfsBackend *backend,
|
|||
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 ++;
|
||||
}
|
||||
while (op_backend->mount_try_again);
|
||||
while (TRUE);
|
||||
|
||||
g_free (uri);
|
||||
|
||||
|
@ -1434,6 +1431,8 @@ set_info_from_stat (GVfsBackendSmb *backend,
|
|||
|
||||
if (g_file_attribute_matcher_matches (matcher,
|
||||
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_STANDARD_ICON) ||
|
||||
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_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,
|
||||
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE) ||
|
||||
|
@ -2041,6 +2041,7 @@ do_move (GVfsBackend *backend,
|
|||
smbc_stat_fn smbc_stat;
|
||||
smbc_rename_fn smbc_rename;
|
||||
smbc_unlink_fn smbc_unlink;
|
||||
goffset size;
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
|
@ -2158,7 +2160,10 @@ do_move (GVfsBackend *backend,
|
|||
g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
|
||||
}
|
||||
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
|
||||
|
|
|
@ -367,9 +367,19 @@ auth_callback (SMBCCTX *context,
|
|||
|
||||
g_debug ("auth_callback - asking for password...\n");
|
||||
|
||||
/* translators: %s is a server name */
|
||||
message = g_strdup_printf (_("Password required for %s"),
|
||||
server_name);
|
||||
if (backend->user)
|
||||
{
|
||||
/* 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,
|
||||
message,
|
||||
username_out,
|
||||
|
@ -957,8 +967,14 @@ do_mount (GVfsBackend *backend,
|
|||
uri, op_backend->mount_try, dir, op_backend->mount_cancelled,
|
||||
errsv, g_strerror (errsv));
|
||||
|
||||
if (dir == NULL &&
|
||||
(op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES)))
|
||||
if (errsv == EINVAL && op_backend->mount_try == 0 && op_backend->user == NULL)
|
||||
{
|
||||
/* 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);
|
||||
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_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));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -612,8 +612,7 @@ send_reply_cb (GObject *source_object,
|
|||
|
||||
job = channel->priv->current_job;
|
||||
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);
|
||||
|
||||
|
@ -634,7 +633,7 @@ send_reply_cb (GObject *source_object,
|
|||
}
|
||||
/* Start queued request or readahead */
|
||||
else if (!start_queued_request (channel) &&
|
||||
class->readahead && job)
|
||||
class->readahead)
|
||||
{
|
||||
/* No queued requests, maybe we want to do a readahead call */
|
||||
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 (channel);
|
||||
}
|
||||
|
||||
/* Might be called on an i/o thread */
|
||||
|
@ -668,7 +666,7 @@ g_vfs_channel_send_reply (GVfsChannel *channel,
|
|||
channel->priv->reply_buffer,
|
||||
G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SIZE,
|
||||
0, NULL,
|
||||
send_reply_cb, g_object_ref (channel));
|
||||
send_reply_cb, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -677,7 +675,7 @@ g_vfs_channel_send_reply (GVfsChannel *channel,
|
|||
channel->priv->output_data,
|
||||
channel->priv->output_data_size,
|
||||
0, NULL,
|
||||
send_reply_cb, g_object_ref (channel));
|
||||
send_reply_cb, channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,14 +87,6 @@ struct _GVfsDaemon
|
|||
gboolean lost_main_daemon;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GVfsDaemon *daemon;
|
||||
char *socket_dir;
|
||||
GDBusServer *server;
|
||||
|
||||
GDBusConnection *conn;
|
||||
} NewConnectionData;
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void g_vfs_daemon_get_property (GObject *object,
|
||||
|
@ -209,7 +201,6 @@ job_handler_callback (gpointer data,
|
|||
GVfsJob *job = G_VFS_JOB (data);
|
||||
|
||||
g_vfs_job_run (job);
|
||||
g_object_unref (job);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -649,30 +640,10 @@ g_vfs_daemon_queue_job (GVfsDaemon *daemon,
|
|||
if (!g_vfs_job_try (job))
|
||||
{
|
||||
/* 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_object_unref (job);
|
||||
g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
peer_unregister_skeleton (const gchar *obj_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 should be always valid in this case */
|
||||
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (daemon_skeleton));
|
||||
|
||||
g_hash_table_remove (daemon->client_connections, connection);
|
||||
|
||||
/* Unexport the registered interface skeletons */
|
||||
g_hash_table_foreach (daemon->registered_paths, (GHFunc) peer_unregister_skeleton, connection);
|
||||
|
||||
/* The peer-to-peer connection was disconnected */
|
||||
g_signal_handlers_disconnect_by_data (connection, user_data);
|
||||
g_object_unref (connection);
|
||||
|
||||
g_hash_table_remove (daemon->client_connections, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_peer_connection_setup (GVfsDaemon *daemon,
|
||||
GDBusConnection *dbus_conn,
|
||||
NewConnectionData *data)
|
||||
GDBusConnection *dbus_conn)
|
||||
{
|
||||
GVfsDBusDaemon *daemon_skeleton;
|
||||
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",
|
||||
error->message, g_quark_to_string (error->domain), error->code);
|
||||
g_error_free (error);
|
||||
g_object_unref (data->conn);
|
||||
goto error_out;
|
||||
return;
|
||||
}
|
||||
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 */
|
||||
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_signal_connect (data->conn, "closed", G_CALLBACK (peer_connection_closed), data->daemon);
|
||||
|
||||
error_out:
|
||||
new_connection_data_free (data);
|
||||
g_signal_connect (dbus_conn, "closed", G_CALLBACK (peer_connection_closed), daemon);
|
||||
}
|
||||
|
||||
#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
|
||||
generate_address (char **address,
|
||||
char **folder)
|
||||
generate_address (gchar **address, gchar **socket_path)
|
||||
{
|
||||
*address = NULL;
|
||||
*folder = NULL;
|
||||
gchar tmp[16] = "socket-";
|
||||
gchar *socket_dir;
|
||||
|
||||
#ifdef USE_ABSTRACT_SOCKETS
|
||||
{
|
||||
gchar tmp[9];
|
||||
gvfs_randomize_string (tmp + 7, 8);
|
||||
tmp[15] = '\0';
|
||||
|
||||
gvfs_randomize_string (tmp, 8);
|
||||
tmp[8] = '\0';
|
||||
*address = g_strdup_printf ("unix:abstract=/dbus-vfs-daemon/socket-%s", tmp);
|
||||
}
|
||||
#else
|
||||
{
|
||||
char *dir;
|
||||
|
||||
dir = create_socket_dir ();
|
||||
*address = g_strdup_printf ("unix:path=%s/socket", dir);
|
||||
*folder = dir;
|
||||
}
|
||||
#endif
|
||||
socket_dir = gvfs_get_socket_dir ();
|
||||
|
||||
*socket_path = g_build_filename (socket_dir, tmp, NULL);
|
||||
*address = g_strdup_printf ("unix:path=%s", *socket_path);
|
||||
|
||||
g_free (socket_dir);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -888,14 +758,9 @@ daemon_new_connection_func (GDBusServer *server,
|
|||
GDBusConnection *connection,
|
||||
gpointer user_data)
|
||||
{
|
||||
NewConnectionData *data;
|
||||
GVfsDaemon *daemon = user_data;
|
||||
|
||||
data = user_data;
|
||||
|
||||
/* Take ownership */
|
||||
data->conn = g_object_ref (connection);
|
||||
|
||||
daemon_peer_connection_setup (data->daemon, data->conn, data);
|
||||
daemon_peer_connection_setup (daemon, connection);
|
||||
|
||||
/* Kill the server, no more need for it */
|
||||
g_dbus_server_stop (server);
|
||||
|
@ -913,16 +778,11 @@ handle_get_connection (GVfsDBusDaemon *object,
|
|||
GDBusServer *server;
|
||||
GError *error;
|
||||
gchar *address1;
|
||||
NewConnectionData *data;
|
||||
char *socket_dir;
|
||||
gchar *socket_path;
|
||||
gchar *guid;
|
||||
|
||||
generate_address (&address1, &socket_dir);
|
||||
const char *pkexec_uid;
|
||||
|
||||
data = g_new (NewConnectionData, 1);
|
||||
data->daemon = daemon;
|
||||
data->socket_dir = socket_dir;
|
||||
data->conn = NULL;
|
||||
generate_address (&address1, &socket_path);
|
||||
|
||||
guid = g_dbus_generate_guid ();
|
||||
error = NULL;
|
||||
|
@ -943,21 +803,34 @@ handle_get_connection (GVfsDBusDaemon *object,
|
|||
}
|
||||
|
||||
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,
|
||||
invocation,
|
||||
address1,
|
||||
"");
|
||||
|
||||
g_free (address1);
|
||||
g_free (socket_path);
|
||||
return TRUE;
|
||||
|
||||
error_out:
|
||||
new_connection_data_free (data);
|
||||
g_free (address1);
|
||||
g_unlink (socket_path);
|
||||
g_free (socket_path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1171,8 +1044,7 @@ void
|
|||
g_vfs_daemon_run_job_in_thread (GVfsDaemon *daemon,
|
||||
GVfsJob *job)
|
||||
{
|
||||
if (!g_thread_pool_push (daemon->thread_pool, g_object_ref (job), NULL)) /* TODO: Check error */
|
||||
g_object_unref (job);
|
||||
g_thread_pool_push (daemon->thread_pool, job, NULL); /* TODO: Check error */
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -332,7 +332,9 @@ gvfs_accept_certificate (GMountSource *mount_source,
|
|||
|
||||
certificate_str = certificate_to_string (certificate);
|
||||
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"
|
||||
"Are you really sure you would like to continue?"),
|
||||
|
@ -361,3 +363,77 @@ gvfs_accept_certificate (GMountSource *mount_source,
|
|||
return FALSE;
|
||||
}
|
||||
#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,
|
||||
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
|
||||
|
||||
#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))
|
||||
break;
|
||||
|
||||
ftp->connections--;
|
||||
g_vfs_ftp_connection_free (task->conn);
|
||||
task->conn = NULL;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* gvfshttpinputstream.c: seekable wrapper around SoupRequestHTTP
|
||||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -29,13 +30,13 @@
|
|||
#include <libsoup/soup.h>
|
||||
|
||||
#include "gvfshttpinputstream.h"
|
||||
#include "gvfsbackendhttp.h"
|
||||
|
||||
static void g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
|
||||
|
||||
struct GVfsHttpInputStreamPrivate {
|
||||
SoupURI *uri;
|
||||
GUri *uri;
|
||||
SoupSession *session;
|
||||
SoupRequest *req;
|
||||
SoupMessage *msg;
|
||||
GInputStream *stream;
|
||||
|
||||
|
@ -61,9 +62,8 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
|||
GVfsHttpInputStream *stream = G_VFS_HTTP_INPUT_STREAM (object);
|
||||
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->req);
|
||||
g_clear_object (&priv->msg);
|
||||
g_clear_object (&priv->stream);
|
||||
g_free (priv->range);
|
||||
|
@ -74,7 +74,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
|||
/**
|
||||
* g_vfs_http_input_stream_new:
|
||||
* @session: a #SoupSession
|
||||
* @uri: a #SoupURI
|
||||
* @uri: a #GUri
|
||||
*
|
||||
* Prepares to send a GET request for @uri on @session, and returns a
|
||||
* #GInputStream that can be used to read the response.
|
||||
|
@ -89,7 +89,7 @@ g_vfs_http_input_stream_finalize (GObject *object)
|
|||
**/
|
||||
GInputStream *
|
||||
g_vfs_http_input_stream_new (SoupSession *session,
|
||||
SoupURI *uri)
|
||||
GUri *uri)
|
||||
{
|
||||
GVfsHttpInputStream *stream;
|
||||
GVfsHttpInputStreamPrivate *priv;
|
||||
|
@ -98,30 +98,27 @@ g_vfs_http_input_stream_new (SoupSession *session,
|
|||
priv = stream->priv;
|
||||
|
||||
priv->session = g_object_ref (session);
|
||||
priv->uri = soup_uri_copy (uri);
|
||||
priv->uri = g_uri_ref (uri);
|
||||
|
||||
return G_INPUT_STREAM (stream);
|
||||
}
|
||||
|
||||
static SoupRequest *
|
||||
g_vfs_http_input_stream_ensure_request (GInputStream *stream)
|
||||
static SoupMessage *
|
||||
g_vfs_http_input_stream_ensure_msg (GInputStream *stream)
|
||||
{
|
||||
GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM (stream)->priv;
|
||||
|
||||
if (!priv->req)
|
||||
if (!priv->msg)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
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->msg = soup_message_new_from_uri (SOUP_METHOD_GET, priv->uri);
|
||||
priv->offset = 0;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -136,7 +133,7 @@ send_callback (GObject *object,
|
|||
|
||||
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)
|
||||
g_task_return_boolean (task, TRUE);
|
||||
else
|
||||
|
@ -188,9 +185,9 @@ g_vfs_http_input_stream_send_async (GInputStream *stream,
|
|||
return;
|
||||
}
|
||||
|
||||
g_vfs_http_input_stream_ensure_request (stream);
|
||||
soup_request_send_async (priv->req, cancellable,
|
||||
send_callback, task);
|
||||
g_vfs_http_input_stream_ensure_msg (stream);
|
||||
soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
|
||||
cancellable, send_callback, task);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,16 +250,16 @@ read_send_callback (GObject *object,
|
|||
ReadAfterSendData *rasd = g_task_get_task_data (task);
|
||||
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)
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
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_task_return_int (task, 0);
|
||||
|
@ -271,9 +268,9 @@ read_send_callback (GObject *object,
|
|||
return;
|
||||
}
|
||||
g_task_return_new_error (task,
|
||||
SOUP_HTTP_ERROR,
|
||||
priv->msg->status_code,
|
||||
"%s", priv->msg->reason_phrase);
|
||||
G_IO_ERROR,
|
||||
http_error_code_from_status (soup_message_get_status (priv->msg)),
|
||||
_("HTTP Error: %s"), soup_message_get_reason_phrase (priv->msg));
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
@ -282,7 +279,7 @@ read_send_callback (GObject *object,
|
|||
gboolean status;
|
||||
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);
|
||||
if (!status || start != priv->request_offset)
|
||||
{
|
||||
|
@ -325,9 +322,9 @@ g_vfs_http_input_stream_read_async (GInputStream *stream,
|
|||
rasd->count = count;
|
||||
g_task_set_task_data (task, rasd, g_free);
|
||||
|
||||
g_vfs_http_input_stream_ensure_request (stream);
|
||||
soup_request_send_async (priv->req, cancellable,
|
||||
read_send_callback, task);
|
||||
g_vfs_http_input_stream_ensure_msg (stream);
|
||||
soup_session_send_async (priv->session, priv->msg, G_PRIORITY_DEFAULT,
|
||||
cancellable, read_send_callback, task);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -419,7 +416,7 @@ g_vfs_http_input_stream_seek (GSeekable *seekable,
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -498,7 +495,7 @@ g_vfs_http_input_stream_get_message (GInputStream *stream)
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* 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
|
||||
* 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;
|
||||
|
||||
GInputStream *g_vfs_http_input_stream_new (SoupSession *session,
|
||||
SoupURI *uri);
|
||||
GUri *uri);
|
||||
|
||||
void g_vfs_http_input_stream_send_async (GInputStream *stream,
|
||||
int io_priority,
|
||||
|
|
|
@ -36,7 +36,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
|||
GType
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -96,9 +96,7 @@ on_name_acquired (GDBusConnection *connection,
|
|||
argv2[0] = LIBEXEC_DIR "/gvfsd-fuse";
|
||||
argv2[1] = fuse_path;
|
||||
argv2[2] = "-f";
|
||||
argv2[3] = "-o";
|
||||
argv2[4] = "big_writes";
|
||||
argv2[5] = NULL;
|
||||
argv2[3] = NULL;
|
||||
|
||||
g_spawn_async (NULL,
|
||||
argv2,
|
||||
|
@ -145,6 +143,7 @@ main (int argc, char *argv[])
|
|||
guint name_owner_id;
|
||||
GBusNameOwnerFlags flags;
|
||||
GOptionContext *context;
|
||||
gchar *socket_dir;
|
||||
const GOptionEntry options[] = {
|
||||
{ "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 },
|
||||
|
@ -214,6 +213,11 @@ main (int argc, char *argv[])
|
|||
if (daemon == NULL)
|
||||
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_CALLBACK (daemon_shutdown), loop);
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ libgvfsdaemon = shared_library(
|
|||
)
|
||||
|
||||
libgvfsdaemon_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
include_directories: '.',
|
||||
dependencies: libgvfscommon_dep,
|
||||
compile_args: cflags,
|
||||
link_with: libgvfsdaemon,
|
||||
|
@ -154,7 +154,7 @@ daemon_main_sources = files(
|
|||
'daemon-main-generic.c',
|
||||
)
|
||||
|
||||
programs = []
|
||||
programs = {}
|
||||
mounts = []
|
||||
schema_data = []
|
||||
convert_data = []
|
||||
|
@ -165,7 +165,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
sources = files(
|
||||
|
@ -184,7 +184,7 @@ cflags = [
|
|||
'-DMAX_JOB_THREADS=10',
|
||||
]
|
||||
|
||||
programs += [['gvfsd-ftp', {'sources': sources, 'c_args': cflags}]]
|
||||
programs += {'gvfsd-ftp': {'sources': sources, 'c_args': cflags}}
|
||||
mounts += ['ftp', 'ftps', 'ftpis']
|
||||
|
||||
cflags = [
|
||||
|
@ -194,7 +194,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
cflags = [
|
||||
|
@ -205,7 +205,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
cflags = [
|
||||
|
@ -216,7 +216,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
cflags = [
|
||||
|
@ -227,7 +227,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
cflags = [
|
||||
|
@ -237,7 +237,7 @@ cflags = [
|
|||
'-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']
|
||||
|
||||
if enable_sftp
|
||||
|
@ -256,10 +256,10 @@ if enable_sftp
|
|||
'-DDEFAULT_BACKEND_TYPE=sftp',
|
||||
'-DBACKEND_TYPES="sftp", G_VFS_TYPE_BACKEND_SFTP,',
|
||||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -273,7 +273,7 @@ if enable_samba
|
|||
'-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']
|
||||
schema_data += files('org.gnome.system.smb.gschema.xml')
|
||||
convert_data += files('gvfs-smb.convert')
|
||||
|
@ -286,7 +286,7 @@ if enable_samba
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -305,7 +305,7 @@ if enable_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']
|
||||
schema_data += files('org.gnome.system.dns_sd.gschema.xml')
|
||||
convert_data += files('gvfs-dns-sd.convert')
|
||||
|
@ -320,7 +320,7 @@ if enable_archive
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -337,7 +337,7 @@ if enable_cdda
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -354,27 +354,27 @@ if enable_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']
|
||||
|
||||
policy = gvfs_namespace + '.file-operations.policy'
|
||||
|
||||
policy_in = configure_file(
|
||||
input: policy + '.in.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: service_conf,
|
||||
)
|
||||
|
||||
i18n.merge_file(
|
||||
input: policy_in,
|
||||
input: configure_file(
|
||||
input: policy + '.in.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: service_conf,
|
||||
),
|
||||
output: '@BASENAME@',
|
||||
po_dir: po_dir,
|
||||
install: true,
|
||||
install_dir: gvfs_datadir / 'polkit-1/actions',
|
||||
)
|
||||
|
||||
install_data(
|
||||
gvfs_namespace + '.file-operations.rules',
|
||||
configure_file(
|
||||
input: gvfs_namespace + '.file-operations.rules.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: {'PRIVILEGED_GROUP': privileged_group},
|
||||
install_dir: gvfs_datadir / 'polkit-1/rules.d',
|
||||
)
|
||||
endif
|
||||
|
@ -391,7 +391,7 @@ if enable_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']
|
||||
endif
|
||||
|
||||
|
@ -409,7 +409,7 @@ if enable_gphoto2
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -430,7 +430,7 @@ if enable_mtp
|
|||
deps += libusb_dep
|
||||
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']
|
||||
endif
|
||||
|
||||
|
@ -453,7 +453,7 @@ if enable_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']
|
||||
|
||||
cflags = [
|
||||
|
@ -472,7 +472,7 @@ if enable_http
|
|||
cflags += '-DBACKEND_TYPES="dav", G_VFS_TYPE_BACKEND_DAV,'
|
||||
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']
|
||||
endif
|
||||
|
||||
|
@ -490,7 +490,7 @@ if enable_afc
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -515,7 +515,7 @@ if enable_afp
|
|||
'-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']
|
||||
|
||||
cflags = [
|
||||
|
@ -525,7 +525,7 @@ if enable_afp
|
|||
'-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']
|
||||
endif
|
||||
|
||||
|
@ -537,12 +537,11 @@ if enable_nfs
|
|||
'-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']
|
||||
endif
|
||||
|
||||
foreach program: programs
|
||||
options = program[1]
|
||||
foreach program, options: programs
|
||||
kwargs = {
|
||||
'sources': daemon_main_sources + options.get('sources', []),
|
||||
'dependencies': [libgvfsdaemon_dep] + options.get('dependencies', []),
|
||||
|
@ -550,7 +549,7 @@ foreach program: programs
|
|||
}
|
||||
|
||||
executable(
|
||||
program[0],
|
||||
program,
|
||||
include_directories: top_inc,
|
||||
kwargs: kwargs,
|
||||
install: true,
|
||||
|
|
|
@ -415,6 +415,30 @@ child_watch_cb (GPid pid,
|
|||
gint status,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -485,7 +509,7 @@ spawn_mount (MountData *data)
|
|||
}
|
||||
else
|
||||
{
|
||||
g_child_watch_add (pid, child_watch_cb, NULL);
|
||||
g_child_watch_add (pid, child_watch_cb, data);
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// based on the client process.
|
||||
polkit.addRule(function(action, subject) {
|
||||
if ((action.id == "org.gtk.vfs.file-operations-helper") &&
|
||||
subject.local &&
|
||||
subject.active &&
|
||||
subject.isInGroup ("sudo")) {
|
||||
subject.isInGroup ("@PRIVILEGED_GROUP@")) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
|
@ -272,10 +272,10 @@ dir_watch_free (DirWatch *watch)
|
|||
if (watch != NULL)
|
||||
{
|
||||
if (watch->parent_monitor)
|
||||
{
|
||||
g_file_monitor_cancel (watch->parent_monitor);
|
||||
g_object_unref (watch->parent_monitor);
|
||||
}
|
||||
{
|
||||
g_file_monitor_cancel (watch->parent_monitor);
|
||||
g_object_unref (watch->parent_monitor);
|
||||
}
|
||||
|
||||
g_object_unref (watch->directory);
|
||||
g_object_unref (watch->topdir);
|
||||
|
|
|
@ -211,6 +211,34 @@ trash_mount_remove (TrashMount **mount_ptr)
|
|||
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
|
||||
trash_watcher_remount (TrashWatcher *watcher)
|
||||
{
|
||||
|
@ -229,7 +257,7 @@ trash_watcher_remount (TrashWatcher *watcher)
|
|||
{
|
||||
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);
|
||||
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
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Source: gvfs
|
||||
Section: gnome
|
||||
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>
|
||||
Build-Depends: debhelper-compat (= 12),
|
||||
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>
|
||||
|
||||
<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/" />
|
||||
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gvfs/issues/" />
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
||||
|
@ -20,7 +20,7 @@
|
|||
<maintainer>
|
||||
<foaf:Person>
|
||||
<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>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
|
|
|
@ -14,20 +14,20 @@ xsltproc_cmd = [
|
|||
'@INPUT@',
|
||||
]
|
||||
|
||||
mans = [
|
||||
['gvfs', '7'],
|
||||
['gvfsd', '1'],
|
||||
['gvfsd-fuse', '1'],
|
||||
['gvfsd-metadata', '1'],
|
||||
]
|
||||
mans = {
|
||||
'gvfs': '7',
|
||||
'gvfsd': '1',
|
||||
'gvfsd-fuse': '1',
|
||||
'gvfsd-metadata': '1',
|
||||
}
|
||||
|
||||
foreach man: mans
|
||||
foreach program, section: mans
|
||||
custom_target(
|
||||
man[0] + man[1],
|
||||
input: man[0] + '.xml',
|
||||
output: '@BASENAME@.' + man[1],
|
||||
program + section,
|
||||
input: program + '.xml',
|
||||
output: '@BASENAME@.' + section,
|
||||
command: xsltproc_cmd,
|
||||
install: true,
|
||||
install_dir: gvfs_mandir / ('man' + man[1]),
|
||||
install_dir: gvfs_mandir / ('man' + section),
|
||||
)
|
||||
endforeach
|
||||
|
|
154
meson.build
154
meson.build
|
@ -1,9 +1,9 @@
|
|||
project(
|
||||
'gvfs', 'c',
|
||||
version: '1.44.1',
|
||||
version: '1.50.3',
|
||||
license: 'LGPL2+',
|
||||
default_options: 'buildtype=debugoptimized',
|
||||
meson_version: '>= 0.50.0',
|
||||
meson_version: '>= 0.56.0',
|
||||
)
|
||||
|
||||
gvfs_name = meson.project_name()
|
||||
|
@ -44,16 +44,16 @@ cc = meson.get_compiler('c')
|
|||
config_h = configuration_data()
|
||||
|
||||
# defines
|
||||
set_defines = [
|
||||
set_defines = {
|
||||
# package
|
||||
['PACKAGE_STRING', '@0@ @1@'.format(gvfs_name, gvfs_version)],
|
||||
['VERSION', gvfs_version],
|
||||
'PACKAGE_STRING': '@0@ @1@'.format(gvfs_name, gvfs_version),
|
||||
'VERSION': gvfs_version,
|
||||
# i18n
|
||||
['GETTEXT_PACKAGE', gvfs_name],
|
||||
]
|
||||
'GETTEXT_PACKAGE': gvfs_name,
|
||||
}
|
||||
|
||||
foreach define: set_defines
|
||||
config_h.set_quoted(define[0], define[1])
|
||||
foreach define, value: set_defines
|
||||
config_h.set_quoted(define, value)
|
||||
endforeach
|
||||
|
||||
# Globally define_GNU_SOURCE and therefore enable the GNU extensions
|
||||
|
@ -179,17 +179,17 @@ foreach name: ['mkdev', 'sysmacros']
|
|||
endforeach
|
||||
|
||||
# types
|
||||
check_types = [
|
||||
check_types = {
|
||||
# type, fallback type
|
||||
['gid_t', 'int'],
|
||||
['pid_t', 'int'],
|
||||
['size_t', 'unsigned int'],
|
||||
['uid_t', 'int'],
|
||||
]
|
||||
'gid_t': 'int',
|
||||
'pid_t': 'int',
|
||||
'size_t': 'unsigned int',
|
||||
'uid_t': 'int',
|
||||
}
|
||||
|
||||
foreach type: check_types
|
||||
if not cc.has_type(type[0], prefix: '#include<sys/types.h>')
|
||||
config_h.set(type[0], type[1])
|
||||
foreach type, value: check_types
|
||||
if not cc.has_type(type, prefix: '#include<sys/types.h>')
|
||||
config_h.set(type, value)
|
||||
endif
|
||||
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_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')
|
||||
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.33.0')
|
||||
|
||||
|
@ -249,23 +249,23 @@ endif
|
|||
config_h.set('HAVE_GCRYPT', enable_gcrypt)
|
||||
|
||||
# *** Check for dbus service dir ***
|
||||
dbus_session_bus_services_dir = dependency('dbus-1').get_pkgconfig_variable(
|
||||
'session_bus_services_dir',
|
||||
define_variable: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||
dbus_session_bus_services_dir = dependency('dbus-1').get_variable(
|
||||
pkgconfig: 'session_bus_services_dir',
|
||||
pkgconfig_define: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||
)
|
||||
|
||||
dbus_service_in = files('dbus.service.in')
|
||||
|
||||
# *** Check for giomoduledir and schemasdir ***
|
||||
gio_giomoduledir = gio_dep.get_pkgconfig_variable(
|
||||
'giomoduledir',
|
||||
define_variable: ['libdir', gvfs_prefix / gvfs_libdir],
|
||||
gio_giomoduledir = gio_dep.get_variable(
|
||||
pkgconfig: 'giomoduledir',
|
||||
pkgconfig_define: ['libdir', gvfs_prefix / gvfs_libdir],
|
||||
)
|
||||
|
||||
gio_schemasdir = gio_dep.get_pkgconfig_variable(
|
||||
'schemasdir',
|
||||
define_variable: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||
default: gvfs_prefix / gvfs_datadir / 'glib-2.0/schemas',
|
||||
gio_schemasdir = gio_dep.get_variable(
|
||||
pkgconfig: 'schemasdir',
|
||||
pkgconfig_define: ['datadir', gvfs_prefix / gvfs_datadir],
|
||||
default_value: gvfs_prefix / gvfs_datadir / 'glib-2.0/schemas',
|
||||
)
|
||||
|
||||
# *** Check for systemd options ***
|
||||
|
@ -281,12 +281,12 @@ if install_systemd_systemduserunitdir or install_systemd_tmpfilesdir
|
|||
|
||||
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')
|
||||
systemd_systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir')
|
||||
systemd_systemduserunitdir = systemd_dep.get_variable(pkgconfig: 'systemduserunitdir', pkgconfig_define: ['prefix', gvfs_prefix])
|
||||
endif
|
||||
|
||||
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')
|
||||
systemd_tmpfilesdir = systemd_dep.get_pkgconfig_variable('tmpfilesdir')
|
||||
systemd_tmpfilesdir = systemd_dep.get_variable(pkgconfig: 'tmpfilesdir', pkgconfig_define: ['prefix', gvfs_prefix])
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -299,17 +299,18 @@ endif
|
|||
config_h.set('HAVE_GCR', enable_gcr)
|
||||
|
||||
# *** Check if we should build with admin backend ***
|
||||
privileged_group = get_option('privileged_group')
|
||||
enable_admin = get_option('admin')
|
||||
if enable_admin
|
||||
libcap_dep = dependency('libcap')
|
||||
polkit_gobject_dep = dependency('polkit-gobject-1')
|
||||
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114')
|
||||
endif
|
||||
|
||||
# *** Check if we should build with http backend ***
|
||||
enable_http = get_option('http')
|
||||
if enable_http
|
||||
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
|
||||
|
||||
# *** Check if we should build with DNS-SD backend ***
|
||||
|
@ -330,7 +331,7 @@ config_h.set('HAVE_GUDEV', enable_gudev)
|
|||
# *** Check for FUSE ***
|
||||
enable_fuse = get_option('fuse')
|
||||
if enable_fuse
|
||||
fuse_dep = dependency('fuse', version: '>= 2.8.0')
|
||||
fuse_dep = dependency('fuse3', version: '>= 3.0.0')
|
||||
endif
|
||||
config_h.set('HAVE_FUSE', enable_fuse)
|
||||
|
||||
|
@ -357,7 +358,10 @@ config_h.set('HAVE_LOGIND', enable_logind)
|
|||
enable_afc = get_option('afc')
|
||||
if enable_afc
|
||||
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
|
||||
|
||||
# *** Check if we should build with GOA volume monitor ***
|
||||
|
@ -416,7 +420,7 @@ enable_google = get_option('google')
|
|||
if enable_google
|
||||
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
|
||||
|
||||
# *** Check for gphoto2 ***
|
||||
|
@ -453,10 +457,6 @@ endif
|
|||
|
||||
# *** SFTP backend ***
|
||||
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_devel_utils = get_option('devel_utils')
|
||||
|
@ -487,37 +487,43 @@ meson.add_install_script(
|
|||
gio_giomoduledir,
|
||||
)
|
||||
|
||||
output = gvfs_name + ' ' + gvfs_version + ' configuration summary:\n'
|
||||
output += '\n'
|
||||
output += ' systemduserunitdir: ' + systemd_systemduserunitdir + '\n'
|
||||
output += ' tmpfilesdir: ' + systemd_tmpfilesdir + '\n'
|
||||
output += '\n'
|
||||
output += ' admin: ' + enable_admin.to_string() + '\n'
|
||||
output += ' afc: ' + enable_afc.to_string() + '\n'
|
||||
output += ' afp: ' + enable_afp.to_string() + '\n'
|
||||
output += ' archive: ' + enable_archive.to_string() + '\n'
|
||||
output += ' cdda: ' + enable_cdda.to_string() + '\n'
|
||||
output += ' dnssd: ' + enable_dnssd.to_string() + '\n'
|
||||
output += ' goa: ' + enable_goa.to_string() + '\n'
|
||||
output += ' google: ' + enable_google.to_string() + '\n'
|
||||
output += ' gphoto2: ' + enable_gphoto2.to_string() + '\n'
|
||||
output += ' http: ' + enable_http.to_string() + '\n'
|
||||
output += ' mtp: ' + enable_mtp.to_string() + '\n'
|
||||
output += ' nfs: ' + enable_nfs.to_string() + '\n'
|
||||
output += ' sftp: ' + enable_sftp.to_string() + '\n'
|
||||
output += ' smb: ' + enable_samba.to_string() + '\n'
|
||||
output += ' udisks2: ' + enable_udisks2.to_string() + '\n'
|
||||
output += '\n'
|
||||
output += ' bluray: ' + enable_bluray.to_string() + '\n'
|
||||
output += ' fuse: ' + enable_fuse.to_string() + '\n'
|
||||
output += ' gcr: ' + enable_gcr.to_string() + '\n'
|
||||
output += ' gcrypt: ' + enable_gcrypt.to_string() + '\n'
|
||||
output += ' gudev: ' + enable_gudev.to_string() + '\n'
|
||||
output += ' keyring: ' + enable_keyring.to_string() + '\n'
|
||||
output += ' logind: ' + enable_logind.to_string() + '\n'
|
||||
output += ' libusb: ' + enable_libusb.to_string() + '\n'
|
||||
output += '\n'
|
||||
output += ' devel_utils: ' + enable_devel_utils.to_string() + '\n'
|
||||
output += ' installed_tests: ' + enable_installed_tests.to_string() + '\n'
|
||||
output += ' man: ' + enable_man.to_string() + '\n'
|
||||
message(output)
|
||||
summary({
|
||||
'systemduserunitdir': systemd_systemduserunitdir,
|
||||
'tmpfilesdir': systemd_tmpfilesdir,
|
||||
'privileged_group': privileged_group,
|
||||
}, section: 'Configuration')
|
||||
|
||||
summary({
|
||||
'admin': enable_admin,
|
||||
'afc': enable_afc,
|
||||
'afp': enable_afp,
|
||||
'archive': enable_archive,
|
||||
'cdda': enable_cdda,
|
||||
'dnssd': enable_dnssd,
|
||||
'goa': enable_goa,
|
||||
'google': enable_google,
|
||||
'gphoto2': enable_gphoto2,
|
||||
'http': enable_http,
|
||||
'mtp': enable_mtp,
|
||||
'nfs': enable_nfs,
|
||||
'sftp': enable_sftp,
|
||||
'smb': enable_samba,
|
||||
'udisks2': enable_udisks2,
|
||||
}, section: 'Backends')
|
||||
|
||||
summary({
|
||||
'bluray': enable_bluray,
|
||||
'fuse': enable_fuse,
|
||||
'gcr': enable_gcr,
|
||||
'gcrypt': enable_gcrypt,
|
||||
'gudev': enable_gudev,
|
||||
'keyring': enable_keyring,
|
||||
'logind': enable_logind,
|
||||
'libusb': enable_libusb,
|
||||
}, 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('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('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='s' name='tree' direction='out'/>
|
||||
</method>
|
||||
<signal name="AttributeChanged">
|
||||
<arg type='s' name='tree_path'/>
|
||||
<arg type='s' name='file_path'/>
|
||||
</signal>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem metadata service
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfsd-metadata
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.Metadata
|
||||
Slice=session.slice
|
||||
|
|
|
@ -47,6 +47,7 @@ sources = files(
|
|||
deps = [
|
||||
gio_dep,
|
||||
glib_dep,
|
||||
libgvfscommon_dep,
|
||||
]
|
||||
|
||||
cflags = [
|
||||
|
@ -58,7 +59,7 @@ cflags = [
|
|||
libmetadata = static_library(
|
||||
'metadata',
|
||||
sources: sources + [dbus_sources],
|
||||
include_directories: [top_inc, common_inc],
|
||||
include_directories: top_inc,
|
||||
dependencies: deps + [gio_unix_dep],
|
||||
c_args: cflags,
|
||||
pic: true,
|
||||
|
@ -71,10 +72,7 @@ libmetadata_dep = declare_dependency(
|
|||
link_with: libmetadata,
|
||||
)
|
||||
|
||||
deps = [
|
||||
libgvfscommon_dep,
|
||||
libmetadata_dep,
|
||||
]
|
||||
deps = [libmetadata_dep]
|
||||
|
||||
if enable_gudev
|
||||
deps += gudev_dep
|
||||
|
@ -104,10 +102,7 @@ if enable_devel_utils
|
|||
app,
|
||||
app + '.c',
|
||||
include_directories: top_inc,
|
||||
dependencies: [
|
||||
libgvfscommon_dep,
|
||||
libmetadata_dep,
|
||||
],
|
||||
dependencies: libmetadata_dep,
|
||||
c_args: cflags,
|
||||
)
|
||||
endforeach
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#define WRITEOUT_TIMEOUT_SECS 60
|
||||
#define WRITEOUT_TIMEOUT_SECS_NFS 15
|
||||
#define WRITEOUT_TIMEOUT_SECS_DBUS 1
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
|
@ -50,11 +51,19 @@ typedef struct {
|
|||
guint writeout_timeout;
|
||||
} TreeInfo;
|
||||
|
||||
typedef struct {
|
||||
gchar *treefile;
|
||||
gchar *path;
|
||||
GVfsMetadata *object;
|
||||
guint timeout_id;
|
||||
} BusNotificationInfo;
|
||||
|
||||
static GHashTable *tree_infos = NULL;
|
||||
static GVfsMetadata *skeleton = NULL;
|
||||
#ifdef HAVE_GUDEV
|
||||
static GUdevClient *gudev_client = NULL;
|
||||
#endif
|
||||
static GList *dbus_notification_list = NULL;
|
||||
|
||||
static void
|
||||
tree_info_free (TreeInfo *info)
|
||||
|
@ -105,8 +114,78 @@ flush_single (const gchar *filename,
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -222,6 +301,7 @@ handle_set (GVfsMetadata *object,
|
|||
}
|
||||
else
|
||||
{
|
||||
emit_attribute_change (object, arg_treefile, arg_path);
|
||||
gvfs_metadata_complete_set (object, invocation);
|
||||
}
|
||||
|
||||
|
@ -257,6 +337,7 @@ handle_remove (GVfsMetadata *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
emit_attribute_change (object, arg_treefile, arg_path);
|
||||
tree_info_schedule_writeout (info);
|
||||
gvfs_metadata_complete_remove (object, invocation);
|
||||
|
||||
|
@ -297,6 +378,8 @@ handle_move (GVfsMetadata *object,
|
|||
/* Remove source if copy succeeded (ignoring errors) */
|
||||
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);
|
||||
gvfs_metadata_complete_move (object, invocation);
|
||||
|
||||
|
@ -344,7 +427,7 @@ on_name_lost (GDBusConnection *connection,
|
|||
GMainLoop *loop = user_data;
|
||||
|
||||
/* means that someone has claimed our name (we allow replacement) */
|
||||
flush_all ();
|
||||
flush_all (TRUE);
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
|
@ -357,7 +440,7 @@ on_connection_closed (GDBusConnection *connection,
|
|||
GMainLoop *loop = user_data;
|
||||
|
||||
/* session bus died */
|
||||
flush_all ();
|
||||
flush_all (FALSE);
|
||||
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);
|
||||
|
||||
if (data)
|
||||
if (data != MAP_FAILED)
|
||||
{
|
||||
old_tag = GUINT32_FROM_BE (*(guint32 *)(data + RANDOM_TAG_OFFSET));
|
||||
*(guint32 *)(data + ROTATED_OFFSET) = 0xffffffff;
|
||||
|
|
|
@ -170,7 +170,7 @@ GVfsMetadata *
|
|||
meta_tree_get_metadata_proxy ()
|
||||
{
|
||||
static GVfsMetadata *proxy = NULL;
|
||||
static volatile gsize initialized = 0;
|
||||
static gsize initialized = 0;
|
||||
|
||||
if (g_once_init_enter (&initialized))
|
||||
{
|
||||
|
@ -451,15 +451,7 @@ meta_tree_init (MetaTree *tree)
|
|||
if (memcmp (tree->header->magic, MAGIC, MAGIC_LEN) != 0)
|
||||
{
|
||||
g_warning ("can't init metadata tree %s: wrong magic", tree->filename);
|
||||
if (!tree->for_write)
|
||||
goto err;
|
||||
|
||||
meta_tree_clear (tree);
|
||||
|
||||
if (g_unlink (tree->filename) != 0)
|
||||
goto err;
|
||||
|
||||
goto retry;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tree->header->major != MAJOR_VERSION)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service - Apple File Conduit monitor
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfs-afc-volume-monitor
|
||||
Type=dbus
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 GError *_error = NULL;
|
||||
static volatile gsize initialized = 0;
|
||||
static gsize initialized = 0;
|
||||
|
||||
if (g_once_init_enter (&initialized))
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service - GNOME Online Accounts monitor
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfs-goa-volume-monitor
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.GoaVolumeMonitor
|
||||
Slice=session.slice
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service - digital camera monitor
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfs-gphoto2-volume-monitor
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.GPhoto2VolumeMonitor
|
||||
Slice=session.slice
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
subdir('proxy')
|
||||
|
||||
# [[service name suffix, install monitor test data]]
|
||||
monitors = []
|
||||
monitors = {}
|
||||
|
||||
if enable_afc
|
||||
monitors += [['Afc', true]]
|
||||
monitors += {'Afc': true}
|
||||
endif
|
||||
|
||||
if enable_goa
|
||||
monitors += [['Goa', false]]
|
||||
monitors += {'Goa': false}
|
||||
endif
|
||||
|
||||
if enable_gphoto2
|
||||
monitors += [['GPhoto2', true]]
|
||||
monitors += {'GPhoto2': true}
|
||||
endif
|
||||
|
||||
if enable_mtp
|
||||
monitors += [['MTP', false]]
|
||||
monitors += {'MTP': false}
|
||||
endif
|
||||
|
||||
if enable_udisks2
|
||||
monitors += [['UDisks2', true]]
|
||||
monitors += {'UDisks2': true}
|
||||
endif
|
||||
|
||||
monitors_test_data = []
|
||||
foreach monitor: monitors
|
||||
monitor_name = monitor[0].to_lower()
|
||||
foreach monitor, monitor_test: monitors
|
||||
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_systemd_service = ''
|
||||
|
||||
|
@ -66,7 +66,7 @@ foreach monitor: monitors
|
|||
install_dir: dbus_session_bus_services_dir,
|
||||
)
|
||||
|
||||
if monitor[1]
|
||||
if monitor_test
|
||||
monitors_test_data += [monitor_data, monitor_service]
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service - Media Transfer Protocol monitor
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfs-mtp-volume-monitor
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.MTPVolumeMonitor
|
||||
Slice=session.slice
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[Unit]
|
||||
Description=Virtual filesystem service - disk device monitor
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@libexecdir@/gvfs-udisks2-volume-monitor
|
||||
Type=dbus
|
||||
BusName=org.gtk.vfs.UDisks2VolumeMonitor
|
||||
Slice=session.slice
|
||||
|
|
|
@ -580,7 +580,6 @@ typedef struct {
|
|||
GDrive *drive;
|
||||
|
||||
GMountOperation *op;
|
||||
gboolean op_aborted;
|
||||
gboolean show_processes_up;
|
||||
|
||||
guint unmount_timer_id;
|
||||
|
@ -687,13 +686,6 @@ unmount_notify_op_show_processes (UnmountNotifyData *data)
|
|||
data->show_processes_up = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
unmount_notify_op_aborted (UnmountNotifyData *data)
|
||||
{
|
||||
unmount_notify_stop_timer (data);
|
||||
data->op_aborted = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
unmount_notify_op_reply (UnmountNotifyData *data,
|
||||
GMountOperationResult result)
|
||||
|
@ -704,7 +696,7 @@ unmount_notify_op_reply (UnmountNotifyData *data,
|
|||
|
||||
if ((result == G_MOUNT_OPERATION_HANDLED && data->show_processes_up && choice == 1) ||
|
||||
result == G_MOUNT_OPERATION_ABORTED)
|
||||
unmount_notify_op_aborted (data);
|
||||
unmount_notify_stop_timer (data);
|
||||
else if (result == G_MOUNT_OPERATION_HANDLED)
|
||||
unmount_notify_ensure_timer (data);
|
||||
|
||||
|
@ -748,7 +740,7 @@ unmount_notify_data_for_operation (GMountOperation *op,
|
|||
unmount_notify_data_free);
|
||||
|
||||
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_CALLBACK (unmount_notify_op_show_processes), data);
|
||||
g_signal_connect_swapped (data->op, "reply",
|
||||
|
@ -780,7 +772,7 @@ gvfs_udisks2_unmount_notify_stop (GMountOperation *op,
|
|||
|
||||
unmount_notify_stop_timer (data);
|
||||
|
||||
if (data->op_aborted || unmount_failed)
|
||||
if (unmount_failed)
|
||||
return;
|
||||
|
||||
name = unmount_notify_get_name (data);
|
||||
|
|
|
@ -1496,13 +1496,14 @@ do_unlock (GTask *task)
|
|||
task);
|
||||
if (g_strcmp0 (type, "crypto_unknown") == 0)
|
||||
/* Translators: %s is the description of the volume that is being unlocked */
|
||||
message = g_strdup_printf (_("Enter a passphrase to unlock the volume\n"
|
||||
"The volume %s might be a VeraCrypt volume as it contains random data."),
|
||||
message = g_strdup_printf (_("Authentication Required\n"
|
||||
"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);
|
||||
else
|
||||
/* Translators: %s is the description of the volume that is being unlocked */
|
||||
message = g_strdup_printf (_("Enter a passphrase to unlock the volume\n"
|
||||
"The passphrase is needed to access encrypted data on %s."),
|
||||
message = g_strdup_printf (_("Authentication Required\n"
|
||||
"A passphrase is needed to access encrypted data on “%s”."),
|
||||
data->desc_of_encrypted_to_unlock);
|
||||
|
||||
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 GError *_error = NULL;
|
||||
static volatile gsize initialized = 0;
|
||||
static gsize initialized = 0;
|
||||
|
||||
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
|
||||
should_include (const gchar *mount_path,
|
||||
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,
|
||||
* 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)
|
||||
{
|
||||
ret = should_include_mount_point (monitor, mount_point);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# please keep this list sorted alphabetically
|
||||
ab
|
||||
af
|
||||
ar
|
||||
as
|
||||
|
@ -33,8 +34,10 @@ hr
|
|||
hu
|
||||
hi
|
||||
id
|
||||
ie
|
||||
it
|
||||
ja
|
||||
ka
|
||||
kk
|
||||
kn
|
||||
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