From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kioslave/trash/kio_trash.cpp | 596 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 kioslave/trash/kio_trash.cpp (limited to 'kioslave/trash/kio_trash.cpp') diff --git a/kioslave/trash/kio_trash.cpp b/kioslave/trash/kio_trash.cpp new file mode 100644 index 000000000..7912cbb7c --- /dev/null +++ b/kioslave/trash/kio_trash.cpp @@ -0,0 +1,596 @@ +/* This file is part of the KDE project + Copyright (C) 2004 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kio_trash.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static const KCmdLineOptions options[] = +{ + { "+protocol", I18N_NOOP( "Protocol name" ), 0 }, + { "+pool", I18N_NOOP( "Socket name" ), 0 }, + { "+app", I18N_NOOP( "Socket name" ), 0 }, + KCmdLineLastOption +}; + +extern "C" { + int KDE_EXPORT kdemain( int argc, char **argv ) + { + //KInstance instance( "kio_trash" ); + // KApplication is necessary to use kio_file + putenv(strdup("SESSION_MANAGER=")); + KApplication::disableAutoDcopRegistration(); + KCmdLineArgs::init(argc, argv, "kio_trash", 0, 0, 0, 0); + KCmdLineArgs::addCmdLineOptions( options ); + KApplication app( false, false ); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + TrashProtocol slave( args->arg(0), args->arg(1), args->arg(2) ); + slave.dispatchLoop(); + return 0; + } +} + +#define INIT_IMPL \ + if ( !impl.init() ) { \ + error( impl.lastErrorCode(), impl.lastErrorMessage() ); \ + return; \ + } + +TrashProtocol::TrashProtocol( const QCString& protocol, const QCString &pool, const QCString &app) + : SlaveBase(protocol, pool, app ) +{ + struct passwd *user = getpwuid( getuid() ); + if ( user ) + m_userName = QString::fromLatin1(user->pw_name); + struct group *grp = getgrgid( getgid() ); + if ( grp ) + m_groupName = QString::fromLatin1(grp->gr_name); +} + +TrashProtocol::~TrashProtocol() +{ +} + +void TrashProtocol::restore( const KURL& trashURL ) +{ + int trashId; + QString fileId, relativePath; + bool ok = TrashImpl::parseURL( trashURL, trashId, fileId, relativePath ); + if ( !ok ) { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1" ).arg( trashURL.prettyURL() ) ); + return; + } + TrashedFileInfo info; + ok = impl.infoForFile( trashId, fileId, info ); + if ( !ok ) { + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + return; + } + KURL dest; + dest.setPath( info.origPath ); + if ( !relativePath.isEmpty() ) + dest.addPath( relativePath ); + + // Check that the destination directory exists, to improve the error code in case it doesn't. + const QString destDir = dest.directory(); + KDE_struct_stat buff; + if ( KDE_lstat( QFile::encodeName( destDir ), &buff ) == -1 ) { + error( KIO::ERR_SLAVE_DEFINED, + i18n( "The directory %1 does not exist anymore, so it is not possible to restore this item to its original location. " + "You can either recreate that directory and use the restore operation again, or drag the item anywhere else to restore it." ).arg( destDir ) ); + return; + } + + copyOrMove( trashURL, dest, false /*overwrite*/, Move ); +} + +void TrashProtocol::rename( const KURL &oldURL, const KURL &newURL, bool overwrite ) +{ + INIT_IMPL; + + kdDebug()<<"TrashProtocol::rename(): old="< 1 ) { + fileURL = url.url(); + } + + KIO::UDSEntry entry; + TrashedFileInfo info; + ok = impl.infoForFile( trashId, fileId, info ); + if ( ok ) + ok = createUDSEntry( filePath, fileName, fileURL, entry, info ); + + if ( !ok ) { + error( KIO::ERR_COULD_NOT_STAT, url.prettyURL() ); + } + + statEntry( entry ); + finished(); + } +} + +void TrashProtocol::del( const KURL &url, bool /*isfile*/ ) +{ + int trashId; + QString fileId, relativePath; + + bool ok = TrashImpl::parseURL( url, trashId, fileId, relativePath ); + if ( !ok ) { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1" ).arg( url.prettyURL() ) ); + return; + } + + ok = relativePath.isEmpty(); + if ( !ok ) { + error( KIO::ERR_ACCESS_DENIED, url.prettyURL() ); + return; + } + + ok = impl.del(trashId, fileId); + if ( !ok ) { + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + return; + } + + finished(); +} + +void TrashProtocol::listDir(const KURL& url) +{ + INIT_IMPL; + kdDebug() << "listdir: " << url << endl; + if ( url.path().length() <= 1 ) { + listRoot(); + return; + } + int trashId; + QString fileId; + QString relativePath; + bool ok = TrashImpl::parseURL( url, trashId, fileId, relativePath ); + if ( !ok ) { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1" ).arg( url.prettyURL() ) ); + return; + } + //was: const QString physicalPath = impl.physicalPath( trashId, fileId, relativePath ); + + // Get info for deleted directory - the date of deletion and orig path will be used + // for all the items in it, and we need the physicalPath. + TrashedFileInfo info; + ok = impl.infoForFile( trashId, fileId, info ); + if ( !ok || info.physicalPath.isEmpty() ) { + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + return; + } + if ( !relativePath.isEmpty() ) { + info.physicalPath += "/"; + info.physicalPath += relativePath; + } + + // List subdir. Can't use kio_file here since we provide our own info... + kdDebug() << k_funcinfo << "listing " << info.physicalPath << endl; + QStrList entryNames = impl.listDir( info.physicalPath ); + totalSize( entryNames.count() ); + KIO::UDSEntry entry; + QStrListIterator entryIt( entryNames ); + for (; entryIt.current(); ++entryIt) { + QString fileName = QFile::decodeName( entryIt.current() ); + if ( fileName == ".." ) + continue; + const QString filePath = info.physicalPath + "/" + fileName; + // shouldn't be necessary + //const QString url = TrashImpl::makeURL( trashId, fileId, relativePath + "/" + fileName ); + entry.clear(); + TrashedFileInfo infoForItem( info ); + infoForItem.origPath += '/'; + infoForItem.origPath += fileName; + if ( ok && createUDSEntry( filePath, fileName, QString::null /*url*/, entry, infoForItem ) ) { + listEntry( entry, false ); + } + } + entry.clear(); + listEntry( entry, true ); + finished(); +} + +bool TrashProtocol::createUDSEntry( const QString& physicalPath, const QString& fileName, const QString& url, KIO::UDSEntry& entry, const TrashedFileInfo& info ) +{ + QCString physicalPath_c = QFile::encodeName( physicalPath ); + KDE_struct_stat buff; + if ( KDE_lstat( physicalPath_c, &buff ) == -1 ) { + kdWarning() << "couldn't stat " << physicalPath << endl; + return false; + } + if (S_ISLNK(buff.st_mode)) { + char buffer2[ 1000 ]; + int n = readlink( physicalPath_c, buffer2, 1000 ); + if ( n != -1 ) { + buffer2[ n ] = 0; + } + + addAtom( entry, KIO::UDS_LINK_DEST, 0, QFile::decodeName( buffer2 ) ); + // Follow symlink + // That makes sense in kio_file, but not in the trash, especially for the size + // #136876 +#if 0 + if ( KDE_stat( physicalPath_c, &buff ) == -1 ) { + // It is a link pointing to nowhere + buff.st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + buff.st_mtime = 0; + buff.st_atime = 0; + buff.st_size = 0; + } +#endif + } + mode_t type = buff.st_mode & S_IFMT; // extract file type + mode_t access = buff.st_mode & 07777; // extract permissions + access &= 07555; // make it readonly, since it's in the trashcan + addAtom( entry, KIO::UDS_NAME, 0, fileName ); + addAtom( entry, KIO::UDS_FILE_TYPE, type ); + if ( !url.isEmpty() ) + addAtom( entry, KIO::UDS_URL, 0, url ); + + KMimeType::Ptr mt = KMimeType::findByPath( physicalPath, buff.st_mode ); + addAtom( entry, KIO::UDS_MIME_TYPE, 0, mt->name() ); + addAtom( entry, KIO::UDS_ACCESS, access ); + addAtom( entry, KIO::UDS_SIZE, buff.st_size ); + addAtom( entry, KIO::UDS_USER, 0, m_userName ); // assumption + addAtom( entry, KIO::UDS_GROUP, 0, m_groupName ); // assumption + addAtom( entry, KIO::UDS_MODIFICATION_TIME, buff.st_mtime ); + addAtom( entry, KIO::UDS_ACCESS_TIME, buff.st_atime ); // ## or use it for deletion time? + addAtom( entry, KIO::UDS_EXTRA, 0, info.origPath ); + addAtom( entry, KIO::UDS_EXTRA, 0, info.deletionDate.toString( Qt::ISODate ) ); + return true; +} + +void TrashProtocol::listRoot() +{ + INIT_IMPL; + const TrashedFileInfoList lst = impl.list(); + totalSize( lst.count() ); + KIO::UDSEntry entry; + createTopLevelDirEntry( entry ); + listEntry( entry, false ); + for ( TrashedFileInfoList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + const KURL url = TrashImpl::makeURL( (*it).trashId, (*it).fileId, QString::null ); + KURL origURL; + origURL.setPath( (*it).origPath ); + entry.clear(); + if ( createUDSEntry( (*it).physicalPath, origURL.fileName(), url.url(), entry, *it ) ) + listEntry( entry, false ); + } + entry.clear(); + listEntry( entry, true ); + finished(); +} + +void TrashProtocol::special( const QByteArray & data ) +{ + INIT_IMPL; + QDataStream stream( data, IO_ReadOnly ); + int cmd; + stream >> cmd; + + switch (cmd) { + case 1: + if ( impl.emptyTrash() ) + finished(); + else + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + break; + case 2: + impl.migrateOldTrash(); + finished(); + break; + case 3: + { + KURL url; + stream >> url; + restore( url ); + break; + } + default: + kdWarning(7116) << "Unknown command in special(): " << cmd << endl; + error( KIO::ERR_UNSUPPORTED_ACTION, QString::number(cmd) ); + break; + } +} + +void TrashProtocol::put( const KURL& url, int /*permissions*/, bool /*overwrite*/, bool /*resume*/ ) +{ + INIT_IMPL; + kdDebug() << "put: " << url << endl; + // create deleted file. We need to get the mtime and original location from metadata... + // Maybe we can find the info file for url.fileName(), in case ::rename() was called first, and failed... + error( KIO::ERR_ACCESS_DENIED, url.prettyURL() ); +} + +void TrashProtocol::get( const KURL& url ) +{ + INIT_IMPL; + kdDebug() << "get() : " << url << endl; + if ( !url.isValid() ) { + kdDebug() << kdBacktrace() << endl; + error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1" ).arg( url.url() ) ); + return; + } + if ( url.path().length() <= 1 ) { + error( KIO::ERR_IS_DIRECTORY, url.prettyURL() ); + return; + } + int trashId; + QString fileId; + QString relativePath; + bool ok = TrashImpl::parseURL( url, trashId, fileId, relativePath ); + if ( !ok ) { + error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1" ).arg( url.prettyURL() ) ); + return; + } + const QString physicalPath = impl.physicalPath( trashId, fileId, relativePath ); + if ( physicalPath.isEmpty() ) { + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + return; + } + + // Usually we run jobs in TrashImpl (for e.g. future kdedmodule) + // But for this one we wouldn't use DCOP for every bit of data... + KURL fileURL; + fileURL.setPath( physicalPath ); + KIO::Job* job = KIO::get( fileURL ); + connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), + this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) ); + connect( job, SIGNAL( mimetype( KIO::Job*, const QString& ) ), + this, SLOT( slotMimetype( KIO::Job*, const QString& ) ) ); + connect( job, SIGNAL( result(KIO::Job *) ), + this, SLOT( jobFinished(KIO::Job *) ) ); + qApp->eventLoop()->enterLoop(); +} + +void TrashProtocol::slotData( KIO::Job*, const QByteArray&arr ) +{ + data( arr ); +} + +void TrashProtocol::slotMimetype( KIO::Job*, const QString& mt ) +{ + mimeType( mt ); +} + +void TrashProtocol::jobFinished( KIO::Job* job ) +{ + if ( job->error() ) + error( job->error(), job->errorText() ); + else + finished(); + qApp->eventLoop()->exitLoop(); +} + +#if 0 +void TrashProtocol::mkdir( const KURL& url, int /*permissions*/ ) +{ + INIT_IMPL; + // create info about deleted dir + // ############ Problem: we don't know the original path. + // Let's try to avoid this case (we should get to copy() instead, for local files) + kdDebug() << "mkdir: " << url << endl; + QString dir = url.directory(); + + if ( dir.length() <= 1 ) // new toplevel entry + { + // ## we should use TrashImpl::parseURL to give the right filename to createInfo + int trashId; + QString fileId; + if ( !impl.createInfo( url.path(), trashId, fileId ) ) { + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + } else { + if ( !impl.mkdir( trashId, fileId, permissions ) ) { + (void)impl.deleteInfo( trashId, fileId ); + error( impl.lastErrorCode(), impl.lastErrorMessage() ); + } else + finished(); + } + } else { + // Well it's not allowed to add a directory to an existing deleted directory. + error( KIO::ERR_ACCESS_DENIED, url.prettyURL() ); + } +} +#endif + +#include "kio_trash.moc" -- cgit v1.2.1