Commit ec40cd6e authored by Harald Sitter's avatar Harald Sitter 🏳🌈
Browse files

add readdirplus2 support for samba>=4.12

Summary:
unlike the dirent itering we do not need a separate stat call with this
new api by instead itering on what are effectively stat-like objects.

this simply runs before the regular itering which we still use to list
shares and workgroups. browse_stat_path has been split into stat and
udsentry-construction-from-stat so it can be used across both code
paths.

fun fact on the side: if there actually was a stat() api that returned
libsmb_file_info, we could use that as well and forget about the stats
structs in general :S

BUG: 402988
FIXED-IN: 20.04.0

Test Plan:
- build samba 4.12 rc
- list server
- list share
- list dir in share

- on 4.7
- all of the above

Reviewers: ngraham, asn

Reviewed By: ngraham

Subscribers: kde-frameworks-devel, kfm-devel

Tags: #dolphin, #frameworks

Differential Revision: https://phabricator.kde.org/D27520

# Conflicts:
#	smb/CMakeLists.txt
#	smb/kio_smb.h
#	smb/kio_smb_browse.cpp
parent 82528611
......@@ -19,8 +19,15 @@ add_feature_info("SMB DNS-SD Discovery" HAVE_KDNSSD_WITH_SIGNAL_RACE_PROTECTION
add_definitions(-DTRANSLATION_DOMAIN=\"kio5_smb\")
include(CheckIncludeFile)
include(CheckSymbolExists)
include(CMakePushCheckState)
set(CMAKE_AUTOMAKE ON)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES ${SAMBA_INCLUDE_DIR})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${SAMBA_LIBRARIES})
check_symbol_exists(smbc_readdirplus2 "libsmbclient.h" HAVE_READDIRPLUS2)
cmake_pop_check_state()
check_include_file(utime.h HAVE_UTIME_H)
configure_file(config-smb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-smb.h)
......
/* Define to 1 if you have the <utime.h> header file. */
#cmakedefine HAVE_UTIME_H 1
#cmakedefine HAVE_READDIRPLUS2 1
......@@ -266,7 +266,7 @@ private:
void smbCopyGet(const QUrl &ksrc, const QUrl &kdst, int permissions, KIO::JobFlags flags);
void smbCopyPut(const QUrl &ksrc, const QUrl &kdst, int permissions, KIO::JobFlags flags);
bool workaroundEEXIST(const int errNum) const;
int statToUDSEntry(const QUrl &url, const struct stat &st, KIO::UDSEntry &udsentry);
void fileSystemFreeSpace(const QUrl &url);
/**
......
......@@ -69,65 +69,71 @@ int SMBSlave::browse_stat_path(const SMBUrl &url, UDSEntry &udsentry)
{
int cacheStatErr = cache_stat(url, &st);
if (cacheStatErr == 0) {
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
qCDebug(KIO_SMB_LOG) << "mode: " << st.st_mode;
warning(
i18n("%1:\n"
return statToUDSEntry(url, st, udsentry);
}
return cacheStatErr;
}
int SMBSlave::statToUDSEntry(const QUrl &url, const struct stat &st, KIO::UDSEntry &udsentry)
{
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
qCDebug(KIO_SMB_LOG) << "mode: "<< st.st_mode;
warning(i18n("%1:\n"
"Unknown file type, neither directory or file.",
url.toDisplayString()));
return EINVAL;
}
return EINVAL;
}
if (!S_ISDIR(st.st_mode)) {
// Awkwardly documented at
// https://www.samba.org/samba/docs/using_samba/ch08.html
// libsmb_stat.c assigns special meaning to +x permissions
// (obviously only on files, all dirs are +x so this hacky representation
// wouldn't work!):
// - S_IXUSR = DOS archive: This file has been touched since the last DOS backup was performed on it.
// - S_IXGRP = DOS system: This file has a specific purpose required by the operating system.
// - S_IXOTH = DOS hidden: This file has been marked to be invisible to the user, unless the operating system is explicitly set to show it.
// Only hiding has backing through KIO right now.
if (st.st_mode & S_IXOTH) { // DOS hidden
udsentry.fastInsert(KIO::UDSEntry::UDS_HIDDEN, true);
}
if (!S_ISDIR(st.st_mode)) {
// Awkwardly documented at
// https://www.samba.org/samba/docs/using_samba/ch08.html
// libsmb_stat.c assigns special meaning to +x permissions
// (obviously only on files, all dirs are +x so this hacky representation
// wouldn't work!):
// - S_IXUSR = DOS archive: This file has been touched since the last DOS backup was performed on it.
// - S_IXGRP = DOS system: This file has a specific purpose required by the operating system.
// - S_IXOTH = DOS hidden: This file has been marked to be invisible to the user, unless the operating system is explicitly set to show it.
// Only hiding has backing through KIO right now.
if (st.st_mode & S_IXOTH) { // DOS hidden
udsentry.fastInsert(KIO::UDSEntry::UDS_HIDDEN, true);
}
// UID and GID **must** not be mapped. The values returned by libsmbclient are
// simply the getuid/getgid of the process. They mean absolutely nothing.
// Also see libsmb_stat.c.
// Related: https://bugs.kde.org/show_bug.cgi?id=212801
// POSIX Access mode must not be mapped either!
// It's meaningless for smb shares and downright disadvantagous.
// The mode attributes outside the ones used and document above are
// useless. The only one actively set is readonlyness.
//
// BUT the READONLY attribute does nothing on NT systems:
// https://support.microsoft.com/en-us/help/326549/you-cannot-view-or-change-the-read-only-or-the-system-attributes-of-fo
// The Read-only and System attributes is only used by Windows Explorer to determine
// whether the folder is a special folder, such as a system folder that has its view
// customized by Windows (for example, My Documents, Favorites, Fonts, Downloaded Program Files),
// or a folder that you customized by using the Customize tab of the folder's Properties dialog box.
//
// As such respecting it on a KIO level is actually wrong as it doesn't indicate actual
// readonlyness since the 90s and causes us to show readonly UI states when in fact
// the directory is perfectly writable.
// https://bugs.kde.org/show_bug.cgi?id=414482
//
// Should we ever want to parse desktop.ini like we do .directory we'd only want to when a
// dir is readonly as per the above microsoft support article.
// Also see:
// https://docs.microsoft.com/en-us/windows/win32/shell/how-to-customize-folders-with-desktop-ini
udsentry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, st.st_mode & S_IFMT);
udsentry.fastInsert(KIO::UDSEntry::UDS_SIZE, st.st_size);
udsentry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, st.st_mtime);
udsentry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, st.st_atime);
// No, st_ctime is not UDS_CREATION_TIME...
}
return cacheStatErr;
// UID and GID **must** not be mapped. The values returned by libsmbclient are
// simply the getuid/getgid of the process. They mean absolutely nothing.
// Also see libsmb_stat.c.
// Related: https://bugs.kde.org/show_bug.cgi?id=212801
// POSIX Access mode must not be mapped either!
// It's meaningless for smb shares and downright disadvantagous.
// The mode attributes outside the ones used and document above are
// useless. The only one actively set is readonlyness.
//
// BUT the READONLY attribute does nothing on NT systems:
// https://support.microsoft.com/en-us/help/326549/you-cannot-view-or-change-the-read-only-or-the-system-attributes-of-fo
// The Read-only and System attributes is only used by Windows Explorer to determine
// whether the folder is a special folder, such as a system folder that has its view
// customized by Windows (for example, My Documents, Favorites, Fonts, Downloaded Program Files),
// or a folder that you customized by using the Customize tab of the folder's Properties dialog box.
//
// As such respecting it on a KIO level is actually wrong as it doesn't indicate actual
// readonlyness since the 90s and causes us to show readonly UI states when in fact
// the directory is perfectly writable.
// https://bugs.kde.org/show_bug.cgi?id=414482
//
// Should we ever want to parse desktop.ini like we do .directory we'd only want to when a
// dir is readonly as per the above microsoft support article.
// Also see:
// https://docs.microsoft.com/en-us/windows/win32/shell/how-to-customize-folders-with-desktop-ini
udsentry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, st.st_mode & S_IFMT);
udsentry.fastInsert(KIO::UDSEntry::UDS_SIZE, st.st_size);
udsentry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, st.st_mtime);
udsentry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, st.st_atime);
// No, st_ctime is not UDS_CREATION_TIME...
return 0;
}
void SMBSlave::stat(const QUrl &kurl)
......@@ -369,6 +375,27 @@ void SMBSlave::listDir(const QUrl &kurl)
qCDebug(KIO_SMB_LOG) << "open " << m_current_url.toSmbcUrl() << " " << m_current_url.getType() << " " << dirfd;
if (dirfd >= 0) {
#ifdef HAVE_READDIRPLUS2
// readdirplus2 improves performance by giving us a stat without separate call (Samba>=4.12)
while (const struct libsmb_file_info *fileInfo = smbc_readdirplus2(dirfd, &st)) {
const QString name = QString::fromUtf8(fileInfo->name);
if (name == ".") {
continue;
} else if (name == "..") {
dir_is_root = false;
continue;
}
udsentry.fastInsert( KIO::UDSEntry::UDS_NAME, name);
m_current_url.addPath(name);
statToUDSEntry(m_current_url, st, udsentry); // won't produce useful error
listEntry(udsentry);
m_current_url.cd("..");
udsentry.clear();
}
#endif // HAVE_READDIRPLUS2
uint direntCount = 0;
do {
qCDebug(KIO_SMB_LOG) << "smbc_readdir ";
......@@ -411,6 +438,7 @@ void SMBSlave::listDir(const QUrl &kurl)
// fprintf(stderr,"----------- hide: -%s-\n",dirp->name);
// do nothing and hide the hidden shares
} else if (dirp->smbc_type == SMBC_FILE || dirp->smbc_type == SMBC_DIR) {
#if !defined(HAVE_READDIRPLUS2)
// Set stat information
m_current_url.addPath(dirpName);
const int statErr = browse_stat_path(m_current_url, udsentry);
......@@ -424,6 +452,7 @@ void SMBSlave::listDir(const QUrl &kurl)
}
m_current_url.cdUp();
} else if (dirp->smbc_type == SMBC_SERVER || dirp->smbc_type == SMBC_FILE_SHARE) {
#endif // HAVE_READDIRPLUS2
// Set type
udsentry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment