58
66
#include "../krslots.h"
59
67
#include "../krservices.h"
61
// header files for ACL
64
#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
65
#include <acl/libacl.h>
69
normal_vfs::normal_vfs(QObject* panel):vfs(panel), watcher(0) {
69
normal_vfs::normal_vfs(QObject* panel): vfs(panel), watcher(0)
71
vfs_type = VFS_NORMAL;
73
bool normal_vfs::populateVfsList(const KUrl& origin, bool showHidden){
74
QString path = KrServices::getPath( origin, KUrl::RemoveTrailingSlash);
74
bool normal_vfs::populateVfsList(const KUrl& origin, bool showHidden)
76
QString path = KrServices::getPath(origin, KUrl::RemoveTrailingSlash);
76
if(! path.contains("/"))
78
path = path + QString( "/" );
78
if (! path.contains("/")) { //change C: to C:/
79
path = path + QString("/");
82
// set the writable attribute to true, if that's not the case - the KIO job
83
// will give the warnings and errors
86
if( watcher ) delete watcher; //stop watching the old dir
91
vfs_origin.setPath(path);
92
//vfs_origin.adjustPath(KUrl::RemoveTrailingSlash);
93
vfs_origin.setProtocol("file"); // do not remove !
94
vfs_origin.cleanPath();
96
// check that the new origin exists
97
if ( !QDir(path).exists() )
99
if( !quietMode ) KMessageBox::error(krApp, i18n("Directory %1 does not exist!", path ), i18n("Error"));
103
KConfigGroup group( krConfig, "Advanced");
104
if (group.readEntry("AutoMount",_AutoMount)) krMtMan.autoMount(path);
106
DIR* dir = opendir(path.toLocal8Bit());
109
if( !quietMode ) KMessageBox::error(krApp, i18n("Can't open the %1 directory!", path ), i18n("Error"));
113
// change directory to the new directory
114
QString save = QDir::currentPath();
115
if ( ! QDir::setCurrent( path ) ) {
116
if( !quietMode ) KMessageBox::error(krApp, i18n("Access denied to")+path, i18n("Error"));
121
struct dirent* dirEnt;
124
while( (dirEnt=readdir(dir)) != NULL ){
125
name = QString::fromLocal8Bit(dirEnt->d_name);
127
// show hidden files ?
128
if ( !showHidden && name.left(1) == "." ) continue ;
129
// we dont need the ".",".." enteries
130
if (name=="." || name == "..") continue;
132
vfile* temp = vfileFromName( name, dirEnt->d_name );
137
QDir::setCurrent( save );
141
watcher = new KDirWatch();
142
// connect the watcher
143
connect(watcher,SIGNAL(dirty(const QString&)),this,SLOT(vfs_slotDirty(const QString&)));
144
connect(watcher,SIGNAL(created(const QString&)),this, SLOT(vfs_slotCreated(const QString&)));
145
connect(watcher,SIGNAL(deleted(const QString&)),this, SLOT(vfs_slotDeleted(const QString&)));
146
watcher->addDir(vfs_getOrigin().path(KUrl::RemoveTrailingSlash), KDirWatch::WatchFiles); //start watching the new dir
147
watcher->startScan(true);
153
// copy a file to the vfs (physical)
154
void normal_vfs::vfs_addFiles(KUrl::List *fileUrls,KIO::CopyJob::CopyMode mode,QObject* toNotify,QString dir, PreserveMode pmode ){
155
//if( watcher ) watcher->stopScan(); // we will refresh manually this time...
157
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
83
// set the writable attribute to true, if that's not the case - the KIO job
84
// will give the warnings and errors
87
if (watcher) delete watcher; //stop watching the old dir
162
dest.setPath(vfs_workingDir()+"/"+dir);
164
KIO::Job* job = PreservingCopyJob::createCopyJob( pmode, *fileUrls,dest,mode,false,true );
165
connect(job,SIGNAL(result(KJob*)),this,SLOT(vfs_refresh(KJob *)) );
166
if(mode == KIO::CopyJob::Move) // notify the other panel
167
connect(job,SIGNAL(result(KJob*)),toNotify,SLOT(vfs_refresh(KJob*)) );
169
job->ui()->setAutoErrorHandlingEnabled( true );
92
vfs_origin.setPath(path);
93
//vfs_origin.adjustPath(KUrl::RemoveTrailingSlash);
94
vfs_origin.setProtocol("file"); // do not remove !
95
vfs_origin.cleanPath();
97
// check that the new origin exists
98
if (!QDir(path).exists()) {
99
if (!quietMode) KMessageBox::error(krApp, i18n("Directory %1 does not exist!", path), i18n("Error"));
103
KConfigGroup group(krConfig, "Advanced");
104
if (group.readEntry("AutoMount", _AutoMount)) krMtMan.autoMount(path);
106
DIR* dir = opendir(path.toLocal8Bit());
108
if (!quietMode) KMessageBox::error(krApp, i18n("Can't open the %1 directory!", path), i18n("Error"));
112
// change directory to the new directory
113
QString save = QDir::currentPath();
114
if (! QDir::setCurrent(path)) {
115
if (!quietMode) KMessageBox::error(krApp, i18n("Access denied to") + path, i18n("Error"));
120
KDE_struct_dirent* dirEnt;
123
while ((dirEnt = KDE_readdir(dir)) != NULL) {
124
name = QString::fromLocal8Bit(dirEnt->d_name);
126
// show hidden files ?
127
if (!showHidden && name.left(1) == ".") continue ;
128
// we don't need the ".",".." entries
129
if (name == "." || name == "..") continue;
131
vfile* temp = vfileFromName(name, dirEnt->d_name);
136
QDir::setCurrent(save);
138
if (panelConnected) {
139
watcher = new KDirWatch();
140
// connect the watcher
141
connect(watcher, SIGNAL(dirty(const QString&)), this, SLOT(vfs_slotDirty(const QString&)));
142
connect(watcher, SIGNAL(created(const QString&)), this, SLOT(vfs_slotCreated(const QString&)));
143
connect(watcher, SIGNAL(deleted(const QString&)), this, SLOT(vfs_slotDeleted(const QString&)));
144
watcher->addDir(vfs_getOrigin().path(KUrl::RemoveTrailingSlash), KDirWatch::WatchFiles); //start watching the new dir
145
watcher->startScan(true);
151
// copy a file to the vfs (physical)
152
void normal_vfs::vfs_addFiles(KUrl::List *fileUrls, KIO::CopyJob::CopyMode mode, QObject* toNotify, QString dir, PreserveMode pmode)
154
//if( watcher ) watcher->stopScan(); // we will refresh manually this time...
156
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
161
dest.setPath(vfs_workingDir() + '/' + dir);
163
KIO::Job* job = PreservingCopyJob::createCopyJob(pmode, *fileUrls, dest, mode, false, true);
164
connect(job, SIGNAL(result(KJob*)), this, SLOT(vfs_refresh(KJob *)));
165
if (mode == KIO::CopyJob::Move) // notify the other panel
166
connect(job, SIGNAL(result(KJob*)), toNotify, SLOT(vfs_refresh(KJob*)));
168
job->ui()->setAutoErrorHandlingEnabled(true);
172
171
// remove a file from the vfs (physical)
173
void normal_vfs::vfs_delFiles(QStringList *fileNames, bool reallyDelete){
174
KUrl::List filesUrls;
176
QDir local( vfs_workingDir() );
179
// if( watcher ) watcher->stopScan(); // we will refresh manually this time...
181
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
186
for(int i=0 ; i<fileNames->count(); ++i){
187
QString filename = (*fileNames)[i];
188
vf = vfs_search(filename);
189
url.setPath( vfs_workingDir()+"/"+filename);
190
filesUrls.append(url);
194
// delete of move to trash ?
195
KConfigGroup group( krConfig, "General");
196
if( !reallyDelete && group.readEntry("Move To Trash",_MoveToTrash) ){
197
job = KIO::trash(filesUrls);
198
connect(job,SIGNAL(result(KJob*)),SLOTS,SLOT(changeTrashIcon()));
201
job = KIO::del(filesUrls);
203
connect(job,SIGNAL(result(KJob*)),this,SLOT(vfs_refresh(KJob*)));
172
void normal_vfs::vfs_delFiles(QStringList *fileNames, bool reallyDelete)
174
KUrl::List filesUrls;
176
QDir local(vfs_workingDir());
179
// if( watcher ) watcher->stopScan(); // we will refresh manually this time...
181
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
186
for (int i = 0 ; i < fileNames->count(); ++i) {
187
QString filename = (*fileNames)[i];
188
vf = vfs_search(filename);
189
url.setPath(vfs_workingDir() + '/' + filename);
190
filesUrls.append(url);
194
// delete of move to trash ?
195
KConfigGroup group(krConfig, "General");
196
if (!reallyDelete && group.readEntry("Move To Trash", _MoveToTrash)) {
197
job = KIO::trash(filesUrls);
198
connect(job, SIGNAL(result(KJob*)), SLOTS, SLOT(changeTrashIcon()));
200
job = KIO::del(filesUrls);
202
connect(job, SIGNAL(result(KJob*)), this, SLOT(vfs_refresh(KJob*)));
206
205
// return a path to the file
207
KUrl normal_vfs::vfs_getFile(const QString& name){
209
if ( vfs_workingDir() == "/" ) url = "/"+name;
210
else url = vfs_workingDir()+"/"+name;
215
KUrl::List* normal_vfs::vfs_getFiles(QStringList* names){
216
KUrl::List* urls = new KUrl::List();
217
for(QStringList::Iterator name = names->begin(); name != names->end(); ++name){
218
urls->append( vfs_getFile(*name) );
223
void normal_vfs::vfs_mkdir(const QString& name){
224
if (!QDir(vfs_workingDir()).mkdir(name))
225
if (!quietMode) KMessageBox::sorry(krApp,i18n("Can't create a directory. Check your permissions."));
229
void normal_vfs::vfs_rename(const QString& fileName,const QString& newName){
233
//if( watcher ) watcher->stopScan(); // we will refresh manually this time...
235
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
239
url.setPath( vfs_workingDir()+"/"+fileName );
240
fileUrls.append(url);
241
dest.setPath(vfs_workingDir()+"/"+newName);
243
KIO::Job *job = KIO::move(fileUrls,dest);
244
connect(job,SIGNAL(result(KJob*)),this,SLOT(vfs_refresh(KJob*)));
247
vfile* normal_vfs::vfileFromName(const QString& name, char * rawName ){
248
QString path = vfs_workingDir()+"/"+name;
249
QByteArray fileName = rawName == 0 ? path.toLocal8Bit() : (vfs_workingDir()+"/").toLocal8Bit().append( rawName );
251
KDE_struct_stat stat_p;
254
KDE_lstat(fileName.data(),&stat_p);
255
KIO::filesize_t size = stat_p.st_size;
256
QString perm = KRpermHandler::mode2QString(stat_p.st_mode);
257
bool symLink= S_ISLNK(stat_p.st_mode);
258
if( S_ISDIR(stat_p.st_mode) ) perm[0] = 'd';
260
KUrl mimeUrl = KUrl(path);
261
QString mime=QString();
264
memset(symDest,0,256);
265
if( S_ISLNK(stat_p.st_mode) ){ // who the link is pointing to ?
267
endOfName=readlink(fileName.data(),symDest,256);
268
if ( endOfName != -1 ){
269
if ( QDir(QString::fromLocal8Bit( symDest ) ).exists() ) perm[0] = 'd';
270
if ( !QDir(vfs_workingDir()).exists( QString::fromLocal8Bit ( symDest ) ) ) mime = "Broken Link !";
272
else krOut << "Failed to read link: "<< path<<endl;
276
if( ::access( fileName.data(), R_OK ) == 0 )
278
if( ::access( fileName.data(), W_OK ) == 0 )
280
if( ::access( fileName.data(), X_OK ) == 0 )
283
// create a new virtual file object
284
vfile* temp=new vfile(name,size,perm,stat_p.st_mtime,symLink,stat_p.st_uid,
285
stat_p.st_gid,mime,QString::fromLocal8Bit( symDest ),stat_p.st_mode, rwx);
286
temp->vfile_setUrl( mimeUrl );
290
void normal_vfs::getACL( vfile *file, QString &acl, QString &defAcl )
292
acl = defAcl = QString();
293
#if defined( HAVE_POSIX_ACL )
294
QByteArray fileName = file->vfile_getUrl().path( KUrl::RemoveTrailingSlash ).toLocal8Bit();
295
#if HAVE_NON_POSIX_ACL_EXTENSIONS
296
if ( acl_extended_file( fileName.data() ) )
299
acl = getACL( fileName.data(), ACL_TYPE_ACCESS );
300
if( file->vfile_isDir() )
301
defAcl = getACL( fileName.data(), ACL_TYPE_DEFAULT );
302
#if HAVE_NON_POSIX_ACL_EXTENSIONS
308
QString normal_vfs::getACL( const QString & path, int type )
310
#if defined( HAVE_POSIX_ACL )
312
// do we have an acl for the file, and/or a default acl for the dir, if it is one?
313
if ( ( acl = acl_get_file( path.data(), type ) ) != 0 )
315
bool aclExtended = false;
317
#if HAVE_NON_POSIX_ACL_EXTENSIONS
318
aclExtended = acl_equiv_mode( acl, 0 );
321
int ret = acl_get_entry( acl, ACL_FIRST_ENTRY, &entry );
323
acl_tag_t currentTag;
324
acl_get_tag_type( entry, ¤tTag );
325
if ( currentTag != ACL_USER_OBJ &&
326
currentTag != ACL_GROUP_OBJ &&
327
currentTag != ACL_OTHER )
332
ret = acl_get_entry( acl, ACL_NEXT_ENTRY, &entry );
346
char *aclString = acl_to_text( acl, 0 );
347
QString ret = QString::fromLatin1( aclString );
348
acl_free( (void*)aclString );
206
KUrl normal_vfs::vfs_getFile(const QString& name)
209
if (vfs_workingDir() == "/") url = "/" + name;
210
else url = vfs_workingDir() + '/' + name;
215
KUrl::List* normal_vfs::vfs_getFiles(QStringList* names)
217
KUrl::List* urls = new KUrl::List();
218
for (QStringList::Iterator name = names->begin(); name != names->end(); ++name) {
219
urls->append(vfs_getFile(*name));
224
void normal_vfs::vfs_mkdir(const QString& name)
226
if (!QDir(vfs_workingDir()).mkdir(name))
227
if (!quietMode) KMessageBox::sorry(krApp, i18n("Can't create a directory. Check your permissions."));
231
void normal_vfs::vfs_rename(const QString& fileName, const QString& newName)
236
//if( watcher ) watcher->stopScan(); // we will refresh manually this time...
238
delete watcher; // stopScan is buggy, leaves reference on the directory, that's why we delete the watcher
242
url.setPath(vfs_workingDir() + '/' + fileName);
243
fileUrls.append(url);
244
dest.setPath(vfs_workingDir() + '/' + newName);
246
KIO::Job *job = KIO::move(fileUrls, dest);
247
connect(job, SIGNAL(result(KJob*)), this, SLOT(vfs_refresh(KJob*)));
250
vfile* normal_vfs::vfileFromName(const QString& name, char * rawName)
252
QString path = vfs_workingDir() + '/' + name;
253
QByteArray fileName = rawName == 0 ? path.toLocal8Bit() : (vfs_workingDir() + '/').toLocal8Bit().append(rawName);
255
KDE_struct_stat stat_p;
258
KDE_lstat(fileName.data(), &stat_p);
259
KIO::filesize_t size = stat_p.st_size;
260
QString perm = KRpermHandler::mode2QString(stat_p.st_mode);
261
bool symLink = S_ISLNK(stat_p.st_mode);
262
if (S_ISDIR(stat_p.st_mode)) perm[0] = 'd';
264
KUrl mimeUrl = KUrl(path);
268
memset(symDest, 0, 256);
269
if (S_ISLNK(stat_p.st_mode)) { // who the link is pointing to ?
271
endOfName = readlink(fileName.data(), symDest, 256);
272
if (endOfName != -1) {
273
if (QDir(QString::fromLocal8Bit(symDest)).exists()) perm[0] = 'd';
274
if (!QDir(vfs_workingDir()).exists(QString::fromLocal8Bit(symDest))) mime = "Broken Link !";
275
} else krOut << "Failed to read link: " << path << endl;
279
if (::access(fileName.data(), R_OK) == 0)
281
if (::access(fileName.data(), W_OK) == 0)
285
if (::access(fileName.data(), X_OK) == 0)
289
// create a new virtual file object
290
vfile* temp = new vfile(name, size, perm, stat_p.st_mtime, symLink, stat_p.st_uid,
291
stat_p.st_gid, mime, QString::fromLocal8Bit(symDest), stat_p.st_mode, rwx);
292
temp->vfile_setUrl(mimeUrl);
296
void normal_vfs::getACL(vfile *file, QString &acl, QString &defAcl)
300
#ifdef HAVE_POSIX_ACL
301
QByteArray fileName = file->vfile_getUrl().path(KUrl::RemoveTrailingSlash).toLocal8Bit();
302
#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
303
if (acl_extended_file(fileName.data())) {
305
acl = getACL(fileName.data(), ACL_TYPE_ACCESS);
306
if (file->vfile_isDir())
307
defAcl = getACL(fileName.data(), ACL_TYPE_DEFAULT);
308
#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
314
QString normal_vfs::getACL(const QString & path, int type)
316
#ifdef HAVE_POSIX_ACL
318
// do we have an acl for the file, and/or a default acl for the dir, if it is one?
319
if ((acl = acl_get_file(path.data(), type)) != 0) {
320
bool aclExtended = false;
322
#ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
323
aclExtended = acl_equiv_mode(acl, 0);
326
int ret = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
328
acl_tag_t currentTag;
329
acl_get_tag_type(entry, ¤tTag);
330
if (currentTag != ACL_USER_OBJ &&
331
currentTag != ACL_GROUP_OBJ &&
332
currentTag != ACL_OTHER) {
336
ret = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
349
char *aclString = acl_to_text(acl, 0);
350
QString ret = QString::fromLatin1(aclString);
351
acl_free((void*)aclString);
357
360
void normal_vfs::vfs_slotRefresh()
359
KConfigGroup group( krConfig, "Advanced");
360
int maxRefreshFrequency = group.readEntry("Max Refresh Frequency", 1000);
362
disconnect( &refreshTimer, SIGNAL( timeout() ), this, SLOT( vfs_slotRefresh() ) );
363
refreshTimer.setSingleShot( true );
364
refreshTimer.start( maxRefreshFrequency );
367
bool normal_vfs::burstRefresh(const QString& path ){
368
if( path == vfs_getOrigin().path(KUrl::RemoveTrailingSlash) ) {
369
if( !refreshTimer.isActive() ) {
370
// the directory itself is dirty - full refresh is needed
371
QTimer::singleShot(0, this, SLOT( vfs_slotRefresh() ) ); // safety: dirty signal comes from KDirWatch!
374
disconnect( &refreshTimer, SIGNAL( timeout() ), this, SLOT( vfs_slotRefresh() ) );
375
connect( &refreshTimer, SIGNAL( timeout() ), this, SLOT( vfs_slotRefresh() ) );
376
postponedRefreshURL = KUrl(path);
382
void normal_vfs::vfs_slotDirty(const QString& path){
383
if( disableRefresh ){
384
if( postponedRefreshURL.isEmpty() )
385
postponedRefreshURL = vfs_getOrigin();
389
if( burstRefresh( path ) )
392
KUrl url = KUrl(path);
393
QString name = url.fileName();
395
if ( name.left(1) == "." && !vfs_showHidden() )
398
// do we have it already ?
399
if( !vfs_search(name ) ) return vfs_slotCreated(path);
401
// we have an updated file..
402
removeFromList(name);
403
vfile* vf = vfileFromName(name, 0);
405
emit updatedVfile(vf);
408
void normal_vfs::vfs_slotCreated(const QString& path){
409
if( disableRefresh ){
410
if( postponedRefreshURL.isEmpty() )
411
postponedRefreshURL = vfs_getOrigin();
415
if( burstRefresh( path ) )
418
KUrl url = KUrl(path);
419
QString name = url.fileName();
421
if ( name.left(1) == "." && !vfs_showHidden() )
424
// if it's in the CVS - it's an update not new file
425
if( vfs_search(name) )
426
return vfs_slotDirty(path);
428
vfile* vf = vfileFromName(name, 0);
433
void normal_vfs::vfs_slotDeleted(const QString& path){
434
if( disableRefresh ){
435
if( postponedRefreshURL.isEmpty() )
436
postponedRefreshURL = vfs_getOrigin();
440
if( burstRefresh( path ) )
444
KUrl url = KUrl(path);
445
QString name = url.fileName();
447
// if it's not in the CVS - do nothing
448
if( vfs_search(name) ){
449
emit deletedVfile(name);
450
removeFromList(name);
362
KConfigGroup group(krConfig, "Advanced");
363
int maxRefreshFrequency = group.readEntry("Max Refresh Frequency", 1000);
365
disconnect(&refreshTimer, SIGNAL(timeout()), this, SLOT(vfs_slotRefresh()));
366
refreshTimer.setSingleShot(true);
367
refreshTimer.start(maxRefreshFrequency);
370
bool normal_vfs::burstRefresh(const QString& path)
372
QString parentPath = path;
373
int ndx = path.lastIndexOf(DIR_SEPARATOR);
375
parentPath = path.left(ndx == 0 ? 1 : ndx);
377
if (path == vfs_getOrigin().path(KUrl::RemoveTrailingSlash) ||
378
parentPath == vfs_getOrigin().path(KUrl::RemoveTrailingSlash)) {
379
if (!refreshTimer.isActive()) {
380
// the directory itself is dirty - full refresh is needed
381
QTimer::singleShot(0, this, SLOT(vfs_slotRefresh())); // safety: dirty signal comes from KDirWatch!
384
disconnect(&refreshTimer, SIGNAL(timeout()), this, SLOT(vfs_slotRefresh()));
385
connect(&refreshTimer, SIGNAL(timeout()), this, SLOT(vfs_slotRefresh()));
386
postponedRefreshURL = KUrl(path);
392
void normal_vfs::vfs_slotDirty(const QString& path)
394
if (disableRefresh) {
395
if (postponedRefreshURL.isEmpty())
396
postponedRefreshURL = vfs_getOrigin();
400
if (burstRefresh(path))
403
KUrl url = KUrl(path);
404
QString name = url.fileName();
406
if (name.left(1) == "." && !vfs_showHidden())
409
// do we have it already ?
410
vfile * vf = vfs_search(name);
411
if (!vf) return vfs_slotCreated(path);
413
// we have an updated file..
414
vfile *newVf = vfileFromName(name, 0);
417
emit updatedVfile(vf);
420
void normal_vfs::vfs_slotCreated(const QString& path)
422
if (disableRefresh) {
423
if (postponedRefreshURL.isEmpty())
424
postponedRefreshURL = vfs_getOrigin();
428
if (burstRefresh(path))
431
KUrl url = KUrl(path);
432
QString name = url.fileName();
434
if (name.left(1) == "." && !vfs_showHidden())
437
// if it's in the CVS - it's an update not new file
438
if (vfs_search(name))
439
return vfs_slotDirty(path);
441
vfile* vf = vfileFromName(name, 0);
446
void normal_vfs::vfs_slotDeleted(const QString& path)
448
if (disableRefresh) {
449
if (postponedRefreshURL.isEmpty())
450
postponedRefreshURL = vfs_getOrigin();
454
if (burstRefresh(path))
458
KUrl url = KUrl(path);
459
QString name = url.fileName();
461
// if it's not in the CVS - do nothing
462
vfile *vf = vfs_search(name);
464
emit deletedVfile(name);
465
removeFromList(name);
454
470
#include "normal_vfs.moc"