Commit 0bd0114a authored by Jonathan Marten's avatar Jonathan Marten
Browse files

nfs: Improve the file handle cache handling and lookup

Ensure that URLs are cleaned of trailing slashes before using them
as a path or key into the file handle cache, so that the cache
matching will not be affected.

Do not store an invalid file handle in the cache, otherwise it can
end up getting used later.

Verify that a NFSFileHandle is valid by looking at the data/link size,
rather than using the separate m_isInvalid flag.  This automatically
verifies the validity of NFS file handles returned from an RPC call.
parent 7d0ce37f
......@@ -66,6 +66,19 @@ int kdemain(int argc, char** argv)
return 0;
}
// Both the insertion and lookup in the file handle cache (managed by
// NFSProtocol), and the use of QFileInfo to locate a parent directory,
// are sensitive to paths having trailing slashes. In order to keep
// everything consistent, any URLs passed in must be cleaned before using
// them as a fileystem or NFS protocol path.
static QUrl cleanPath(const QUrl &url)
{
return (url.adjusted(QUrl::StripTrailingSlash|QUrl::NormalizePathSegments));
}
NFSSlave::NFSSlave(const QByteArray& pool, const QByteArray& app)
: KIO::SlaveBase("nfs", pool, app),
m_protocol(nullptr)
......@@ -171,7 +184,7 @@ void NFSSlave::put(const QUrl& url, int _mode, KIO::JobFlags _flags)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->put(url, _mode, _flags);
m_protocol->put(cleanPath(url), _mode, _flags);
}
}
......@@ -180,7 +193,7 @@ void NFSSlave::get(const QUrl& url)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->get(url);
m_protocol->get(cleanPath(url));
}
}
......@@ -189,7 +202,7 @@ void NFSSlave::listDir(const QUrl& url)
qCDebug(LOG_KIO_NFS) << url;
if (verifyProtocol(url)) {
m_protocol->listDir(url);
m_protocol->listDir(cleanPath(url));
}
}
......@@ -198,7 +211,7 @@ void NFSSlave::symlink(const QString& target, const QUrl& dest, KIO::JobFlags _f
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(dest)) {
m_protocol->symlink(target, dest, _flags);
m_protocol->symlink(target, cleanPath(dest), _flags);
}
}
......@@ -207,7 +220,7 @@ void NFSSlave::stat(const QUrl& url)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->stat(url);
m_protocol->stat(cleanPath(url));
}
}
......@@ -216,7 +229,7 @@ void NFSSlave::mkdir(const QUrl& url, int permissions)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->mkdir(url, permissions);
m_protocol->mkdir(cleanPath(url), permissions);
}
}
......@@ -225,7 +238,7 @@ void NFSSlave::del(const QUrl& url, bool isfile)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->del(url, isfile);
m_protocol->del(cleanPath(url), isfile);
}
}
......@@ -234,7 +247,7 @@ void NFSSlave::chmod(const QUrl& url, int permissions)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(url)) {
m_protocol->chmod(url, permissions);
m_protocol->chmod(cleanPath(url), permissions);
}
}
......@@ -243,7 +256,7 @@ void NFSSlave::rename(const QUrl& src, const QUrl& dest, KIO::JobFlags flags)
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(src) && verifyProtocol(dest)) {
m_protocol->rename(src, dest, flags);
m_protocol->rename(cleanPath(src), cleanPath(dest), flags);
}
}
......@@ -252,7 +265,7 @@ void NFSSlave::copy(const QUrl& src, const QUrl& dest, int mode, KIO::JobFlags f
qCDebug(LOG_KIO_NFS);
if (verifyProtocol(src) && verifyProtocol(dest)) {
m_protocol->copy(src, dest, mode, flags);
m_protocol->copy(cleanPath(src), cleanPath(dest), mode, flags);
}
}
......@@ -310,10 +323,8 @@ NFSFileHandle::NFSFileHandle()
m_size(0),
m_linkHandle(nullptr),
m_linkSize(0),
m_isInvalid(true),
m_isLink(false)
{
}
NFSFileHandle::NFSFileHandle(const NFSFileHandle& src)
......@@ -385,7 +396,6 @@ NFSFileHandle& NFSFileHandle::operator=(const NFSFileHandle& src)
delete [] m_handle;
m_handle = nullptr;
}
m_size = src.m_size;
m_handle = new char[m_size];
memcpy(m_handle, src.m_handle, m_size);
......@@ -401,7 +411,6 @@ NFSFileHandle& NFSFileHandle::operator=(const NFSFileHandle& src)
memcpy(m_linkHandle, src.m_linkHandle, m_linkSize);
}
m_isInvalid = src.m_isInvalid;
m_isLink = src.m_isLink;
return *this;
}
......@@ -416,7 +425,6 @@ NFSFileHandle& NFSFileHandle::operator=(const fhandle3& src)
m_size = src.fhandle3_len;
m_handle = new char[m_size];
memcpy(m_handle, src.fhandle3_val, m_size);
m_isInvalid = false;
return *this;
}
......@@ -430,7 +438,6 @@ NFSFileHandle& NFSFileHandle::operator=(const fhandle& src)
m_size = NFS_FHSIZE;
m_handle = new char[m_size];
memcpy(m_handle, src, m_size);
m_isInvalid = false;
return *this;
}
......@@ -444,7 +451,6 @@ NFSFileHandle& NFSFileHandle::operator=(const nfs_fh3& src)
m_size = src.data.data_len;
m_handle = new char[m_size];
memcpy(m_handle, src.data.data_val, m_size);
m_isInvalid = false;
return *this;
}
......@@ -458,7 +464,6 @@ NFSFileHandle& NFSFileHandle::operator=(const nfs_fh& src)
m_size = NFS_FHSIZE;
m_handle = new char[m_size];
memcpy(m_handle, src.data, m_size);
m_isInvalid = false;
return *this;
}
......@@ -488,7 +493,6 @@ void NFSFileHandle::setLinkSource(const nfs_fh& src)
m_isLink = true;
}
NFSProtocol::NFSProtocol(NFSSlave* slave)
: m_slave(slave)
{
......@@ -544,7 +548,8 @@ void NFSProtocol::removeExportedDir(const QString& path)
void NFSProtocol::addFileHandle(const QString& path, NFSFileHandle fh)
{
m_handleCache.insert(path, fh);
if (fh.isInvalid()) qDebug() << "not adding" << path << "with invalid NFSFileHandle";
else m_handleCache.insert(path, fh);
}
NFSFileHandle NFSProtocol::getFileHandle(const QString& path)
......@@ -558,6 +563,10 @@ NFSFileHandle NFSProtocol::getFileHandle(const QString& path)
return NFSFileHandle();
}
if (path.endsWith('/')) {
qCWarning(LOG_KIO_NFS) << "Passed a path ending with '/'. Fix the caller.";
}
// The handle may already be in the cache, check it now.
// The exported dirs are always in the cache.
if (m_handleCache.contains(path)) {
......@@ -572,7 +581,7 @@ NFSFileHandle NFSProtocol::getFileHandle(const QString& path)
// Look up the file handle from the protocol
NFSFileHandle childFH = lookupFileHandle(path);
if (!childFH.isInvalid()) {
m_handleCache.insert(path, childFH);
addFileHandle(path, childFH);
}
return childFH;
......
......@@ -103,13 +103,8 @@ public:
bool isInvalid() const
{
return m_isInvalid;
return m_size==0 && m_linkSize==0;
}
void setInvalid()
{
m_isInvalid = true;
}
bool isLink() const
{
return m_isLink;
......@@ -134,13 +129,12 @@ protected:
// Set to the link source's handle.
char* m_linkHandle;
unsigned int m_linkSize;
bool m_isInvalid;
bool m_isLink;
};
typedef QMap<QString, NFSFileHandle> NFSFileHandleMap;
class NFSProtocol
{
public:
......
......@@ -61,6 +61,7 @@
#define NFS3_MAXDATA 32768
#define NFS3_MAXPATHLEN PATH_MAX
NFSProtocolV3::NFSProtocolV3(NFSSlave* slave)
: NFSProtocol(slave),
m_slave(slave),
......@@ -307,7 +308,6 @@ void NFSProtocolV3::listDir(const QUrl& url)
}
const QString path(url.path());
// Is it part of an exported(virtual) dir?
if (isExportedDir(path)) {
qCDebug(LOG_KIO_NFS) << "Listing virtual dir" << path;
......@@ -458,8 +458,8 @@ void NFSProtocolV3::listDir(const QUrl& url)
completeBadLinkUDSEntry(entry, dirEntry->name_attributes.post_op_attr_u.attributes);
}
} else {
addFileHandle(filePath, static_cast<NFSFileHandle>(dirEntry->name_handle.post_op_fh3_u.handle));
NFSFileHandle entryFH = dirEntry->name_handle.post_op_fh3_u.handle;
addFileHandle(filePath, entryFH);
completeUDSEntry(entry, dirEntry->name_attributes.post_op_attr_u.attributes);
}
......@@ -485,7 +485,6 @@ void NFSProtocolV3::listDirCompat(const QUrl& url)
}
const QString path(url.path());
// Is it part of an exported (virtual) dir?
if (NFSProtocol::isExportedDir(path)) {
QStringList virtualList;
......@@ -639,7 +638,6 @@ void NFSProtocolV3::stat(const QUrl& url)
qCDebug(LOG_KIO_NFS) << url;
const QString path(url.path());
// We can't stat an exported dir, but we know it's a dir.
if (isExportedDir(path)) {
KIO::UDSEntry entry;
......@@ -746,7 +744,6 @@ void NFSProtocolV3::mkdir(const QUrl& url, int permissions)
qCDebug(LOG_KIO_NFS) << url;
const QString path(url.path());
const QFileInfo fileInfo(path);
if (isExportedDir(fileInfo.path())) {
m_slave->error(KIO::ERR_ACCESS_DENIED, path);
......@@ -793,7 +790,6 @@ void NFSProtocolV3::del(const QUrl& url, bool/* isfile*/)
qCDebug(LOG_KIO_NFS) << url;
const QString path(url.path());
if (isExportedDir(QFileInfo(path).path())) {
m_slave->error(KIO::ERR_ACCESS_DENIED, path);
return;
......@@ -839,7 +835,6 @@ void NFSProtocolV3::get(const QUrl& url)
qCDebug(LOG_KIO_NFS) << url;
const QString path(url.path());
const NFSFileHandle fh = getFileHandle(path);
if (fh.isInvalid() || fh.isBadLink()) {
m_slave->error(KIO::ERR_DOES_NOT_EXIST, path);
......@@ -929,7 +924,6 @@ void NFSProtocolV3::put(const QUrl& url, int _mode, KIO::JobFlags flags)
qCDebug(LOG_KIO_NFS) << url;
const QString destPath(url.path());
if (isExportedDir(QFileInfo(destPath).path())) {
m_slave->error(KIO::ERR_WRITE_ACCESS_DENIED, destPath);
return;
......@@ -1064,7 +1058,6 @@ void NFSProtocolV3::copySame(const QUrl& src, const QUrl& dest, int _mode, KIO::
qCDebug(LOG_KIO_NFS) << src << "to" << dest;
const QString srcPath(src.path());
if (isExportedDir(QFileInfo(srcPath).path())) {
m_slave->error(KIO::ERR_ACCESS_DENIED, srcPath);
return;
......@@ -1077,7 +1070,6 @@ void NFSProtocolV3::copySame(const QUrl& src, const QUrl& dest, int _mode, KIO::
}
const QString destPath(dest.path());
if (isExportedDir(QFileInfo(destPath).path())) {
m_slave->error(KIO::ERR_ACCESS_DENIED, destPath);
return;
......@@ -1301,7 +1293,6 @@ void NFSProtocolV3::copyFrom(const QUrl& src, const QUrl& dest, int _mode, KIO::
qCDebug(LOG_KIO_NFS) << src << "to" << dest;
const QString srcPath(src.path());
const NFSFileHandle srcFH = getFileHandle(srcPath);
if (srcFH.isInvalid()) {
m_slave->error(KIO::ERR_DOES_NOT_EXIST, srcPath);
......@@ -1309,7 +1300,6 @@ void NFSProtocolV3::copyFrom(const QUrl& src, const QUrl& dest, int _mode, KIO::
}
const QString destPath(dest.path());
// The file exists and we don't want to overwrite.
if (QFile::exists(destPath) && (_flags & KIO::Overwrite) == 0) {
m_slave->error(KIO::ERR_FILE_ALREADY_EXIST, destPath);
......@@ -1714,7 +1704,6 @@ void NFSProtocolV3::copyTo(const QUrl& src, const QUrl& dest, int _mode, KIO::Jo
void NFSProtocolV3::symlink(const QString& target, const QUrl& dest, KIO::JobFlags flags)
{
const QString destPath(dest.path());
if (isExportedDir(QFileInfo(destPath).path())) {
m_slave->error(KIO::ERR_ACCESS_DENIED, destPath);
return;
......
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