kio Library API Documentation

chmodjob.cpp

00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
00003                        David Faure <faure@kde.org>
00004                        Waldo Bastian <bastian@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019     Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <config.h>
00023 
00024 #include <pwd.h>
00025 #include <grp.h>
00026 #include <sys/types.h>
00027 #include <unistd.h>
00028 #include <assert.h>
00029 
00030 #include <qtimer.h>
00031 #include <qfile.h>
00032 #include <klocale.h>
00033 #include <kdebug.h>
00034 #include <kmessagebox.h>
00035 
00036 #include "kio/job.h"
00037 #include "kio/chmodjob.h"
00038 
00039 #include <kdirnotify_stub.h>
00040 
00041 using namespace KIO;
00042 
00043 ChmodJob::ChmodJob( const KFileItemList& lstItems, int permissions, int mask,
00044                     int newOwner, int newGroup,
00045                     bool recursive, bool showProgressInfo )
00046     : KIO::Job( showProgressInfo ), state( STATE_LISTING ),
00047       m_permissions( permissions ), m_mask( mask ),
00048       m_newOwner( newOwner ), m_newGroup( newGroup ),
00049       m_recursive( recursive ), m_lstItems( lstItems )
00050 {
00051     QTimer::singleShot( 0, this, SLOT(processList()) );
00052 }
00053 
00054 void ChmodJob::processList()
00055 {
00056     while ( !m_lstItems.isEmpty() )
00057     {
00058         KFileItem * item = m_lstItems.first();
00059         if ( !item->isLink() ) // don't do anything with symlinks
00060         {
00061             // File or directory -> remember to chmod
00062             ChmodInfo info;
00063             info.url = item->url();
00064             // This is a toplevel file, we apply changes directly (no +X emulation here)
00065             info.permissions = ( m_permissions & m_mask ) | ( item->permissions() & ~m_mask );
00066             /*kdDebug(7007) << "\n current permissions=" << QString::number(item->permissions(),8)
00067                           << "\n wanted permission=" << QString::number(m_permissions,8)
00068                           << "\n with mask=" << QString::number(m_mask,8)
00069                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8)
00070                           << "\n bits we keep =" << QString::number(item->permissions() & ~m_mask,8)
00071                           << "\n new permissions = " << QString::number(info.permissions,8)
00072                           << endl;*/
00073             m_infos.prepend( info );
00074             //kdDebug(7007) << "processList : Adding info for " << info.url.prettyURL() << endl;
00075             // Directory and recursive -> list
00076             if ( item->isDir() && m_recursive )
00077             {
00078                 //kdDebug(7007) << "ChmodJob::processList dir -> listing" << endl;
00079                 KIO::ListJob * listJob = KIO::listRecursive( item->url(), false /* no GUI */ );
00080                 connect( listJob, SIGNAL(entries( KIO::Job *,
00081                                                   const KIO::UDSEntryList& )),
00082                          SLOT( slotEntries( KIO::Job*,
00083                                             const KIO::UDSEntryList& )));
00084                 addSubjob( listJob );
00085                 return; // we'll come back later, when this one's finished
00086             }
00087         }
00088         m_lstItems.removeFirst();
00089     }
00090     kdDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING" << endl;
00091     // We have finished, move on
00092     state = STATE_CHMODING;
00093     chmodNextFile();
00094 }
00095 
00096 void ChmodJob::slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
00097 {
00098     KIO::UDSEntryListConstIterator it = list.begin();
00099     KIO::UDSEntryListConstIterator end = list.end();
00100     for (; it != end; ++it) {
00101         KIO::UDSEntry::ConstIterator it2 = (*it).begin();
00102         mode_t permissions = 0;
00103         bool isDir = false;
00104         bool isLink = false;
00105         QString relativePath;
00106         for( ; it2 != (*it).end(); it2++ ) {
00107           switch( (*it2).m_uds ) {
00108             case KIO::UDS_NAME:
00109               relativePath = (*it2).m_str;
00110               break;
00111             case KIO::UDS_FILE_TYPE:
00112               isDir = S_ISDIR((*it2).m_long);
00113               break;
00114             case KIO::UDS_LINK_DEST:
00115               isLink = !(*it2).m_str.isEmpty();
00116               break;
00117             case KIO::UDS_ACCESS:
00118               permissions = (mode_t)((*it2).m_long);
00119               break;
00120             default:
00121               break;
00122           }
00123         }
00124         if ( !isLink && relativePath != QString::fromLatin1("..") )
00125         {
00126             ChmodInfo info;
00127             info.url = m_lstItems.first()->url(); // base directory
00128             info.url.addPath( relativePath );
00129             int mask = m_mask;
00130             // Emulate -X: only give +x to files that had a +x bit already
00131             // So the check is the opposite : if the file had no x bit, don't touch x bits
00132             // For dirs this doesn't apply
00133             if ( !isDir )
00134             {
00135                 int newPerms = m_permissions & mask;
00136                 if ( (newPerms & 0111) && !(permissions & 0111) )
00137                 {
00138                     // don't interfere with mandatory file locking
00139                     if ( newPerms & 02000 )
00140                       mask = mask & ~0101;
00141                     else
00142                       mask = mask & ~0111;
00143                 }
00144             }
00145             info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
00146             /*kdDebug(7007) << "\n current permissions=" << QString::number(permissions,8)
00147                           << "\n wanted permission=" << QString::number(m_permissions,8)
00148                           << "\n with mask=" << QString::number(mask,8)
00149                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8)
00150                           << "\n bits we keep =" << QString::number(permissions & ~mask,8)
00151                           << "\n new permissions = " << QString::number(info.permissions,8)
00152                           << endl;*/
00153             // Prepend this info in our todo list.
00154             // This way, the toplevel dirs are done last.
00155             m_infos.prepend( info );
00156         }
00157     }
00158 }
00159 
00160 void ChmodJob::chmodNextFile()
00161 {
00162     if ( !m_infos.isEmpty() )
00163     {
00164         ChmodInfo info = m_infos.first();
00165         m_infos.remove( m_infos.begin() );
00166         // First update group / owner (if local file)
00167         // (permissions have to set after, in case of suid and sgid)
00168         if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
00169         {
00170             QString path = info.url.path();
00171             if ( chown( QFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
00172             {
00173                 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), QString::null, i18n("&Skip File") );
00174                 if (answer == KMessageBox::Cancel)
00175                 {
00176                     m_error = ERR_USER_CANCELED;
00177                     emitResult();
00178                     return;
00179                 }
00180             }
00181         }
00182 
00183         kdDebug(7007) << "ChmodJob::chmodNextFile chmod'ing " << info.url.prettyURL()
00184                       << " to " << QString::number(info.permissions,8) << endl;
00185         KIO::SimpleJob * job = KIO::chmod( info.url, info.permissions );
00186         addSubjob(job);
00187     }
00188     else
00189         // We have finished
00190         emitResult();
00191 }
00192 
00193 void ChmodJob::slotResult( KIO::Job * job )
00194 {
00195     if ( job->error() )
00196     {
00197         m_error = job->error();
00198         m_errorText = job->errorText();
00199         emitResult();
00200         return;
00201     }
00202     //kdDebug(7007) << " ChmodJob::slotResult( KIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
00203     switch ( state )
00204     {
00205         case STATE_LISTING:
00206             subjobs.remove(job);
00207             m_lstItems.removeFirst();
00208             kdDebug(7007) << "ChmodJob::slotResult -> processList" << endl;
00209             processList();
00210             return;
00211         case STATE_CHMODING:
00212             subjobs.remove(job);
00213             kdDebug(7007) << "ChmodJob::slotResult -> chmodNextFile" << endl;
00214             chmodNextFile();
00215             return;
00216         default:
00217             assert(0);
00218             return;
00219     }
00220 }
00221 
00222 // antlarr: KDE 4: Make owner and group be const QString &
00223 KIO_EXPORT ChmodJob *KIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
00224                       QString owner, QString group,
00225                       bool recursive, bool showProgressInfo )
00226 {
00227     uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
00228     if ( !owner.isEmpty() )
00229     {
00230         struct passwd* pw = getpwnam(QFile::encodeName(owner));
00231         if ( pw == 0L )
00232             kdError(250) << " ERROR: No user " << owner << endl;
00233         else
00234             newOwnerID = pw->pw_uid;
00235     }
00236     gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
00237     if ( !group.isEmpty() )
00238     {
00239         struct group* g = getgrnam(QFile::encodeName(group));
00240         if ( g == 0L )
00241             kdError(250) << " ERROR: No group " << group << endl;
00242         else
00243             newGroupID = g->gr_gid;
00244     }
00245     return new ChmodJob( lstItems, permissions, mask, newOwnerID, newGroupID, recursive, showProgressInfo );
00246 }
00247 
00248 void ChmodJob::virtual_hook( int id, void* data )
00249 { KIO::Job::virtual_hook( id, data ); }
00250 
00251 #include "chmodjob.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:52 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003