chmodjob.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:12:43 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001