00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
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 }
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() )
00121 {
00122
00123 ChmodInfo info;
00124 info.url = item.url();
00125
00126 info.permissions = ( m_permissions & m_mask ) | ( item.permissions() & ~m_mask );
00127
00128
00129
00130
00131
00132
00133 m_infos.prepend( info );
00134
00135
00136 if ( item.isDir() && m_recursive )
00137 {
00138
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;
00145 }
00146 }
00147 m_lstItems.removeFirst();
00148 }
00149 kDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING";
00150
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();
00169 info.url.addPath( relativePath );
00170 int mask = m_mask;
00171
00172
00173
00174 if ( !entry.isDir() )
00175 {
00176 int newPerms = m_permissions & mask;
00177 if ( (newPerms & 0111) && !(permissions & 0111) )
00178 {
00179
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
00188
00189
00190
00191
00192
00193
00194
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
00207
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
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
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
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);
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);
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"