summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2018-11-26 13:58:09 +0100
committerOndrej Holy <oholy@redhat.com>2018-11-26 14:00:21 +0100
commit185eae05d0150d54976a46785200fbb65f0915ed (patch)
tree46c0e95442a82aaf005cb00269839160cc5ea5ca
parent396216f71abf6907efd1383ca0d1a597918cd83d (diff)
downloadgvfs-wip/oholy/smb-enumeration-performance.tar.gz
smb: Improve enumeration performancewip/oholy/smb-enumeration-performance
https://gitlab.gnome.org/GNOME/gvfs/issues/306
-rw-r--r--daemon/gvfsbackendsmb.c256
1 files changed, 128 insertions, 128 deletions
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
index 60cd0376..b2c984dd 100644
--- a/daemon/gvfsbackendsmb.c
+++ b/daemon/gvfsbackendsmb.c
@@ -89,10 +89,11 @@ struct _GVfsBackendSmb
G_DEFINE_TYPE (GVfsBackendSmb, g_vfs_backend_smb, G_VFS_TYPE_BACKEND)
static void set_info_from_stat (GVfsBackendSmb *backend,
- GFileInfo *info,
- struct stat *statbuf,
- const char *basename,
- GFileAttributeMatcher *matcher);
+ GFileInfo *info,
+ struct stat *statbuf,
+ const struct libsmb_file_info *exstat,
+ const char *basename,
+ GFileAttributeMatcher *matcher);
static void
@@ -749,8 +750,8 @@ do_query_info_on_read (GVfsBackend *backend,
if (res == 0)
{
- set_info_from_stat (op_backend, info, &st, NULL, matcher);
-
+ set_info_from_stat (op_backend, info, &st, NULL, NULL, matcher);
+
g_vfs_job_succeeded (G_VFS_JOB (job));
}
else
@@ -1005,9 +1006,15 @@ copy_file (GVfsBackendSmb *backend,
}
static char *
-create_etag (struct stat *statbuf)
+create_etag (struct stat *statbuf, const struct libsmb_file_info *exstat)
{
- return g_strdup_printf ("%lu", (long unsigned int)statbuf->st_mtime);
+ gulong time;
+
+ g_assert (statbuf || exstat);
+
+ time = (statbuf != NULL) ? statbuf->st_mtime : exstat->mtime_ts.tv_sec;
+
+ return g_strdup_printf ("%lu", time);
}
static void
@@ -1058,7 +1065,7 @@ do_replace (GVfsBackend *backend,
if (res == 0)
{
- current_etag = create_etag (&original_stat);
+ current_etag = create_etag (&original_stat, NULL);
if (strcmp (etag, current_etag) != 0)
{
g_free (current_etag);
@@ -1246,7 +1253,7 @@ do_query_info_on_write (GVfsBackend *backend,
if (res == 0)
{
- set_info_from_stat (op_backend, info, &st, NULL, matcher);
+ set_info_from_stat (op_backend, info, &st, NULL, NULL, matcher);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
@@ -1330,7 +1337,7 @@ do_close_write (GVfsBackend *backend,
if (stat_res == 0)
{
char *etag;
- etag = create_etag (&stat_at_close);
+ etag = create_etag (&stat_at_close, NULL);
g_vfs_job_close_write_set_etag (job, etag);
g_free (etag);
}
@@ -1343,15 +1350,22 @@ do_close_write (GVfsBackend *backend,
static void
set_info_from_stat (GVfsBackendSmb *backend,
- GFileInfo *info,
- struct stat *statbuf,
- const char *basename,
- GFileAttributeMatcher *matcher)
+ GFileInfo *info,
+ struct stat *statbuf,
+ const struct libsmb_file_info *exstat,
+ const char *basename,
+ GFileAttributeMatcher *matcher)
{
GFileType file_type;
GTimeVal t;
char *content_type;
char *display_name;
+ guint16 mode;
+ guint64 size;
+ gboolean have_statbuf;
+
+ g_assert (statbuf || exstat);
+ have_statbuf = (statbuf != NULL);
if (basename)
{
@@ -1392,35 +1406,46 @@ set_info_from_stat (GVfsBackendSmb *backend,
file_type = G_FILE_TYPE_UNKNOWN;
- if (S_ISREG (statbuf->st_mode))
+ mode = have_statbuf ? statbuf->st_mode : exstat->attrs;
+ if (S_ISREG (mode))
file_type = G_FILE_TYPE_REGULAR;
- else if (S_ISDIR (statbuf->st_mode))
+ else if (S_ISDIR (mode))
file_type = G_FILE_TYPE_DIRECTORY;
- else if (S_ISCHR (statbuf->st_mode) ||
- S_ISBLK (statbuf->st_mode) ||
- S_ISFIFO (statbuf->st_mode)
+ else if (S_ISCHR (mode) ||
+ S_ISBLK (mode) ||
+ S_ISFIFO (mode)
#ifdef S_ISSOCK
- || S_ISSOCK (statbuf->st_mode)
+ || S_ISSOCK (mode)
#endif
- )
+ )
file_type = G_FILE_TYPE_SPECIAL;
- else if (S_ISLNK (statbuf->st_mode))
+ else if (S_ISLNK (mode))
file_type = G_FILE_TYPE_SYMBOLIC_LINK;
g_file_info_set_file_type (info, file_type);
- g_file_info_set_size (info, statbuf->st_size);
- g_file_info_set_attribute_uint64 (info,
- G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE,
- statbuf->st_blocks * G_GUINT64_CONSTANT (512));
- t.tv_sec = statbuf->st_mtime;
+ size = have_statbuf ? statbuf->st_size : exstat->size;
+ g_file_info_set_size (info, size);
+
+ if (have_statbuf)
+ g_file_info_set_attribute_uint64 (info,
+ G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE,
+ statbuf->st_blocks * G_GUINT64_CONSTANT (512));
+
+ t.tv_sec = have_statbuf ? statbuf->st_mtime : exstat->mtime_ts.tv_sec;
+ if (have_statbuf)
+ {
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
- t.tv_usec = statbuf->st_mtimensec / 1000;
+ t.tv_usec = statbuf->st_mtimensec / 1000;
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
- t.tv_usec = statbuf->st_mtim.tv_nsec / 1000;
+ t.tv_usec = statbuf->st_mtim.tv_nsec / 1000;
#else
- t.tv_usec = 0;
+ t.tv_usec = 0;
#endif
+ }
+ else
+ t.tv_usec = exstat->mtime_ts.tv_nsec / 1000;
+
g_file_info_set_modification_time (info, &t);
@@ -1436,7 +1461,7 @@ set_info_from_stat (GVfsBackendSmb *backend,
content_type = NULL;
- if (S_ISDIR(statbuf->st_mode))
+ if (S_ISDIR (mode))
{
content_type = g_strdup ("inode/directory");
if (basename != NULL && strcmp (basename, "/") == 0)
@@ -1480,46 +1505,70 @@ set_info_from_stat (GVfsBackendSmb *backend,
/* Don't trust n_link, uid, gid, etc returned from libsmb, its just made up.
These are ok though: */
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE, statbuf->st_dev);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE, statbuf->st_ino);
+ if (have_statbuf)
+ {
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE, statbuf->st_dev);
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE, statbuf->st_ino);
+ }
/* If file is dos-readonly, libsmbclient doesn't set S_IWUSR, we use this to
trigger ACCESS_WRITE = FALSE. Only set for regular files, see
https://bugzilla.gnome.org/show_bug.cgi?id=598206 */
- if (S_ISREG (statbuf->st_mode))
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, statbuf->st_mode & S_IWUSR);
+ if (S_ISREG (mode))
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, mode & S_IWUSR);
g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS, statbuf->st_atime);
+ t.tv_sec = have_statbuf ? statbuf->st_atime : exstat->atime_ts.tv_sec;
+ if (have_statbuf)
+ {
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atimensec / 1000);
+ t.tv_usec = statbuf->st_atimensec / 1000);
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000);
+ t.tv_usec = statbuf->st_atim.tv_nsec / 1000;
+#else
+ t.tv_usec = 0;
#endif
- g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED, statbuf->st_ctime);
-#if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000);
-#elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC)
- g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, statbuf->st_ctim.tv_nsec / 1000);
+ }
+ else
+ t.tv_usec = exstat->atime_ts.tv_nsec / 1000;
+
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS, t.tv_sec);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC, t.tv_usec);
+
+ t.tv_sec = have_statbuf ? statbuf->st_ctime : exstat->ctime_ts.tv_sec;
+ if (have_statbuf)
+ {
+#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
+ t.tv_usec = statbuf->st_ctimensec / 1000);
+#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
+ t.tv_usec = statbuf->st_ctim.tv_nsec / 1000;
+#else
+ t.tv_usec = 0;
#endif
+ }
+ else
+ t.tv_usec = exstat->ctime_ts.tv_nsec / 1000;
+
+ g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED, t.tv_sec);
+ g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_CHANGED_USEC, t.tv_usec);
/* Libsmb sets the X bit on files to indicate some special things: */
- if ((statbuf->st_mode & S_IFDIR) == 0) {
-
- if (statbuf->st_mode & S_IXOTH)
- g_file_info_set_is_hidden (info, TRUE);
-
- if (statbuf->st_mode & S_IXUSR)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_ARCHIVE, TRUE);
-
- if (statbuf->st_mode & S_IXGRP)
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_SYSTEM, TRUE);
- }
+ if ((mode & S_IFDIR) == 0)
+ {
+ if (mode & S_IXOTH)
+ g_file_info_set_is_hidden (info, TRUE);
+
+ if (mode & S_IXUSR)
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_ARCHIVE, TRUE);
+
+ if (mode & S_IXGRP)
+ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_DOS_IS_SYSTEM, TRUE);
+ }
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_ETAG_VALUE))
{
- char *etag = create_etag (statbuf);
+ char *etag = create_etag (statbuf, exstat);
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag);
g_free (etag);
}
@@ -1549,7 +1598,7 @@ do_query_info (GVfsBackend *backend,
if (res == 0)
{
basename = g_path_get_basename (filename);
- set_info_from_stat (op_backend, info, &st, basename, matcher);
+ set_info_from_stat (op_backend, info, &st, NULL, basename, matcher);
g_free (basename);
g_vfs_job_succeeded (G_VFS_JOB (job));
@@ -1738,28 +1787,22 @@ do_enumerate (GVfsBackend *backend,
GFileQueryInfoFlags flags)
{
GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- struct stat st;
- int res;
GError *error;
SMBCFILE *dir;
- char dirents[1024*4];
- struct smbc_dirent *dirp;
+ const struct libsmb_file_info *exstat;
GFileInfo *info;
- GString *uri;
- int uri_start_len;
+ char *uri;
smbc_opendir_fn smbc_opendir;
- smbc_getdents_fn smbc_getdents;
- smbc_stat_fn smbc_stat;
+ smbc_readdirplus_fn smbc_readdirplus;
smbc_closedir_fn smbc_closedir;
- uri = create_smb_uri_string (op_backend->server, op_backend->port, op_backend->share, filename);
-
+ uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, filename);
+
smbc_opendir = smbc_getFunctionOpendir (op_backend->smb_context);
- smbc_getdents = smbc_getFunctionGetdents (op_backend->smb_context);
- smbc_stat = smbc_getFunctionStat (op_backend->smb_context);
+ smbc_readdirplus = smbc_getFunctionReaddirPlus (op_backend->smb_context);
smbc_closedir = smbc_getFunctionClosedir (op_backend->smb_context);
-
- dir = smbc_opendir (op_backend->smb_context, uri->str);
+
+ dir = smbc_opendir (op_backend->smb_context, uri);
if (dir == NULL)
{
@@ -1774,72 +1817,29 @@ do_enumerate (GVfsBackend *backend,
g_vfs_job_succeeded (G_VFS_JOB (job));
- if (uri->str[uri->len - 1] != '/')
- g_string_append_c (uri, '/');
- uri_start_len = uri->len;
-
- while (TRUE)
+ while ((exstat = smbc_readdirplus (op_backend->smb_context, dir)) != NULL)
{
- res = smbc_getdents (op_backend->smb_context, dir, (struct smbc_dirent *)dirents, sizeof (dirents));
- if (res <= 0)
- break;
-
- dirp = (struct smbc_dirent *)dirents;
- while (res > 0)
- {
- unsigned int dirlen;
-
- /* TODO: Only do stat if required for flags */
-
- if ((dirp->smbc_type == SMBC_DIR ||
- dirp->smbc_type == SMBC_FILE ||
- dirp->smbc_type == SMBC_LINK) &&
- strcmp (dirp->name, ".") != 0 &&
- strcmp (dirp->name, "..") != 0)
- {
- int stat_res;
- g_string_truncate (uri, uri_start_len);
- g_string_append_uri_escaped (uri, dirp->name, SUB_DELIM_CHARS ":@/", FALSE);
-
- if (matcher == NULL ||
- g_file_attribute_matcher_matches_only (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME))
- {
- info = g_file_info_new ();
- g_file_info_set_name (info, dirp->name);
- g_vfs_job_enumerate_add_info (job, info);
- g_object_unref (info);
- }
- else
- {
- stat_res = smbc_stat (op_backend->smb_context,
- uri->str, &st);
- if (stat_res == 0)
- {
- info = g_file_info_new ();
- set_info_from_stat (op_backend, info, &st, dirp->name, matcher);
- g_vfs_job_enumerate_add_info (job, info);
- g_object_unref (info);
- }
- }
- }
-
- dirlen = dirp->dirlen;
- dirp = (struct smbc_dirent *) (((char *)dirp) + dirlen);
- res -= dirlen;
- }
+ if (strcmp (exstat->name, ".") != 0 &&
+ strcmp (exstat->name, "..") != 0)
+ {
+ info = g_file_info_new ();
+ set_info_from_stat (op_backend, info, NULL, exstat, exstat->name, matcher);
+ g_vfs_job_enumerate_add_info (job, info);
+ g_object_unref (info);
+ }
}
-
- res = smbc_closedir (op_backend->smb_context, dir);
+
+ smbc_closedir (op_backend->smb_context, dir);
g_vfs_job_enumerate_done (job);
- g_string_free (uri, TRUE);
+ g_free (uri);
return;
-
+
error:
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
- g_string_free (uri, TRUE);
+ g_free (uri);
}
static void