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 struct KIO::ChmodInfo
00044 {
00045     KURL url;
00046     int permissions;
00047 };
00048 
00049 ChmodJob::ChmodJob( const KFileItemList& lstItems, int permissions, int mask,
00050                     int newOwner, int newGroup,
00051                     bool recursive, bool showProgressInfo )
00052     : KIO::Job( showProgressInfo ), state( STATE_LISTING ),
00053       m_permissions( permissions ), m_mask( mask ),
00054       m_newOwner( newOwner ), m_newGroup( newGroup ),
00055       m_recursive( recursive ), m_lstItems( lstItems )
00056 {
00057     QTimer::singleShot( 0, this, SLOT(processList()) );
00058 }
00059 
00060 void ChmodJob::processList()
00061 {
00062     while ( !m_lstItems.isEmpty() )
00063     {
00064         KFileItem * item = m_lstItems.first();
00065         if ( !item->isLink() ) // don't do anything with symlinks
00066         {
00067             // File or directory -> remember to chmod
00068             ChmodInfo info;
00069             info.url = item->url();
00070             // This is a toplevel file, we apply changes directly (no +X emulation here)
00071             info.permissions = ( m_permissions & m_mask ) | ( item->permissions() & ~m_mask );
00072             /*kdDebug(7007) << "\n current permissions=" << QString::number(item->permissions(),8)
00073                           << "\n wanted permission=" << QString::number(m_permissions,8)
00074                           << "\n with mask=" << QString::number(m_mask,8)
00075                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8)
00076                           << "\n bits we keep =" << QString::number(item->permissions() & ~m_mask,8)
00077                           << "\n new permissions = " << QString::number(info.permissions,8)
00078                           << endl;*/
00079             m_infos.prepend( info );
00080             //kdDebug(7007) << "processList : Adding info for " << info.url.prettyURL() << endl;
00081             // Directory and recursive -> list
00082             if ( item->isDir() && m_recursive )
00083             {
00084                 //kdDebug(7007) << "ChmodJob::processList dir -> listing" << endl;
00085                 KIO::ListJob * listJob = KIO::listRecursive( item->url(), false /* no GUI */ );
00086                 connect( listJob, SIGNAL(entries( KIO::Job *,
00087                                                   const KIO::UDSEntryList& )),
00088                          SLOT( slotEntries( KIO::Job*,
00089                                             const KIO::UDSEntryList& )));
00090                 addSubjob( listJob );
00091                 return; // we'll come back later, when this one's finished
00092             }
00093         }
00094         m_lstItems.removeFirst();
00095     }
00096     kdDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING" << endl;
00097     // We have finished, move on
00098     state = STATE_CHMODING;
00099     chmodNextFile();
00100 }
00101 
00102 void ChmodJob::slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
00103 {
00104     KIO::UDSEntryListConstIterator it = list.begin();
00105     KIO::UDSEntryListConstIterator end = list.end();
00106     for (; it != end; ++it) {
00107         KIO::UDSEntry::ConstIterator it2 = (*it).begin();
00108         mode_t permissions = 0;
00109         bool isDir = false;
00110         bool isLink = false;
00111         QString relativePath;
00112         for( ; it2 != (*it).end(); it2++ ) {
00113           switch( (*it2).m_uds ) {
00114             case KIO::UDS_NAME:
00115               relativePath = (*it2).m_str;
00116               break;
00117             case KIO::UDS_FILE_TYPE:
00118               isDir = S_ISDIR((*it2).m_long);
00119               break;
00120             case KIO::UDS_LINK_DEST:
00121               isLink = !(*it2).m_str.isEmpty();
00122               break;
00123             case KIO::UDS_ACCESS:
00124               permissions = (mode_t)((*it2).m_long);
00125               break;
00126             default:
00127               break;
00128           }
00129         }
00130         if ( !isLink && relativePath != QString::fromLatin1("..") )
00131         {
00132             ChmodInfo info;
00133             info.url = m_lstItems.first()->url(); // base directory
00134             info.url.addPath( relativePath );
00135             int mask = m_mask;
00136             // Emulate -X: only give +x to files that had a +x bit already
00137             // So the check is the opposite : if the file had no x bit, don't touch x bits
00138             // For dirs this doesn't apply
00139             if ( !isDir )
00140             {
00141                 int newPerms = m_permissions & mask;
00142                 if ( (newPerms & 0111) && !(permissions & 0111) )
00143                 {
00144                     // don't interfere with mandatory file locking
00145                     if ( newPerms & 02000 )
00146                       mask = mask & ~0101;
00147                     else
00148                       mask = mask & ~0111;
00149                 }
00150             }
00151             info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
00152             /*kdDebug(7007) << "\n current permissions=" << QString::number(permissions,8)
00153                           << "\n wanted permission=" << QString::number(m_permissions,8)
00154                           << "\n with mask=" << QString::number(mask,8)
00155                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8)
00156                           << "\n bits we keep =" << QString::number(permissions & ~mask,8)
00157                           << "\n new permissions = " << QString::number(info.permissions,8)
00158                           << endl;*/
00159             // Prepend this info in our todo list.
00160             // This way, the toplevel dirs are done last.
00161             m_infos.prepend( info );
00162         }
00163     }
00164 }
00165 
00166 void ChmodJob::chmodNextFile()
00167 {
00168     if ( !m_infos.isEmpty() )
00169     {
00170         ChmodInfo info = m_infos.first();
00171         m_infos.remove( m_infos.begin() );
00172         // First update group / owner (if local file)
00173         // (permissions have to set after, in case of suid and sgid)
00174         if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
00175         {
00176             QString path = info.url.path();
00177             if ( chown( QFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
00178             {
00179                 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") );
00180                 if (answer == KMessageBox::Cancel)
00181                 {
00182                     m_error = ERR_USER_CANCELED;
00183                     emitResult();
00184                     return;
00185                 }
00186             }
00187         }
00188 
00189         kdDebug(7007) << "ChmodJob::chmodNextFile chmod'ing " << info.url.prettyURL()
00190                       << " to " << QString::number(info.permissions,8) << endl;
00191         KIO::SimpleJob * job = KIO::chmod( info.url, info.permissions );
00192         addSubjob(job);
00193     }
00194     else
00195         // We have finished
00196         emitResult();
00197 }
00198 
00199 void ChmodJob::slotResult( KIO::Job * job )
00200 {
00201     if ( job->error() )
00202     {
00203         m_error = job->error();
00204         m_errorText = job->errorText();
00205         emitResult();
00206         return;
00207     }
00208     //kdDebug(7007) << " ChmodJob::slotResult( KIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
00209     switch ( state )
00210     {
00211         case STATE_LISTING:
00212             subjobs.remove(job);
00213             m_lstItems.removeFirst();
00214             kdDebug(7007) << "ChmodJob::slotResult -> processList" << endl;
00215             processList();
00216             return;
00217         case STATE_CHMODING:
00218             subjobs.remove(job);
00219             kdDebug(7007) << "ChmodJob::slotResult -> chmodNextFile" << endl;
00220             chmodNextFile();
00221             return;
00222         default:
00223             assert(0);
00224             return;
00225     }
00226 }
00227 
00228 // antlarr: KDE 4: Make owner and group be const QString &
00229 KIO_EXPORT ChmodJob *KIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
00230                       QString owner, QString group,
00231                       bool recursive, bool showProgressInfo )
00232 {
00233     uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
00234     if ( !owner.isEmpty() )
00235     {
00236         struct passwd* pw = getpwnam(QFile::encodeName(owner));
00237         if ( pw == 0L )
00238             kdError(250) << " ERROR: No user " << owner << endl;
00239         else
00240             newOwnerID = pw->pw_uid;
00241     }
00242     gid_t newGroupID = (gid_t)-1; // chown(2) : -1 means no change
00243     if ( !group.isEmpty() )
00244     {
00245         struct group* g = getgrnam(QFile::encodeName(group));
00246         if ( g == 0L )
00247             kdError(250) << " ERROR: No group " << group << endl;
00248         else
00249             newGroupID = g->gr_gid;
00250     }
00251     return new ChmodJob( lstItems, permissions, mask, newOwnerID, newGroupID, recursive, showProgressInfo );
00252 }
00253 
00254 void ChmodJob::virtual_hook( int id, void* data )
00255 { KIO::Job::virtual_hook( id, data ); }
00256 
00257 #include "chmodjob.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:15:26 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003