summaryrefslogtreecommitdiff
path: root/client/gvfsfusedaemon.c
diff options
context:
space:
mode:
authorRoss Lagerwall <rosslagerwall@gmail.com>2014-07-24 07:17:47 +0100
committerRoss Lagerwall <rosslagerwall@gmail.com>2014-10-26 15:58:56 +0000
commit8dc5941cf17d2d82c8faf69b0ea88b7c66e0ccff (patch)
tree7d87d8a0f18b35d7cc72a8a9101426ddb99a4fc9 /client/gvfsfusedaemon.c
parent4512e0a2f6c43094ed8ac2a40c2bc6e453448b07 (diff)
downloadgvfs-8dc5941cf17d2d82c8faf69b0ea88b7c66e0ccff.tar.gz
fuse: Use query_info_on_{read,write} if a stream is open
If a stream is open and it supports query_info_on_{read,write}, use that in preference to querying the file using the path. This causes the correct information to be retrieved when g_file_replace is implemented by writing to a temporary file, rather than the information of the yet-to-be-replaced file. https://bugzilla.gnome.org/show_bug.cgi?id=632296
Diffstat (limited to 'client/gvfsfusedaemon.c')
-rw-r--r--client/gvfsfusedaemon.c180
1 files changed, 119 insertions, 61 deletions
diff --git a/client/gvfsfusedaemon.c b/client/gvfsfusedaemon.c
index 35719306..79657347 100644
--- a/client/gvfsfusedaemon.c
+++ b/client/gvfsfusedaemon.c
@@ -734,6 +734,50 @@ file_info_get_stat_mode (GFileInfo *file_info)
return unix_mode;
}
+static void
+set_attributes_from_info (GFileInfo *file_info, struct stat *sbuf)
+{
+ GTimeVal mod_time;
+
+ sbuf->st_mode = file_info_get_stat_mode (file_info);
+ sbuf->st_size = g_file_info_get_size (file_info);
+ sbuf->st_uid = daemon_uid;
+ sbuf->st_gid = daemon_gid;
+
+ g_file_info_get_modification_time (file_info, &mod_time);
+ sbuf->st_mtime = mod_time.tv_sec;
+ sbuf->st_ctime = mod_time.tv_sec;
+ sbuf->st_atime = mod_time.tv_sec;
+
+ if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_TIME_CHANGED))
+ sbuf->st_ctime = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_TIME_CHANGED);
+ if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS))
+ sbuf->st_atime = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+
+ if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE))
+ sbuf->st_blksize = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE);
+ if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCKS))
+ sbuf->st_blocks = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCKS);
+ else /* fake it to make 'du' work like 'du --apparent'. */
+ sbuf->st_blocks = (sbuf->st_size + 511) / 512;
+
+ /* Setting st_nlink to 1 for directories makes 'find' work */
+ sbuf->st_nlink = 1;
+}
+
+static const char *query_attributes = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_UNIX_MODE ","
+ G_FILE_ATTRIBUTE_TIME_CHANGED ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED ","
+ G_FILE_ATTRIBUTE_TIME_ACCESS ","
+ G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE ","
+ G_FILE_ATTRIBUTE_UNIX_BLOCKS ","
+ G_FILE_ATTRIBUTE_ACCESS_CAN_READ ","
+ G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE ","
+ G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE;
+
static gint
getattr_for_file (GFile *file, struct stat *sbuf)
{
@@ -741,49 +785,11 @@ getattr_for_file (GFile *file, struct stat *sbuf)
GError *error = NULL;
gint result = 0;
- file_info = g_file_query_info (file,
- G_FILE_ATTRIBUTE_STANDARD_TYPE ","
- G_FILE_ATTRIBUTE_STANDARD_NAME ","
- G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
- G_FILE_ATTRIBUTE_STANDARD_SIZE ","
- G_FILE_ATTRIBUTE_UNIX_MODE ","
- G_FILE_ATTRIBUTE_TIME_CHANGED ","
- G_FILE_ATTRIBUTE_TIME_MODIFIED ","
- G_FILE_ATTRIBUTE_TIME_ACCESS ","
- G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE ","
- G_FILE_ATTRIBUTE_UNIX_BLOCKS ","
- "access::*",
- 0, NULL, &error);
+ file_info = g_file_query_info (file, query_attributes, 0, NULL, &error);
if (file_info)
{
- GTimeVal mod_time;
-
- sbuf->st_mode = file_info_get_stat_mode (file_info);
- sbuf->st_size = g_file_info_get_size (file_info);
- sbuf->st_uid = daemon_uid;
- sbuf->st_gid = daemon_gid;
-
- g_file_info_get_modification_time (file_info, &mod_time);
- sbuf->st_mtime = mod_time.tv_sec;
- sbuf->st_ctime = mod_time.tv_sec;
- sbuf->st_atime = mod_time.tv_sec;
-
- if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_TIME_CHANGED))
- sbuf->st_ctime = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_TIME_CHANGED);
- if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS))
- sbuf->st_atime = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
-
- if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE))
- sbuf->st_blksize = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE);
- if (g_file_info_has_attribute (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCKS))
- sbuf->st_blocks = file_info_get_attribute_as_uint (file_info, G_FILE_ATTRIBUTE_UNIX_BLOCKS);
- else /* fake it to make 'du' work like 'du --apparent'. */
- sbuf->st_blocks = (sbuf->st_size + 511) / 512;
-
- /* Setting st_nlink to 1 for directories makes 'find' work */
- sbuf->st_nlink = 1;
-
+ set_attributes_from_info (file_info, sbuf);
g_object_unref (file_info);
}
else
@@ -804,16 +810,51 @@ getattr_for_file (GFile *file, struct stat *sbuf)
return result;
}
-static void
+/* Call with fh locked */
+static gint
getattr_for_file_handle (FileHandle *fh, struct stat *sbuf)
{
- sbuf->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
- sbuf->st_uid = daemon_uid;
- sbuf->st_gid = daemon_gid;
- sbuf->st_nlink = 1;
- sbuf->st_size = fh->pos;
- sbuf->st_blksize = 512;
- sbuf->st_blocks = (sbuf->st_size + 511) / 512;
+ GFileInfo *file_info;
+ GError *error = NULL;
+ gint result = 0;
+
+ switch (fh->op)
+ {
+ case FILE_OP_READ:
+ file_info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (fh->stream),
+ query_attributes,
+ NULL, &error);
+ break;
+ case FILE_OP_WRITE:
+ file_info = g_file_output_stream_query_info (G_FILE_OUTPUT_STREAM (fh->stream),
+ query_attributes,
+ NULL, &error);
+ break;
+ default:
+ return -ENOTSUP;
+ }
+
+ if (file_info)
+ {
+ set_attributes_from_info (file_info, sbuf);
+ g_object_unref (file_info);
+ }
+ else
+ {
+ if (error)
+ {
+ debug_print ("Error from GVFS: %s\n", error->message);
+ result = -errno_from_error (error);
+ g_error_free (error);
+ }
+ else
+ {
+ debug_print ("No file info, but no error from GVFS.\n");
+ result = -EIO;
+ }
+ }
+
+ return result;
}
static gint
@@ -853,27 +894,44 @@ vfs_getattr (const gchar *path, struct stat *sbuf)
else if ((file = file_from_full_path (path)))
{
/* Submount */
+ FileHandle *fh = get_file_handle_for_path (path);
- result = getattr_for_file (file, sbuf);
-
- if (result != 0)
+ if (fh)
{
- FileHandle *fh = get_file_handle_for_path (path);
+ goffset pos;
- /* Some backends don't create new files until their stream has
- * been closed. So, if the path doesn't exist, but we have a stream
- * associated with it, pretend it's there. */
+ g_mutex_lock (&fh->mutex);
- if (fh != NULL)
+ result = getattr_for_file_handle (fh, sbuf);
+ pos = fh->pos;
+
+ g_mutex_unlock (&fh->mutex);
+ file_handle_unref (fh);
+
+ if (result == -ENOTSUP)
{
- g_mutex_lock (&fh->mutex);
- getattr_for_file_handle (fh, sbuf);
- g_mutex_unlock (&fh->mutex);
+ result = getattr_for_file (file, sbuf);
- file_handle_unref (fh);
- result = 0;
+ /* Some backends don't create new files until their stream has
+ * been closed. So, if the path doesn't exist, but we have a
+ * stream associated with it, pretend it's there. */
+ if (result != 0)
+ {
+ result = 0;
+ sbuf->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR;
+ sbuf->st_uid = daemon_uid;
+ sbuf->st_gid = daemon_gid;
+ sbuf->st_size = pos;
+ sbuf->st_nlink = 1;
+ sbuf->st_blksize = 512;
+ sbuf->st_blocks = (sbuf->st_size + 511) / 512;
+ }
}
}
+ else
+ {
+ result = getattr_for_file (file, sbuf);
+ }
g_object_unref (file);
}