summaryrefslogtreecommitdiffstats
path: root/tdeio/tdeio/chmodjob.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeio/tdeio/chmodjob.cpp')
-rw-r--r--tdeio/tdeio/chmodjob.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/tdeio/tdeio/chmodjob.cpp b/tdeio/tdeio/chmodjob.cpp
new file mode 100644
index 000000000..434466d77
--- /dev/null
+++ b/tdeio/tdeio/chmodjob.cpp
@@ -0,0 +1,258 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
+ David Faure <faure@kde.org>
+ Waldo Bastian <bastian@kde.org>
+
+ 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 <config.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <tqtimer.h>
+#include <tqfile.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "tdeio/job.h"
+#include "tdeio/chmodjob.h"
+
+#include <kdirnotify_stub.h>
+
+using namespace TDEIO;
+
+ChmodJob::ChmodJob( const KFileItemList& lstItems, int permissions, int mask,
+ int newOwner, int newGroup,
+ bool recursive, bool showProgressInfo )
+ : TDEIO::Job( showProgressInfo ), state( STATE_LISTING ),
+ m_permissions( permissions ), m_mask( mask ),
+ m_newOwner( newOwner ), m_newGroup( newGroup ),
+ m_recursive( recursive ), m_lstItems( lstItems )
+{
+ TQTimer::singleShot( 0, this, TQT_SLOT(processList()) );
+}
+
+void ChmodJob::processList()
+{
+ while ( !m_lstItems.isEmpty() )
+ {
+ KFileItem * item = m_lstItems.first();
+ if ( !item->isLink() ) // don't do anything with symlinks
+ {
+ // File or directory -> remember to chmod
+ ChmodInfo info;
+ info.url = item->url();
+ // This is a toplevel file, we apply changes directly (no +X emulation here)
+ info.permissions = ( m_permissions & m_mask ) | ( item->permissions() & ~m_mask );
+ /*kdDebug(7007) << "\n current permissions=" << TQString::number(item->permissions(),8)
+ << "\n wanted permission=" << TQString::number(m_permissions,8)
+ << "\n with mask=" << TQString::number(m_mask,8)
+ << "\n with ~mask (mask bits we keep) =" << TQString::number((uint)~m_mask,8)
+ << "\n bits we keep =" << TQString::number(item->permissions() & ~m_mask,8)
+ << "\n new permissions = " << TQString::number(info.permissions,8)
+ << endl;*/
+ m_infos.prepend( info );
+ //kdDebug(7007) << "processList : Adding info for " << info.url.prettyURL() << endl;
+ // Directory and recursive -> list
+ if ( item->isDir() && m_recursive )
+ {
+ //kdDebug(7007) << "ChmodJob::processList dir -> listing" << endl;
+ TDEIO::ListJob * listJob = TDEIO::listRecursive( item->url(), false /* no GUI */ );
+ connect( listJob, TQT_SIGNAL(entries( TDEIO::Job *,
+ const TDEIO::UDSEntryList& )),
+ TQT_SLOT( slotEntries( TDEIO::Job*,
+ const TDEIO::UDSEntryList& )));
+ addSubjob( listJob );
+ return; // we'll come back later, when this one's finished
+ }
+ }
+ m_lstItems.removeFirst();
+ }
+ kdDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING" << endl;
+ // We have finished, move on
+ state = STATE_CHMODING;
+ chmodNextFile();
+}
+
+void ChmodJob::slotEntries( TDEIO::Job*, const TDEIO::UDSEntryList & list )
+{
+ TDEIO::UDSEntryListConstIterator it = list.begin();
+ TDEIO::UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it) {
+ TDEIO::UDSEntry::ConstIterator it2 = (*it).begin();
+ mode_t permissions = 0;
+ bool isDir = false;
+ bool isLink = false;
+ TQString relativePath;
+ for( ; it2 != (*it).end(); it2++ ) {
+ switch( (*it2).m_uds ) {
+ case TDEIO::UDS_NAME:
+ relativePath = (*it2).m_str;
+ break;
+ case TDEIO::UDS_FILE_TYPE:
+ isDir = S_ISDIR((*it2).m_long);
+ break;
+ case TDEIO::UDS_LINK_DEST:
+ isLink = !(*it2).m_str.isEmpty();
+ break;
+ case TDEIO::UDS_ACCESS:
+ permissions = (mode_t)((*it2).m_long);
+ break;
+ default:
+ break;
+ }
+ }
+ if ( !isLink && relativePath != TQString::fromLatin1("..") )
+ {
+ ChmodInfo info;
+ info.url = m_lstItems.first()->url(); // base directory
+ info.url.addPath( relativePath );
+ int mask = m_mask;
+ // Emulate -X: only give +x to files that had a +x bit already
+ // So the check is the opposite : if the file had no x bit, don't touch x bits
+ // For dirs this doesn't apply
+ if ( !isDir )
+ {
+ int newPerms = m_permissions & mask;
+ if ( (newPerms & 0111) && !(permissions & 0111) )
+ {
+ // don't interfere with mandatory file locking
+ if ( newPerms & 02000 )
+ mask = mask & ~0101;
+ else
+ mask = mask & ~0111;
+ }
+ }
+ info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
+ /*kdDebug(7007) << "\n current permissions=" << TQString::number(permissions,8)
+ << "\n wanted permission=" << TQString::number(m_permissions,8)
+ << "\n with mask=" << TQString::number(mask,8)
+ << "\n with ~mask (mask bits we keep) =" << TQString::number((uint)~mask,8)
+ << "\n bits we keep =" << TQString::number(permissions & ~mask,8)
+ << "\n new permissions = " << TQString::number(info.permissions,8)
+ << endl;*/
+ // Prepend this info in our todo list.
+ // This way, the toplevel dirs are done last.
+ m_infos.prepend( info );
+ }
+ }
+}
+
+void ChmodJob::chmodNextFile()
+{
+ if ( !m_infos.isEmpty() )
+ {
+ ChmodInfo info = m_infos.first();
+ m_infos.remove( m_infos.begin() );
+ // First update group / owner (if local file)
+ // (permissions have to set after, in case of suid and sgid)
+ if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
+ {
+ TQString path = info.url.path();
+ if ( chown( TQFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
+ {
+ int answer = KMessageBox::warningContinueCancel( 0, i18n( "<qt>Could not modify the ownership of file <b>%1</b>. You have insufficient access to the file to perform the change.</qt>" ).arg(path), TQString::null, i18n("&Skip File") );
+ if (answer == KMessageBox::Cancel)
+ {
+ m_error = ERR_USER_CANCELED;
+ emitResult();
+ return;
+ }
+ }
+ }
+
+ kdDebug(7007) << "ChmodJob::chmodNextFile chmod'ing " << info.url.prettyURL()
+ << " to " << TQString::number(info.permissions,8) << endl;
+ TDEIO::SimpleJob * job = TDEIO::chmod( info.url, info.permissions );
+ // copy the metadata for acl and default acl
+ const TQString aclString = queryMetaData( "ACL_STRING" );
+ const TQString defaultAclString = queryMetaData( "DEFAULT_ACL_STRING" );
+ if ( !aclString.isEmpty() )
+ job->addMetaData( "ACL_STRING", aclString );
+ if ( !defaultAclString.isEmpty() )
+ job->addMetaData( "DEFAULT_ACL_STRING", defaultAclString );
+ addSubjob(job);
+ }
+ else
+ // We have finished
+ emitResult();
+}
+
+void ChmodJob::slotResult( TDEIO::Job * job )
+{
+ if ( job->error() )
+ {
+ m_error = job->error();
+ m_errorText = job->errorText();
+ emitResult();
+ return;
+ }
+ //kdDebug(7007) << " ChmodJob::slotResult( TDEIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
+ switch ( state )
+ {
+ case STATE_LISTING:
+ subjobs.remove(job);
+ m_lstItems.removeFirst();
+ kdDebug(7007) << "ChmodJob::slotResult -> processList" << endl;
+ processList();
+ return;
+ case STATE_CHMODING:
+ subjobs.remove(job);
+ kdDebug(7007) << "ChmodJob::slotResult -> chmodNextFile" << endl;
+ chmodNextFile();
+ return;
+ default:
+ assert(0);
+ return;
+ }
+}
+
+// antlarr: KDE 4: Make owner and group be const TQString &
+TDEIO_EXPORT ChmodJob *TDEIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
+ TQString owner, TQString group,
+ bool recursive, bool showProgressInfo )
+{
+ uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
+ if ( !owner.isEmpty() )
+ {
+ struct passwd* pw = getpwnam(TQFile::encodeName(owner));
+ if ( pw == 0L )
+ kdError(250) << " ERROR: No user " << owner << endl;
+ else
+ newOwnerID = pw->pw_uid;
+ }
+ gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
+ if ( !group.isEmpty() )
+ {
+ struct group* g = getgrnam(TQFile::encodeName(group));
+ if ( g == 0L )
+ kdError(250) << " ERROR: No group " << group << endl;
+ else
+ newGroupID = g->gr_gid;
+ }
+ return new ChmodJob( lstItems, permissions, mask, newOwnerID, newGroupID, recursive, showProgressInfo );
+}
+
+void ChmodJob::virtual_hook( int id, void* data )
+{ TDEIO::Job::virtual_hook( id, data ); }
+
+#include "chmodjob.moc"