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 const mode_t permissions = item.permissions() & 0777;
00127 info.permissions = ( m_permissions & m_mask ) | ( permissions & ~m_mask );
00128
00129
00130
00131
00132
00133
00134 m_infos.prepend( info );
00135
00136
00137 if ( item.isDir() && m_recursive )
00138 {
00139
00140 KIO::ListJob * listJob = KIO::listRecursive( item.url(), KIO::HideProgressInfo );
00141 q->connect( listJob, SIGNAL(entries( KIO::Job *,
00142 const KIO::UDSEntryList& )),
00143 SLOT(_k_slotEntries( KIO::Job*, const KIO::UDSEntryList& )));
00144 q->addSubjob( listJob );
00145 return;
00146 }
00147 }
00148 m_lstItems.removeFirst();
00149 }
00150 kDebug(7007) << "ChmodJob::processList -> going to STATE_CHMODING";
00151
00152 state = CHMODJOB_STATE_CHMODING;
00153 chmodNextFile();
00154 }
00155
00156 void ChmodJobPrivate::_k_slotEntries( KIO::Job*, const KIO::UDSEntryList & list )
00157 {
00158 KIO::UDSEntryList::ConstIterator it = list.begin();
00159 KIO::UDSEntryList::ConstIterator end = list.end();
00160 for (; it != end; ++it) {
00161 const KIO::UDSEntry& entry = *it;
00162 const bool isLink = !entry.stringValue( KIO::UDSEntry::UDS_LINK_DEST ).isEmpty();
00163 const QString relativePath = entry.stringValue( KIO::UDSEntry::UDS_NAME );
00164 if ( !isLink && relativePath != ".." )
00165 {
00166 const mode_t permissions = entry.numberValue( KIO::UDSEntry::UDS_ACCESS )
00167 & 0777;
00168
00169 ChmodInfo info;
00170 info.url = m_lstItems.first().url();
00171 info.url.addPath( relativePath );
00172 int mask = m_mask;
00173
00174
00175
00176 if ( !entry.isDir() )
00177 {
00178 int newPerms = m_permissions & mask;
00179 if ( (newPerms & 0111) && !(permissions & 0111) )
00180 {
00181
00182 if ( newPerms & 02000 )
00183 mask = mask & ~0101;
00184 else
00185 mask = mask & ~0111;
00186 }
00187 }
00188 info.permissions = ( m_permissions & mask ) | ( permissions & ~mask );
00189
00190
00191
00192
00193
00194
00195
00196
00197 m_infos.prepend( info );
00198 }
00199 }
00200 }
00201
00202 void ChmodJobPrivate::chmodNextFile()
00203 {
00204 Q_Q(ChmodJob);
00205 if ( !m_infos.isEmpty() )
00206 {
00207 ChmodInfo info = m_infos.takeFirst();
00208
00209
00210 if ( info.url.isLocalFile() && ( m_newOwner != -1 || m_newGroup != -1 ) )
00211 {
00212 QString path = info.url.toLocalFile();
00213 if ( chown( QFile::encodeName(path), m_newOwner, m_newGroup ) != 0 )
00214 {
00215 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")) );
00216 if (answer == KMessageBox::Cancel)
00217 {
00218 q->setError( ERR_USER_CANCELED );
00219 q->emitResult();
00220 return;
00221 }
00222 }
00223 }
00224
00225 kDebug(7007) << "chmod'ing" << info.url
00226 << "to" << QString::number(info.permissions,8);
00227 KIO::SimpleJob * job = KIO::chmod( info.url, info.permissions );
00228
00229 const QString aclString = q->queryMetaData( QLatin1String("ACL_STRING") );
00230 const QString defaultAclString = q->queryMetaData( QLatin1String("DEFAULT_ACL_STRING") );
00231 if ( !aclString.isEmpty() )
00232 job->addMetaData( QLatin1String("ACL_STRING"), aclString );
00233 if ( !defaultAclString.isEmpty() )
00234 job->addMetaData( QLatin1String("DEFAULT_ACL_STRING"), defaultAclString );
00235 q->addSubjob(job);
00236 }
00237 else
00238
00239 q->emitResult();
00240 }
00241
00242 void ChmodJob::slotResult( KJob * job )
00243 {
00244 Q_D(ChmodJob);
00245 removeSubjob(job);
00246 if ( job->error() )
00247 {
00248 setError( job->error() );
00249 setErrorText( job->errorText() );
00250 emitResult();
00251 return;
00252 }
00253
00254 switch ( d->state )
00255 {
00256 case CHMODJOB_STATE_LISTING:
00257 d->m_lstItems.removeFirst();
00258 kDebug(7007) << "-> processList";
00259 d->_k_processList();
00260 return;
00261 case CHMODJOB_STATE_CHMODING:
00262 kDebug(7007) << "-> chmodNextFile";
00263 d->chmodNextFile();
00264 return;
00265 default:
00266 assert(0);
00267 return;
00268 }
00269 }
00270
00271 ChmodJob *KIO::chmod( const KFileItemList& lstItems, int permissions, int mask,
00272 const QString& owner, const QString& group,
00273 bool recursive, JobFlags flags )
00274 {
00275 uid_t newOwnerID = uid_t(-1);
00276 if ( !owner.isEmpty() )
00277 {
00278 struct passwd* pw = getpwnam(QFile::encodeName(owner));
00279 if ( pw == 0L )
00280 kError(250) << " ERROR: No user" << owner;
00281 else
00282 newOwnerID = pw->pw_uid;
00283 }
00284 gid_t newGroupID = gid_t(-1);
00285 if ( !group.isEmpty() )
00286 {
00287 struct group* g = getgrnam(QFile::encodeName(group));
00288 if ( g == 0L )
00289 kError(250) << " ERROR: No group" << group;
00290 else
00291 newGroupID = g->gr_gid;
00292 }
00293 return ChmodJobPrivate::newJob(lstItems, permissions, mask, newOwnerID,
00294 newGroupID, recursive, flags);
00295 }
00296
00297 #include "chmodjob.moc"