Logo Search packages:      
Sourcecode: kbear version File versions  Download package

kbearchmodjob.cpp

/***************************************************************************
                          kbearchmodjob.cpp  -  description
                             -------------------
    begin                : tis sep 17 2002
    copyright            : (C) 2002 by Björn Sahlström
    email                : kbjorn@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

//////////////////////////////////////////////////////////////////////
// Qt specific include files
#include <qtimer.h>
#include <qfile.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <kapplication.h>
#include <dcopclient.h>
#include <klocale.h>
#include <kdebug.h>
#include <kmessagebox.h>

#include "kio/job.h"
//////////////////////////////////////////////////////////////////////
// Application specific include files

#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>

#include "../../base/kbearconnectionmanager.h"
#include "../../base/kbearlistjob.h"
#include "kbearchmodjob.h"

#include "kbearchmodjob.moc"


/*

 NOTE : This job is currently in ksycoca because kfileitem needs to know
 about mimetypes. For KDE 3.0, make a base class for KFileItem, that holds
 all the information except the mimetype, so that jobs can use it.

*/

KBearChmodJob::KBearChmodJob( unsigned long id, const KFileItemList& lstItems, int permissions, int mask,
                    int newOwner, int newGroup,
                    bool recursive, bool showProgressInfo )
    : KIO::Job( showProgressInfo ), state( STATE_LISTING ),
      m_permissions( permissions ), m_mask( mask ),
      m_newOwner( newOwner ), m_newGroup( newGroup ),
      m_recursive( recursive ), m_lstItems( lstItems ), m_ID( id )
{
    QTimer::singleShot( 0, this, SLOT(processList()) );
}

void KBearChmodJob::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
            KBearChmodJob::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=" << QString::number(item->permissions(),8)
                          << "\n wanted permission=" << QString::number(m_permissions,8)
                          << "\n with mask=" << QString::number(m_mask,8)
                          << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~m_mask,8)
                          << "\n bits we keep =" << QString::number(item->permissions() & ~m_mask,8)
                          << "\n new permissions = " << QString::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) << "KBearChmodJob::processList dir -> listing" << endl;
                KBearListJob * listJob = KBearListJob::listRecursive( m_ID, item->url(), false, true );
                connectionManager->attachJob( m_ID, listJob );
                        connect( listJob, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList& )),
                         SLOT( slotEntries( KIO::Job*, const KIO::UDSEntryList& )));
/*
                  connect( listJob, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
                              this, SIGNAL( infoMessage( KIO::Job*, const QString& ) ) );
*/
                addSubjob( listJob );
                return; // we'll come back later, when this one's finished
            }
        }
        m_lstItems.removeFirst();
    }
    kdDebug() << "KBearChmodJob::processList -> going to STATE_CHMODING" << endl;
    // We have finished, move on
    state = STATE_CHMODING;
    chmodNextFile();
}

void KBearChmodJob::slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
{
    KIO::UDSEntryListConstIterator it = list.begin();
    KIO::UDSEntryListConstIterator end = list.end();
    for (; it != end; ++it) {
        KIO::UDSEntry::ConstIterator it2 = (*it).begin();
        mode_t permissions = 0;
        bool isDir = false;
        bool isLink = false;
        QString relativePath;
        for( ; it2 != (*it).end(); it2++ ) {
          switch( (*it2).m_uds ) {
            case KIO::UDS_NAME:
              relativePath = (*it2).m_str;
              break;
            case KIO::UDS_FILE_TYPE:
              isDir = S_ISDIR((*it2).m_long);
              break;
            case KIO::UDS_LINK_DEST:
              isLink = !(*it2).m_str.isEmpty();
              break;
            case KIO::UDS_ACCESS:
              permissions = (mode_t)((*it2).m_long);
              break;
            default:
              break;
          }
        }
        if ( !isLink && relativePath != QString::fromLatin1("..") )
        {
            KBearChmodJob::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) )
                    mask = mask & ~0111;
            }
            info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
            /*kdDebug(7007) << "\n current permissions=" << QString::number(permissions,8)
                          << "\n wanted permission=" << QString::number(m_permissions,8)
                          << "\n with mask=" << QString::number(mask,8)
                          << "\n with ~mask (mask bits we keep) =" << QString::number((uint)~mask,8)
                          << "\n bits we keep =" << QString::number(permissions & ~mask,8)
                          << "\n new permissions = " << QString::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 KBearChmodJob::chmodNextFile()
{
    if ( !m_infos.isEmpty() )
    {
        KBearChmodJob::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 ) )
        {
            QString path = info.url.path();
            if ( chown( QFile::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), QString::null, i18n("Continue") );
                if (answer == KMessageBox::Cancel)
                {
                    m_error = KIO::ERR_USER_CANCELED;
                    emitResult();
                    return;
                }
            }
        }

        kdDebug() << "KBearChmodJob::chmodNextFile chmod'ing " << info.url.prettyURL()
                      << " to " << QString::number(info.permissions,8) << endl;
        KIO::SimpleJob * job = KIO::chmod( info.url, info.permissions );
            connectionManager->attachJob( m_ID, job );
/*          connect( job, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
                  this, SIGNAL( infoMessage( KIO::Job*, const QString& ) ) );
*/        addSubjob(job);
    }
    else
        // We have finished
        emitResult();
}

void KBearChmodJob::slotResult( KIO::Job * job )
{
    if ( job->error() )
    {
        m_error = job->error();
        m_errorText = job->errorText();
        emitResult();
        return;
    }
    //kdDebug(7007) << " KBearChmodJob::slotResult( KIO::Job * job ) m_lstItems:" << m_lstItems.count() << endl;
    switch ( state )
    {
        case STATE_LISTING:
            subjobs.remove(job);
            m_lstItems.removeFirst();
            kdDebug() << "KBearChmodJob::slotResult -> processList" << endl;
            processList();
            return;
        case STATE_CHMODING:
            subjobs.remove(job);
            kdDebug() << "KBearChmodJob::slotResult -> chmodNextFile" << endl;
            chmodNextFile();
            return;
        default:
            assert(0);
            return;
    }
}

00234 KBearChmodJob *KBearChmodJob::chmod( unsigned long id, const KFileItemList& lstItems, int permissions, int mask,
                      QString owner, QString group,
                      bool recursive, bool showProgressInfo )
{
    uid_t newOwnerID = (uid_t)-1; // chown(2) : -1 means no change
    if ( !owner.isEmpty() )
    {
        struct passwd* pw = getpwnam(QFile::encodeName(owner));
        if ( pw == 0L )
            kdError() << " 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(QFile::encodeName(group));
        if ( g == 0L )
            kdError() << " ERROR: No group " << group << endl;
        else
            newGroupID = g->gr_gid;
    }
    return new KBearChmodJob( id, lstItems, permissions, mask, newOwnerID, newGroupID, recursive, showProgressInfo );
}



Generated by  Doxygen 1.6.0   Back to index