• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

chmodjob.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "chmodjob.h"
00023 
00024 #include "job.h"
00025 #include "jobuidelegate.h"
00026 
00027 #include <kglobal.h>
00028 #include <kuiserverjobtracker.h>
00029 
00030 #include <klocale.h>
00031 #include <kdebug.h>
00032 #include <kmessagebox.h>
00033 #include <QtCore/QFile>
00034 
00035 #include <config.h>
00036 
00037 #include <pwd.h>
00038 #include <grp.h>
00039 #include <sys/types.h>
00040 #include <unistd.h>
00041 #include <assert.h>
00042 
00043 #include "job_p.h"
00044 
00045 namespace KIO {
00046 
00047     struct ChmodInfo
00048     {
00049         KUrl url;
00050         int permissions;
00051     };
00052 
00053     enum ChmodJobState {
00054         CHMODJOB_STATE_LISTING,
00055         CHMODJOB_STATE_CHMODING
00056     };
00057 
00058     class ChmodJobPrivate: public KIO::JobPrivate
00059     {
00060     public:
00061         ChmodJobPrivate(const KFileItemList& lstItems, int permissions, int mask,
00062                         int newOwner, int newGroup, bool recursive)
00063             : state( CHMODJOB_STATE_LISTING )
00064             , m_permissions( permissions )
00065             , m_mask( mask )
00066             , m_newOwner( newOwner )
00067             , m_newGroup( newGroup )
00068             , m_recursive( recursive )
00069             , m_lstItems( lstItems )
00070         {
00071         }
00072 
00073         ChmodJobState state;
00074         int m_permissions;
00075         int m_mask;
00076         int m_newOwner;
00077         int m_newGroup;
00078         bool m_recursive;
00079         KFileItemList m_lstItems;
00080         QLinkedList<ChmodInfo> m_infos; // linkedlist since we keep removing the first item
00081 
00082         void chmodNextFile();
00083         void _k_slotEntries( KIO::Job * , const KIO::UDSEntryList & );
00084         void _k_processList();
00085 
00086         Q_DECLARE_PUBLIC(ChmodJob)
00087 
00088         static inline ChmodJob *newJob(const KFileItemList& lstItems, int permissions, int mask,
00089                                        int newOwner, int newGroup, bool recursive, JobFlags flags)
00090         {
00091             ChmodJob *job = new ChmodJob(*new ChmodJobPrivate(lstItems,permissions,mask,
00092                                                               newOwner,newGroup,recursive));
00093             job->setUiDelegate(new JobUiDelegate());
00094             if (!(flags & HideProgressInfo))
00095                 KIO::getJobTracker()->registerJob(job);
00096             return job;
00097         }
00098     };
00099 
00100 } // namespace KIO
00101 
00102 using namespace KIO;
00103 
00104 ChmodJob::ChmodJob(ChmodJobPrivate &dd)
00105     : KIO::Job(dd)
00106 {
00107     QMetaObject::invokeMethod( this, "_k_processList", Qt::QueuedConnection );
00108 }
00109 
00110 ChmodJob::~ChmodJob()
00111 {
00112 }
00113 
00114 void ChmodJobPrivate::_k_processList()
00115 {
00116     Q_Q(ChmodJob);
00117     while ( !m_lstItems.isEmpty() )
00118     {
00119         const KFileItem item = m_lstItems.first();
00120         if ( !item.isLink() ) // don't do anything with symlinks
00121         {
00122             // File or directory -> remember to chmod
00123             ChmodInfo info;
00124             info.url = item.url();
00125             // This is a toplevel file, we apply changes directly (no +X emulation here)
00126             info.permissions = ( m_permissions & m_mask ) | ( item.permissions() & ~m_mask );
00127             /*kDebug(7007) << "\n current permissions=" << QString::number(item->permissions(),8)
00128                           << "\n wanted permission=" << QString::number(m_permissions,8)
00129                           << "\n with mask=" << QString::number(m_mask,8)
00130                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8)
00131                           << "\n bits we keep =" << QString::number(item->permissions() & ~m_mask,8)
00132                           << "\n new permissions = " << QString::number(info.permissions,8);*/
00133             m_infos.prepend( info );
00134             //kDebug(7007) << "processList : Adding info for " << info.url;
00135             // Directory and recursive -> list
00136             if ( item.isDir() && m_recursive )
00137             {
00138                 //kDebug(7007) << "ChmodJob::processList dir -> listing";
00139                 KIO::ListJob * listJob = KIO::listRecursive( item.url(), KIO::HideProgressInfo );
00140                 q->connect( listJob, SIGNAL(entries( KIO::Job *,
00141                                                      const KIO::UDSEntryList& )),
00142                             SLOT(_k_slotEntries( KIO::Job*, const KIO::UDSEntryList& )));
00143                 q->addSubjob( listJob );
00144                 return; // we'll come back later, when this one's finished
00145             }
00146         }
00147         m_lstItems.removeFirst();
00148     }
00149     kDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING";
00150     // We have finished, move on
00151     state = CHMODJOB_STATE_CHMODING;
00152     chmodNextFile();
00153 }
00154 
00155 void ChmodJobPrivate::_k_slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
00156 {
00157     KIO::UDSEntryList::ConstIterator it = list.begin();
00158     KIO::UDSEntryList::ConstIterator end = list.end();
00159     for (; it != end; ++it) {
00160         const KIO::UDSEntry& entry = *it;
00161         const bool isLink = !entry.stringValue( KIO::UDSEntry::UDS_STRING ).isEmpty();
00162         const QString relativePath = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00163         if ( !isLink && relativePath != ".." )
00164         {
00165             const mode_t permissions = entry.numberValue( KIO::UDSEntry::UDS_ACCESS );
00166 
00167             ChmodInfo info;
00168             info.url = m_lstItems.first().url(); // base directory
00169             info.url.addPath( relativePath );
00170             int mask = m_mask;
00171             // Emulate -X: only give +x to files that had a +x bit already
00172             // So the check is the opposite : if the file had no x bit, don't touch x bits
00173             // For dirs this doesn't apply
00174             if ( !entry.isDir() )
00175             {
00176                 int newPerms = m_permissions & mask;
00177                 if ( (newPerms & 0111) && !(permissions & 0111) )
00178                 {
00179                     // don't interfere with mandatory file locking
00180                     if ( newPerms & 02000 )
00181                       mask = mask & ~0101;
00182                     else
00183                       mask = mask & ~0111;
00184                 }
00185             }
00186             info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
00187             /*kDebug(7007) << "\n current permissions=" << QString::number(permissions,8)
00188                           << "\n wanted permission=" << QString::number(m_permissions,8)
00189                           << "\n with mask=" << QString::number(mask,8)
00190                           << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8)
00191                           << "\n bits we keep =" << QString::number(permissions & ~mask,8)
00192                           << "\n new permissions = " << QString::number(info.permissions,8);*/
00193             // Prepend this info in our todo list.
00194             // This way, the toplevel dirs are done last.
00195             m_infos.prepend( info );
00196         }
00197     }
00198 }
00199 
00200 void ChmodJobPrivate::chmodNextFile()
00201 {
00202     Q_Q(ChmodJob);
00203     if ( !m_infos.isEmpty() )
00204     {
00205         ChmodInfo info = m_infos.takeFirst();
00206         // First update group / owner (if local file)
00207         // (permissions have to set after, in case of suid and sgid)
00208         if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
00209         {
00210             QString path = info.url.path();
00211             if ( chown( QFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
00212             {
00213                 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>" , path), QString(), KGuiItem(i18n("&Skip File")) );
00214                 if (answer == KMessageBox::Cancel)
00215                 {
00216                     q->setError( ERR_USER_CANCELED );
00217                     q->emitResult();
00218                     return;
00219                 }
00220             }
00221         }
00222 
00223         kDebug(7007) << "chmod'ing" << info.url
00224                       << "to" << QString::number(info.permissions,8);
00225         KIO::SimpleJob * job = KIO::chmod( info.url, info.permissions );
00226         // copy the metadata for acl and default acl
00227         const QString aclString = q->queryMetaData( QLatin1String("ACL_STRING") );
00228         const QString defaultAclString = q->queryMetaData( QLatin1String("DEFAULT_ACL_STRING") );
00229         if ( !aclString.isEmpty() )
00230             job->addMetaData( QLatin1String("ACL_STRING"), aclString );
00231         if ( !defaultAclString.isEmpty() )
00232             job->addMetaData( QLatin1String("DEFAULT_ACL_STRING"), defaultAclString );
00233         q->addSubjob(job);
00234     }
00235     else
00236         // We have finished
00237         q->emitResult();
00238 }
00239 
00240 void ChmodJob::slotResult( KJob * job )
00241 {
00242     Q_D(ChmodJob);
00243     removeSubjob(job);
00244     if ( job->error() )
00245     {
00246         setError( job->error() );
00247         setErrorText( job->errorText() );
00248         emitResult();
00249         return;
00250     }
00251     //kDebug(7007) << "d->m_lstItems:" << d->m_lstItems.count();
00252     switch ( d->state )
00253     {
00254         case CHMODJOB_STATE_LISTING:
00255             d->m_lstItems.removeFirst();
00256             kDebug(7007) << "-> processList";
00257             d->_k_processList();
00258             return;
00259         case CHMODJOB_STATE_CHMODING:
00260             kDebug(7007) << "-> chmodNextFile";
00261             d->chmodNextFile();
00262             return;
00263         default:
00264             assert(0);
00265             return;
00266     }
00267 }
00268 
00269 ChmodJob *KIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
00270                       const QString& owner, const QString& group,
00271                       bool recursive, JobFlags flags )
00272 {
00273     uid_t newOwnerID = uid_t(-1); // chown(2) : -1 means no change
00274     if ( !owner.isEmpty() )
00275     {
00276         struct passwd* pw = getpwnam(QFile::encodeName(owner));
00277         if ( pw == 0L )
00278             kError(250) << " ERROR: No user" << owner;
00279         else
00280             newOwnerID = pw->pw_uid;
00281     }
00282     gid_t newGroupID = gid_t(-1); // chown(2) : -1 means no change
00283     if ( !group.isEmpty() )
00284     {
00285         struct group* g = getgrnam(QFile::encodeName(group));
00286         if ( g == 0L )
00287             kError(250) << " ERROR: No group" << group;
00288         else
00289             newGroupID = g->gr_gid;
00290     }
00291     return ChmodJobPrivate::newJob(lstItems, permissions, mask, newOwnerID,
00292                                    newGroupID, recursive, flags);
00293 }
00294 
00295 #include "chmodjob.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal