~ubuntu-branches/ubuntu/quantal/kde4libs/quantal

« back to all changes in this revision

Viewing changes to .pc/15_kfreebsd_support.diff/kioslave/file/file.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer, Philip Muškovac, Jonathan Thomas, Felix Geyer
  • Date: 2011-05-29 17:19:55 UTC
  • mfrom: (1.14.5 upstream) (0.1.19 sid)
  • Revision ID: package-import@ubuntu.com-20110529171955-nodep1593tuwyu6k
Tags: 4:4.6.3-1ubuntu1
[ Philip Muškovac]
* Drop kubuntu_83_fix_solid_network_status.diff
* Update Vcs links as the branch is owned by kubuntu-packagers now

[ Jonathan Thomas ]
* Drop kubuntu_06_user_disk_mounting. We no longer compile the hal
  backend, so this patch is useless.

[ Felix Geyer ]
* Merge from Debian unstable, remaining changes:
  - no build-dep on libaspell-dev
  - no build-dep on libfam-dev
  - kdelibs5-data: don't install kspell_aspell.desktop and
    usr/lib/kde4/kspell_aspell.so
  - kdelibs5-dev: don't install preparetips
  - Pass -DKDESU_USE_SUDO_DEFAULT=true to configure
  - dh_fixperms: exclude /usr/lib/kde4/libexec/fileshareset
  - set export KUBUNTU_DESKTOP_POT=kdelibs
  - don't apply use_dejavu_as_default_font.diff
  - don't apply kconf_update_migrate_from_kde3_icon_theme.diff
    - kdelibs5-data.install: drop usr/share/kde4/apps/kconf_update/kdeui.upd
  - don't build depend on libglu1-mesa-dev, not needed due to
    kubuntu_no_direct_gl_usage.diff
  - Add kdelibs5-data.links: link from /usr/share/doc/kde4 to kde for
    backwards compatible with old docs location
  - Keep the kdelibs5 transitional package
  - kdelibs5-dev.install: install ksambasharedata.h
  - kdelibs5-plugins: recommend ttf-dejavu-core instead of ttf-dejavu to save
    CD space.
* Add Breaks in addition to Replaces for moving files between packages.
* Drop no longer needed Breaks and Replaces.
* Completely drop kubuntu_51_launchpad_integration.diff and
  kubuntu_68_remove_applet_confirmation.diff.
  + Also drop the launchpad and kubuntu icons.
* Remove sequence numbers from kubuntu patches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
   Copyright (C) 2000-2002 Stephan Kulow <coolo@kde.org>
3
 
   Copyright (C) 2000-2002 David Faure <faure@kde.org>
4
 
   Copyright (C) 2000-2002 Waldo Bastian <bastian@kde.org>
5
 
   Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
6
 
   Copyright (C) 2007 Thiago Macieira <thiago@kde.org>
7
 
 
8
 
   This library is free software; you can redistribute it and/or
9
 
   modify it under the terms of the GNU Library General Public
10
 
   License (LGPL) as published by the Free Software Foundation;
11
 
   either version 2 of the License, or (at your option) any later
12
 
   version.
13
 
 
14
 
   This library is distributed in the hope that it will be useful,
15
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 
   Library General Public License for more details.
18
 
 
19
 
   You should have received a copy of the GNU Library General Public License
20
 
   along with this library; see the file COPYING.LIB.  If not, write to
21
 
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22
 
   Boston, MA 02110-1301, USA.
23
 
*/
24
 
 
25
 
#define QT_NO_CAST_FROM_ASCII
26
 
 
27
 
#include "file.h"
28
 
#include <QDirIterator>
29
 
 
30
 
#include <config.h>
31
 
#include <config-acl.h>
32
 
 
33
 
#include <sys/types.h>
34
 
#include <sys/wait.h>
35
 
#include <sys/stat.h>
36
 
#include <sys/socket.h>
37
 
#ifdef HAVE_SYS_TIME_H
38
 
#include <sys/time.h>
39
 
#endif
40
 
 
41
 
#ifdef HAVE_POSIX_ACL
42
 
#include <sys/acl.h>
43
 
#include <acl/libacl.h>
44
 
#endif
45
 
 
46
 
#include <assert.h>
47
 
#include <dirent.h>
48
 
#include <errno.h>
49
 
#include <fcntl.h>
50
 
#include <grp.h>
51
 
#include <pwd.h>
52
 
#include <stdio.h>
53
 
#include <stdlib.h>
54
 
#include <signal.h>
55
 
#include <time.h>
56
 
#include <utime.h>
57
 
#include <unistd.h>
58
 
#ifdef HAVE_STRING_H
59
 
#include <string.h>
60
 
#endif
61
 
 
62
 
#include <QtCore/QByteRef>
63
 
#include <QtCore/QDate>
64
 
#include <QtCore/QVarLengthArray>
65
 
#include <QtCore/QCoreApplication>
66
 
#include <QtCore/QRegExp>
67
 
#include <QtCore/QFile>
68
 
#ifdef Q_WS_WIN
69
 
#include <QtCore/QDir>
70
 
#include <QtCore/QFileInfo>
71
 
#endif
72
 
 
73
 
#include <kdebug.h>
74
 
#include <kurl.h>
75
 
#include <kcomponentdata.h>
76
 
#include <kconfig.h>
77
 
#include <kconfiggroup.h>
78
 
#include <ktemporaryfile.h>
79
 
#include <klocale.h>
80
 
#include <limits.h>
81
 
#include <kshell.h>
82
 
#include <kmountpoint.h>
83
 
#include <kstandarddirs.h>
84
 
 
85
 
#ifdef HAVE_VOLMGT
86
 
#include <volmgt.h>
87
 
#include <sys/mnttab.h>
88
 
#endif
89
 
 
90
 
#include <kdirnotify.h>
91
 
#include <kio/ioslave_defaults.h>
92
 
#include <kde_file.h>
93
 
#include <kglobal.h>
94
 
#include <kmimetype.h>
95
 
 
96
 
using namespace KIO;
97
 
 
98
 
#define MAX_IPC_SIZE (1024*32)
99
 
 
100
 
static QString testLogFile( const QByteArray&_filename );
101
 
#ifdef HAVE_POSIX_ACL
102
 
static bool isExtendedACL(  acl_t p_acl );
103
 
static void appendACLAtoms( const QByteArray & path, UDSEntry& entry,
104
 
                            mode_t type, bool withACL );
105
 
#endif
106
 
 
107
 
extern "C" int KDE_EXPORT kdemain( int argc, char **argv )
108
 
{
109
 
  QCoreApplication app( argc, argv ); // needed for QSocketNotifier
110
 
  KComponentData componentData( "kio_file", "kdelibs4" );
111
 
  ( void ) KGlobal::locale();
112
 
 
113
 
  kDebug(7101) << "Starting" << getpid();
114
 
 
115
 
  if (argc != 4)
116
 
  {
117
 
     fprintf(stderr, "Usage: kio_file protocol domain-socket1 domain-socket2\n");
118
 
     exit(-1);
119
 
  }
120
 
 
121
 
  FileProtocol slave(argv[2], argv[3]);
122
 
  slave.dispatchLoop();
123
 
 
124
 
  kDebug(7101) << "Done";
125
 
  return 0;
126
 
}
127
 
 
128
 
FileProtocol::FileProtocol( const QByteArray &pool, const QByteArray &app )
129
 
    : SlaveBase( "file", pool, app ), openFd(-1)
130
 
{
131
 
}
132
 
 
133
 
FileProtocol::~FileProtocol()
134
 
{
135
 
}
136
 
 
137
 
#ifdef HAVE_POSIX_ACL
138
 
static QString aclToText(acl_t acl) {
139
 
    ssize_t size = 0;
140
 
    char* txt = acl_to_text(acl, &size);
141
 
    const QString ret = QString::fromLatin1(txt, size);
142
 
    acl_free(txt);
143
 
    return ret;
144
 
}
145
 
#endif
146
 
 
147
 
int FileProtocol::setACL( const char *path, mode_t perm, bool directoryDefault )
148
 
{
149
 
    int ret = 0;
150
 
#ifdef HAVE_POSIX_ACL
151
 
 
152
 
    const QString ACLString = metaData(QLatin1String("ACL_STRING"));
153
 
    const QString defaultACLString = metaData(QLatin1String("DEFAULT_ACL_STRING"));
154
 
    // Empty strings mean leave as is
155
 
    if ( !ACLString.isEmpty() ) {
156
 
        acl_t acl = 0;
157
 
        if (ACLString == QLatin1String("ACL_DELETE")) {
158
 
            // user told us to delete the extended ACL, so let's write only
159
 
            // the minimal (UNIX permission bits) part
160
 
            acl = acl_from_mode( perm );
161
 
        }
162
 
        acl = acl_from_text( ACLString.toLatin1() );
163
 
        if ( acl_valid( acl ) == 0 ) { // let's be safe
164
 
            ret = acl_set_file( path, ACL_TYPE_ACCESS, acl );
165
 
            kDebug(7101) << "Set ACL on:" << path << "to:" << aclToText(acl);
166
 
        }
167
 
        acl_free( acl );
168
 
        if ( ret != 0 ) return ret; // better stop trying right away
169
 
    }
170
 
 
171
 
    if ( directoryDefault && !defaultACLString.isEmpty() ) {
172
 
        if ( defaultACLString == QLatin1String("ACL_DELETE") ) {
173
 
            // user told us to delete the default ACL, do so
174
 
            ret += acl_delete_def_file( path );
175
 
        } else {
176
 
            acl_t acl = acl_from_text( defaultACLString.toLatin1() );
177
 
            if ( acl_valid( acl ) == 0 ) { // let's be safe
178
 
                ret += acl_set_file( path, ACL_TYPE_DEFAULT, acl );
179
 
                kDebug(7101) << "Set Default ACL on:" << path << "to:" << aclToText(acl);
180
 
            }
181
 
            acl_free( acl );
182
 
        }
183
 
    }
184
 
#else
185
 
    Q_UNUSED(path);
186
 
    Q_UNUSED(perm);
187
 
    Q_UNUSED(directoryDefault);
188
 
#endif
189
 
    return ret;
190
 
}
191
 
 
192
 
void FileProtocol::chmod( const KUrl& url, int permissions )
193
 
{
194
 
    const QString path(url.toLocalFile());
195
 
    const QByteArray _path( QFile::encodeName(path) );
196
 
    /* FIXME: Should be atomic */
197
 
    if ( KDE::chmod( path, permissions ) == -1 ||
198
 
        ( setACL( _path.data(), permissions, false ) == -1 ) ||
199
 
        /* if not a directory, cannot set default ACLs */
200
 
        ( setACL( _path.data(), permissions, true ) == -1 && errno != ENOTDIR ) ) {
201
 
 
202
 
        switch (errno) {
203
 
            case EPERM:
204
 
            case EACCES:
205
 
                error(KIO::ERR_ACCESS_DENIED, path);
206
 
                break;
207
 
#if defined(ENOTSUP)
208
 
            case ENOTSUP: // from setACL since chmod can't return ENOTSUP
209
 
                error(KIO::ERR_UNSUPPORTED_ACTION, i18n("Setting ACL for %1", path));
210
 
                break;
211
 
#endif
212
 
            case ENOSPC:
213
 
                error(KIO::ERR_DISK_FULL, path);
214
 
                break;
215
 
            default:
216
 
                error(KIO::ERR_CANNOT_CHMOD, path);
217
 
        }
218
 
    } else
219
 
        finished();
220
 
}
221
 
 
222
 
void FileProtocol::setModificationTime( const KUrl& url, const QDateTime& mtime )
223
 
{
224
 
    const QString path(url.toLocalFile());
225
 
    KDE_struct_stat statbuf;
226
 
    if (KDE::lstat(path, &statbuf) == 0) {
227
 
        struct utimbuf utbuf;
228
 
        utbuf.actime = statbuf.st_atime; // access time, unchanged
229
 
        utbuf.modtime = mtime.toTime_t(); // modification time
230
 
        if (KDE::utime(path, &utbuf) != 0) {
231
 
            // TODO: errno could be EACCES, EPERM, EROFS
232
 
            error(KIO::ERR_CANNOT_SETTIME, path);
233
 
        } else {
234
 
            finished();
235
 
        }
236
 
    } else {
237
 
        error(KIO::ERR_DOES_NOT_EXIST, path);
238
 
    }
239
 
}
240
 
 
241
 
void FileProtocol::mkdir( const KUrl& url, int permissions )
242
 
{
243
 
    const QString path(url.toLocalFile());
244
 
 
245
 
    kDebug(7101) << path << "permission=" << permissions;
246
 
 
247
 
    // Remove existing file or symlink, if requested (#151851)
248
 
    if (metaData(QLatin1String("overwrite")) == QLatin1String("true"))
249
 
        QFile::remove(path);
250
 
 
251
 
    KDE_struct_stat buff;
252
 
    if ( KDE::lstat( path, &buff ) == -1 ) {
253
 
        if ( KDE::mkdir( path, 0777 /*umask will be applied*/ ) != 0 ) {
254
 
            if ( errno == EACCES ) {
255
 
                error(KIO::ERR_ACCESS_DENIED, path);
256
 
                return;
257
 
            } else if ( errno == ENOSPC ) {
258
 
                error(KIO::ERR_DISK_FULL, path);
259
 
                return;
260
 
            } else {
261
 
                error(KIO::ERR_COULD_NOT_MKDIR, path);
262
 
                return;
263
 
            }
264
 
        } else {
265
 
            if ( permissions != -1 )
266
 
                chmod( url, permissions );
267
 
            else
268
 
                finished();
269
 
            return;
270
 
        }
271
 
    }
272
 
 
273
 
    if ( S_ISDIR( buff.st_mode ) ) {
274
 
        kDebug(7101) << "ERR_DIR_ALREADY_EXIST";
275
 
        error(KIO::ERR_DIR_ALREADY_EXIST, path);
276
 
        return;
277
 
    }
278
 
    error(KIO::ERR_FILE_ALREADY_EXIST, path);
279
 
    return;
280
 
}
281
 
 
282
 
void FileProtocol::get( const KUrl& url )
283
 
{
284
 
    if (!url.isLocalFile()) {
285
 
        KUrl redir(url);
286
 
        redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
287
 
        redirection(redir);
288
 
        finished();
289
 
        return;
290
 
    }
291
 
 
292
 
    const QString path(url.toLocalFile());
293
 
    KDE_struct_stat buff;
294
 
    if ( KDE::stat( path, &buff ) == -1 ) {
295
 
        if ( errno == EACCES )
296
 
           error(KIO::ERR_ACCESS_DENIED, path);
297
 
        else
298
 
           error(KIO::ERR_DOES_NOT_EXIST, path);
299
 
        return;
300
 
    }
301
 
 
302
 
    if ( S_ISDIR( buff.st_mode ) ) {
303
 
        error(KIO::ERR_IS_DIRECTORY, path);
304
 
        return;
305
 
    }
306
 
    if ( !S_ISREG( buff.st_mode ) ) {
307
 
        error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
308
 
        return;
309
 
    }
310
 
 
311
 
    int fd = KDE::open( path, O_RDONLY);
312
 
    if ( fd < 0 ) {
313
 
        error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
314
 
        return;
315
 
    }
316
 
 
317
 
#ifdef HAVE_FADVISE
318
 
    posix_fadvise( fd, 0, 0, POSIX_FADV_SEQUENTIAL);
319
 
#endif
320
 
 
321
 
    // Determine the mimetype of the file to be retrieved, and emit it.
322
 
    // This is mandatory in all slaves (for KRun/BrowserRun to work)
323
 
    // In real "remote" slaves, this is usually done using findByNameAndContent
324
 
    // after receiving some data. But we don't know how much data the mimemagic rules
325
 
    // need, so for local files, better use findByUrl with localUrl=true.
326
 
    KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true /* local URL */ );
327
 
    emit mimeType( mt->name() );
328
 
    // Emit total size AFTER mimetype
329
 
    totalSize( buff.st_size );
330
 
 
331
 
    KIO::filesize_t processed_size = 0;
332
 
 
333
 
    const QString resumeOffset = metaData(QLatin1String("resume"));
334
 
    if ( !resumeOffset.isEmpty() )
335
 
    {
336
 
        bool ok;
337
 
        KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
338
 
        if (ok && (offset > 0) && (offset < buff.st_size))
339
 
        {
340
 
            if (KDE_lseek(fd, offset, SEEK_SET) == offset)
341
 
            {
342
 
                canResume ();
343
 
                processed_size = offset;
344
 
                kDebug(7101) << "Resume offset:" << KIO::number(offset);
345
 
            }
346
 
        }
347
 
    }
348
 
 
349
 
    char buffer[ MAX_IPC_SIZE ];
350
 
    QByteArray array;
351
 
 
352
 
    while( 1 )
353
 
    {
354
 
       int n = ::read( fd, buffer, MAX_IPC_SIZE );
355
 
       if (n == -1)
356
 
       {
357
 
          if (errno == EINTR)
358
 
              continue;
359
 
          error(KIO::ERR_COULD_NOT_READ, path);
360
 
          ::close(fd);
361
 
          return;
362
 
       }
363
 
       if (n == 0)
364
 
          break; // Finished
365
 
 
366
 
       array = QByteArray::fromRawData(buffer, n);
367
 
       data( array );
368
 
       array.clear();
369
 
 
370
 
       processed_size += n;
371
 
       processedSize( processed_size );
372
 
 
373
 
       //kDebug(7101) << "Processed: " << KIO::number (processed_size);
374
 
    }
375
 
 
376
 
    data( QByteArray() );
377
 
 
378
 
    ::close( fd );
379
 
 
380
 
    processedSize( buff.st_size );
381
 
    finished();
382
 
}
383
 
 
384
 
int write_all(int fd, const char *buf, size_t len)
385
 
{
386
 
   while (len > 0)
387
 
   {
388
 
      ssize_t written = write(fd, buf, len);
389
 
      if (written < 0)
390
 
      {
391
 
          if (errno == EINTR)
392
 
             continue;
393
 
          return -1;
394
 
      }
395
 
      buf += written;
396
 
      len -= written;
397
 
   }
398
 
   return 0;
399
 
}
400
 
 
401
 
void FileProtocol::open(const KUrl &url, QIODevice::OpenMode mode)
402
 
{
403
 
    kDebug(7101) << url;
404
 
 
405
 
    openPath = url.toLocalFile();
406
 
    KDE_struct_stat buff;
407
 
    if (KDE::stat(openPath, &buff) == -1) {
408
 
        if ( errno == EACCES )
409
 
           error(KIO::ERR_ACCESS_DENIED, openPath);
410
 
        else
411
 
           error(KIO::ERR_DOES_NOT_EXIST, openPath);
412
 
        return;
413
 
    }
414
 
 
415
 
    if ( S_ISDIR( buff.st_mode ) ) {
416
 
        error(KIO::ERR_IS_DIRECTORY, openPath);
417
 
        return;
418
 
    }
419
 
    if ( !S_ISREG( buff.st_mode ) ) {
420
 
        error(KIO::ERR_CANNOT_OPEN_FOR_READING, openPath);
421
 
        return;
422
 
    }
423
 
 
424
 
    int flags = 0;
425
 
    if (mode & QIODevice::ReadOnly) {
426
 
        if (mode & QIODevice::WriteOnly) {
427
 
            flags = O_RDWR | O_CREAT;
428
 
        } else {
429
 
            flags = O_RDONLY;
430
 
        }
431
 
    } else if (mode & QIODevice::WriteOnly) {
432
 
        flags = O_WRONLY | O_CREAT;
433
 
    }
434
 
 
435
 
    if (mode & QIODevice::Append) {
436
 
        flags |= O_APPEND;
437
 
    } else if (mode & QIODevice::Truncate) {
438
 
        flags |= O_TRUNC;
439
 
    }
440
 
 
441
 
    int fd = -1;
442
 
    if ( flags & O_CREAT)
443
 
        fd = KDE::open( openPath, flags, 0666);
444
 
    else
445
 
        fd = KDE::open( openPath, flags);
446
 
    if ( fd < 0 ) {
447
 
        error(KIO::ERR_CANNOT_OPEN_FOR_READING, openPath);
448
 
        return;
449
 
    }
450
 
    // Determine the mimetype of the file to be retrieved, and emit it.
451
 
    // This is mandatory in all slaves (for KRun/BrowserRun to work).
452
 
    // If we're not opening the file ReadOnly or ReadWrite, don't attempt to
453
 
    // read the file and send the mimetype.
454
 
    if (mode & QIODevice::ReadOnly){
455
 
        KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode, true /* local URL */ );
456
 
        emit mimeType( mt->name() );
457
 
   }
458
 
 
459
 
    totalSize( buff.st_size );
460
 
    position( 0 );
461
 
 
462
 
    emit opened();
463
 
    openFd = fd;
464
 
}
465
 
 
466
 
void FileProtocol::read(KIO::filesize_t bytes)
467
 
{
468
 
    kDebug(7101) << "File::open -- read";
469
 
    Q_ASSERT(openFd != -1);
470
 
 
471
 
    QVarLengthArray<char> buffer(bytes);
472
 
    while (true) {
473
 
        int res;
474
 
        do {
475
 
            res = ::read(openFd, buffer.data(), bytes);
476
 
        } while (res == -1 && errno == EINTR);
477
 
 
478
 
        if (res > 0) {
479
 
            QByteArray array = QByteArray::fromRawData(buffer.data(), res);
480
 
            data( array );
481
 
            bytes -= res;
482
 
        } else {
483
 
            // empty array designates eof
484
 
            data(QByteArray());
485
 
            if (res != 0) {
486
 
                error(KIO::ERR_COULD_NOT_READ, openPath);
487
 
                close();
488
 
            }
489
 
            break;
490
 
        }
491
 
        if (bytes <= 0) break;
492
 
    }
493
 
}
494
 
 
495
 
void FileProtocol::write(const QByteArray &data)
496
 
{
497
 
    kDebug(7101) << "File::open -- write";
498
 
    Q_ASSERT(openFd != -1);
499
 
 
500
 
    if (write_all(openFd, data.constData(), data.size())) {
501
 
        if (errno == ENOSPC) { // disk full
502
 
            error(KIO::ERR_DISK_FULL, openPath);
503
 
            close();
504
 
        } else {
505
 
            kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
506
 
            error(KIO::ERR_COULD_NOT_WRITE, openPath);
507
 
            close();
508
 
        }
509
 
    } else {
510
 
        written(data.size());
511
 
    }
512
 
}
513
 
 
514
 
void FileProtocol::seek(KIO::filesize_t offset)
515
 
{
516
 
    kDebug(7101) << "File::open -- seek";
517
 
    Q_ASSERT(openFd != -1);
518
 
 
519
 
    int res = KDE_lseek(openFd, offset, SEEK_SET);
520
 
    if (res != -1) {
521
 
        position( offset );
522
 
    } else {
523
 
        error(KIO::ERR_COULD_NOT_SEEK, openPath);
524
 
        close();
525
 
    }
526
 
}
527
 
 
528
 
void FileProtocol::close()
529
 
{
530
 
    kDebug(7101) << "File::open -- close ";
531
 
    Q_ASSERT(openFd != -1);
532
 
 
533
 
    ::close( openFd );
534
 
    openFd = -1;
535
 
    openPath.clear();
536
 
 
537
 
    finished();
538
 
}
539
 
 
540
 
void FileProtocol::put( const KUrl& url, int _mode, KIO::JobFlags _flags )
541
 
{
542
 
    const QString dest_orig = url.toLocalFile();
543
 
 
544
 
    kDebug(7101) << dest_orig << "mode=" << _mode;
545
 
 
546
 
    QString dest_part(dest_orig + QLatin1String(".part"));
547
 
 
548
 
    KDE_struct_stat buff_orig;
549
 
    const bool bOrigExists = (KDE::lstat(dest_orig, &buff_orig) != -1);
550
 
    bool bPartExists = false;
551
 
    const bool bMarkPartial = config()->readEntry("MarkPartial", true);
552
 
 
553
 
    if (bMarkPartial)
554
 
    {
555
 
        KDE_struct_stat buff_part;
556
 
        bPartExists = (KDE::stat( dest_part, &buff_part ) != -1);
557
 
 
558
 
        if (bPartExists && !(_flags & KIO::Resume) && !(_flags & KIO::Overwrite) && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
559
 
        {
560
 
            kDebug(7101) << "calling canResume with" << KIO::number(buff_part.st_size);
561
 
 
562
 
            // Maybe we can use this partial file for resuming
563
 
            // Tell about the size we have, and the app will tell us
564
 
            // if it's ok to resume or not.
565
 
            _flags |= canResume( buff_part.st_size ) ? KIO::Resume : KIO::DefaultFlags;
566
 
 
567
 
            kDebug(7101) << "got answer" << (_flags & KIO::Resume);
568
 
        }
569
 
    }
570
 
 
571
 
    if ( bOrigExists && !(_flags & KIO::Overwrite) && !(_flags & KIO::Resume))
572
 
    {
573
 
        if (S_ISDIR(buff_orig.st_mode))
574
 
            error( KIO::ERR_DIR_ALREADY_EXIST, dest_orig );
575
 
        else
576
 
            error( KIO::ERR_FILE_ALREADY_EXIST, dest_orig );
577
 
        return;
578
 
    }
579
 
 
580
 
    int result;
581
 
    QString dest;
582
 
    QByteArray _dest;
583
 
 
584
 
    int fd = -1;
585
 
 
586
 
    // Loop until we got 0 (end of data)
587
 
    do
588
 
    {
589
 
        QByteArray buffer;
590
 
        dataReq(); // Request for data
591
 
        result = readData( buffer );
592
 
 
593
 
        if (result >= 0)
594
 
        {
595
 
            if (dest.isEmpty())
596
 
            {
597
 
                if (bMarkPartial)
598
 
                {
599
 
                    kDebug(7101) << "Appending .part extension to" << dest_orig;
600
 
                    dest = dest_part;
601
 
                    if ( bPartExists && !(_flags & KIO::Resume) )
602
 
                    {
603
 
                        kDebug(7101) << "Deleting partial file" << dest_part;
604
 
                        QFile::remove( dest_part );
605
 
                        // Catch errors when we try to open the file.
606
 
                    }
607
 
                }
608
 
                else
609
 
                {
610
 
                    dest = dest_orig;
611
 
                    if ( bOrigExists && !(_flags & KIO::Resume) )
612
 
                    {
613
 
                        kDebug(7101) << "Deleting destination file" << dest_orig;
614
 
                        QFile::remove( dest_orig );
615
 
                        // Catch errors when we try to open the file.
616
 
                    }
617
 
                }
618
 
 
619
 
                if ( (_flags & KIO::Resume) )
620
 
                {
621
 
                    fd = KDE::open( dest, O_RDWR );  // append if resuming
622
 
                    KDE_lseek(fd, 0, SEEK_END); // Seek to end
623
 
                }
624
 
                else
625
 
                {
626
 
                    // WABA: Make sure that we keep writing permissions ourselves,
627
 
                    // otherwise we can be in for a surprise on NFS.
628
 
                    mode_t initialMode;
629
 
                    if (_mode != -1)
630
 
                        initialMode = _mode | S_IWUSR | S_IRUSR;
631
 
                    else
632
 
                        initialMode = 0666;
633
 
 
634
 
                    fd = KDE::open(dest, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
635
 
                }
636
 
 
637
 
                if ( fd < 0 )
638
 
                {
639
 
                    kDebug(7101) << "####################### COULD NOT WRITE" << dest << "_mode=" << _mode;
640
 
                    kDebug(7101) << "errno==" << errno << "(" << strerror(errno) << ")";
641
 
                    if ( errno == EACCES )
642
 
                        error(KIO::ERR_WRITE_ACCESS_DENIED, dest);
643
 
                    else
644
 
                        error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest);
645
 
                    return;
646
 
                }
647
 
            }
648
 
 
649
 
            if (write_all( fd, buffer.data(), buffer.size()))
650
 
            {
651
 
                if ( errno == ENOSPC ) // disk full
652
 
                {
653
 
                  error(KIO::ERR_DISK_FULL, dest_orig);
654
 
                  result = -2; // means: remove dest file
655
 
                }
656
 
                else
657
 
                {
658
 
                  kWarning(7101) << "Couldn't write. Error:" << strerror(errno);
659
 
                  error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
660
 
                  result = -1;
661
 
                }
662
 
            }
663
 
        }
664
 
    }
665
 
    while ( result > 0 );
666
 
 
667
 
    // An error occurred deal with it.
668
 
    if (result < 0)
669
 
    {
670
 
        kDebug(7101) << "Error during 'put'. Aborting.";
671
 
 
672
 
        if (fd != -1)
673
 
        {
674
 
          ::close(fd);
675
 
 
676
 
          KDE_struct_stat buff;
677
 
          if (bMarkPartial && KDE::stat( dest, &buff ) == 0)
678
 
          {
679
 
            int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
680
 
            if (buff.st_size <  size)
681
 
              remove(_dest.data());
682
 
          }
683
 
        }
684
 
 
685
 
        ::exit(255);
686
 
    }
687
 
 
688
 
    if ( fd == -1 ) // we got nothing to write out, so we never opened the file
689
 
    {
690
 
        finished();
691
 
        return;
692
 
    }
693
 
 
694
 
    if ( ::close(fd) )
695
 
    {
696
 
        kWarning(7101) << "Error when closing file descriptor:" << strerror(errno);
697
 
        error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
698
 
        return;
699
 
    }
700
 
 
701
 
    // after full download rename the file back to original name
702
 
    if ( bMarkPartial )
703
 
    {
704
 
        // If the original URL is a symlink and we were asked to overwrite it,
705
 
        // remove the symlink first. This ensures that we do not overwrite the
706
 
        // current source if the symlink points to it.
707
 
        if( (_flags & KIO::Overwrite) && S_ISLNK( buff_orig.st_mode ) )
708
 
          QFile::remove( dest_orig );
709
 
        if ( KDE::rename( dest, dest_orig ) )
710
 
        {
711
 
            kWarning(7101) << " Couldn't rename " << _dest << " to " << dest_orig;
712
 
            error(KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig);
713
 
            return;
714
 
        }
715
 
        org::kde::KDirNotify::emitFileRenamed(dest, dest_orig);
716
 
    }
717
 
 
718
 
    // set final permissions
719
 
    if ( _mode != -1 && !(_flags & KIO::Resume) )
720
 
    {
721
 
        if (KDE::chmod(dest_orig, _mode) != 0)
722
 
        {
723
 
            // couldn't chmod. Eat the error if the filesystem apparently doesn't support it.
724
 
            KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(dest_orig);
725
 
            if (mp && mp->testFileSystemFlag(KMountPoint::SupportsChmod))
726
 
                 warning( i18n( "Could not change permissions for\n%1" ,  dest_orig ) );
727
 
        }
728
 
    }
729
 
 
730
 
    // set modification time
731
 
    const QString mtimeStr = metaData(QLatin1String("modified"));
732
 
    if ( !mtimeStr.isEmpty() ) {
733
 
        QDateTime dt = QDateTime::fromString( mtimeStr, Qt::ISODate );
734
 
        if ( dt.isValid() ) {
735
 
            KDE_struct_stat dest_statbuf;
736
 
            if (KDE::stat( dest_orig, &dest_statbuf ) == 0) {
737
 
                struct timeval utbuf[2];
738
 
                // access time
739
 
                utbuf[0].tv_sec = dest_statbuf.st_atime; // access time, unchanged  ## TODO preserve msec
740
 
                utbuf[0].tv_usec = 0;
741
 
                // modification time
742
 
                utbuf[1].tv_sec = dt.toTime_t();
743
 
                utbuf[1].tv_usec = dt.time().msec() * 1000;
744
 
                utimes( QFile::encodeName(dest_orig), utbuf );
745
 
            }
746
 
        }
747
 
 
748
 
    }
749
 
 
750
 
    // We have done our job => finish
751
 
    finished();
752
 
}
753
 
 
754
 
QString FileProtocol::getUserName( uid_t uid ) const
755
 
{
756
 
    if ( !mUsercache.contains( uid ) ) {
757
 
        struct passwd *user = getpwuid( uid );
758
 
        if ( user ) {
759
 
            mUsercache.insert( uid, QString::fromLatin1(user->pw_name) );
760
 
        }
761
 
        else
762
 
            return QString::number( uid );
763
 
    }
764
 
    return mUsercache[uid];
765
 
}
766
 
 
767
 
QString FileProtocol::getGroupName( gid_t gid ) const
768
 
{
769
 
    if ( !mGroupcache.contains( gid ) ) {
770
 
        struct group *grp = getgrgid( gid );
771
 
        if ( grp ) {
772
 
            mGroupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
773
 
        }
774
 
        else
775
 
            return QString::number( gid );
776
 
    }
777
 
    return mGroupcache[gid];
778
 
}
779
 
 
780
 
bool FileProtocol::createUDSEntry( const QString & filename, const QByteArray & path, UDSEntry & entry,
781
 
                                   short int details, bool withACL )
782
 
{
783
 
#ifndef HAVE_POSIX_ACL
784
 
    Q_UNUSED(withACL);
785
 
#endif
786
 
    assert(entry.count() == 0); // by contract :-)
787
 
    // entry.reserve( 8 ); // speed up QHash insertion
788
 
 
789
 
    entry.insert( KIO::UDSEntry::UDS_NAME, filename );
790
 
 
791
 
    mode_t type;
792
 
    mode_t access;
793
 
    KDE_struct_stat buff;
794
 
 
795
 
    if ( KDE_lstat( path.data(), &buff ) == 0 )  {
796
 
 
797
 
        if (S_ISLNK(buff.st_mode)) {
798
 
 
799
 
            char buffer2[ 1000 ];
800
 
            int n = readlink( path.data(), buffer2, 1000 );
801
 
            if ( n != -1 ) {
802
 
                buffer2[ n ] = 0;
803
 
            }
804
 
 
805
 
            entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName( buffer2 ) );
806
 
 
807
 
            // A symlink -> follow it only if details>1
808
 
            if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
809
 
                // It is a link pointing to nowhere
810
 
                type = S_IFMT - 1;
811
 
                access = S_IRWXU | S_IRWXG | S_IRWXO;
812
 
 
813
 
                entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
814
 
                entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
815
 
                entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
816
 
                goto notype;
817
 
 
818
 
            }
819
 
        }
820
 
    } else {
821
 
        // kWarning() << "lstat didn't work on " << path.data();
822
 
        return false;
823
 
    }
824
 
 
825
 
    type = buff.st_mode & S_IFMT; // extract file type
826
 
    access = buff.st_mode & 07777; // extract permissions
827
 
 
828
 
    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
829
 
    entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
830
 
 
831
 
    entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
832
 
 
833
 
#ifdef HAVE_POSIX_ACL
834
 
    if (details > 0) {
835
 
        /* Append an atom indicating whether the file has extended acl information
836
 
         * and if withACL is specified also one with the acl itself. If it's a directory
837
 
         * and it has a default ACL, also append that. */
838
 
        appendACLAtoms( path, entry, type, withACL );
839
 
    }
840
 
#endif
841
 
 
842
 
 notype:
843
 
    if (details > 0) {
844
 
        entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
845
 
        entry.insert( KIO::UDSEntry::UDS_USER, getUserName( buff.st_uid ) );
846
 
        entry.insert( KIO::UDSEntry::UDS_GROUP, getGroupName( buff.st_gid ) );
847
 
        entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime );
848
 
    }
849
 
 
850
 
    // Note: buff.st_ctime isn't the creation time !
851
 
    // We made that mistake for KDE 2.0, but it's in fact the
852
 
    // "file status" change time, which we don't care about.
853
 
 
854
 
    return true;
855
 
}
856
 
 
857
 
void FileProtocol::special( const QByteArray &data)
858
 
{
859
 
    int tmp;
860
 
    QDataStream stream(data);
861
 
 
862
 
    stream >> tmp;
863
 
    switch (tmp) {
864
 
    case 1:
865
 
      {
866
 
        QString fstype, dev, point;
867
 
        qint8 iRo;
868
 
 
869
 
        stream >> iRo >> fstype >> dev >> point;
870
 
 
871
 
        bool ro = ( iRo != 0 );
872
 
 
873
 
        kDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << point << " ro=" << ro;
874
 
        bool ok = pmount( dev );
875
 
        if (ok)
876
 
            finished();
877
 
        else
878
 
            mount( ro, fstype.toAscii(), dev, point );
879
 
 
880
 
      }
881
 
      break;
882
 
    case 2:
883
 
      {
884
 
        QString point;
885
 
        stream >> point;
886
 
        bool ok = pumount( point );
887
 
        if (ok)
888
 
            finished();
889
 
        else
890
 
            unmount( point );
891
 
      }
892
 
      break;
893
 
 
894
 
    default:
895
 
      break;
896
 
    }
897
 
}
898
 
 
899
 
void FileProtocol::mount( bool _ro, const char *_fstype, const QString& _dev, const QString& _point )
900
 
{
901
 
    kDebug(7101) << "fstype=" << _fstype;
902
 
 
903
 
#ifndef _WIN32_WCE
904
 
#ifdef HAVE_VOLMGT
905
 
        /*
906
 
         *  support for Solaris volume management
907
 
         */
908
 
        QString err;
909
 
        QByteArray devname = QFile::encodeName( _dev );
910
 
 
911
 
        if( volmgt_running() ) {
912
 
//              kDebug(7101) << "VOLMGT: vold ok.";
913
 
                if( volmgt_check( devname.data() ) == 0 ) {
914
 
                        kDebug(7101) << "VOLMGT: no media in "
915
 
                                        << devname.data();
916
 
                        err = i18n("No Media inserted or Media not recognized.");
917
 
                        error( KIO::ERR_COULD_NOT_MOUNT, err );
918
 
                        return;
919
 
                } else {
920
 
                        kDebug(7101) << "VOLMGT: " << devname.data()
921
 
                                << ": media ok";
922
 
                        finished();
923
 
                        return;
924
 
                }
925
 
        } else {
926
 
                err = i18n("\"vold\" is not running.");
927
 
                kDebug(7101) << "VOLMGT: " << err;
928
 
                error( KIO::ERR_COULD_NOT_MOUNT, err );
929
 
                return;
930
 
        }
931
 
#else
932
 
 
933
 
 
934
 
    KTemporaryFile tmpFile;
935
 
    tmpFile.setAutoRemove(false);
936
 
    tmpFile.open();
937
 
    QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
938
 
    QByteArray dev;
939
 
    if (_dev.startsWith(QLatin1String("LABEL="))) { // turn LABEL=foo into -L foo (#71430)
940
 
        QString labelName = _dev.mid( 6 );
941
 
        dev = "-L ";
942
 
        dev += QFile::encodeName( KShell::quoteArg( labelName ) ); // is it correct to assume same encoding as filesystem?
943
 
    } else if (_dev.startsWith(QLatin1String("UUID="))) { // and UUID=bar into -U bar
944
 
        QString uuidName = _dev.mid( 5 );
945
 
        dev = "-U ";
946
 
        dev += QFile::encodeName( KShell::quoteArg( uuidName ) );
947
 
    }
948
 
    else
949
 
        dev = QFile::encodeName( KShell::quoteArg(_dev) ); // get those ready to be given to a shell
950
 
 
951
 
    QByteArray point = QFile::encodeName( KShell::quoteArg(_point) );
952
 
    bool fstype_empty = !_fstype || !*_fstype;
953
 
    QByteArray fstype = KShell::quoteArg(QString::fromLatin1(_fstype)).toLatin1(); // good guess
954
 
    QByteArray readonly = _ro ? "-r" : "";
955
 
    QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
956
 
    QString path = QLatin1String("/sbin:/bin");
957
 
    if(!epath.isEmpty())
958
 
        path += QLatin1String(":") + epath;
959
 
    QByteArray mountProg = KGlobal::dirs()->findExe(QLatin1String("mount"), path).toLocal8Bit();
960
 
    if (mountProg.isEmpty()){
961
 
      error( KIO::ERR_COULD_NOT_MOUNT, i18n("Could not find program \"mount\""));
962
 
      return;
963
 
    }
964
 
 
965
 
    // Two steps, in case mount doesn't like it when we pass all options
966
 
    for ( int step = 0 ; step <= 1 ; step++ )
967
 
    {
968
 
        QByteArray buffer = mountProg + ' ';
969
 
        // Mount using device only if no fstype nor mountpoint (KDE-1.x like)
970
 
        if ( !dev.isEmpty() && _point.isEmpty() && fstype_empty )
971
 
            buffer += dev;
972
 
        else
973
 
          // Mount using the mountpoint, if no fstype nor device (impossible in first step)
974
 
          if ( !_point.isEmpty() && dev.isEmpty() && fstype_empty )
975
 
              buffer += point;
976
 
          else
977
 
            // mount giving device + mountpoint but no fstype
978
 
            if ( !_point.isEmpty() && !dev.isEmpty() && fstype_empty )
979
 
                buffer += readonly + ' ' + dev + ' ' + point;
980
 
            else
981
 
              // mount giving device + mountpoint + fstype
982
 
#if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
983
 
                // believe this is true for SVR4 in general
984
 
                buffer += "-F " + fstype + ' ' + (_ro ? "-oro" : "") + ' ' + dev + ' ' + point;
985
 
#else
986
 
                buffer += readonly + " -t " + fstype + ' ' + dev + ' ' + point;
987
 
#endif
988
 
        buffer += " 2>" + tmpFileName;
989
 
        kDebug(7101) << buffer;
990
 
 
991
 
        int mount_ret = system( buffer.constData() );
992
 
 
993
 
        QString err = testLogFile( tmpFileName );
994
 
        if ( err.isEmpty() && mount_ret == 0)
995
 
        {
996
 
            finished();
997
 
            return;
998
 
        }
999
 
        else
1000
 
        {
1001
 
            // Didn't work - or maybe we just got a warning
1002
 
            KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( _dev );
1003
 
            // Is the device mounted ?
1004
 
            if ( mp && mount_ret == 0)
1005
 
            {
1006
 
                kDebug(7101) << "mount got a warning:" << err;
1007
 
                warning( err );
1008
 
                finished();
1009
 
                return;
1010
 
            }
1011
 
            else
1012
 
            {
1013
 
                if ( (step == 0) && !_point.isEmpty())
1014
 
                {
1015
 
                    kDebug(7101) << err;
1016
 
                    kDebug(7101) << "Mounting with those options didn't work, trying with only mountpoint";
1017
 
                    fstype = "";
1018
 
                    fstype_empty = true;
1019
 
                    dev = "";
1020
 
                    // The reason for trying with only mountpoint (instead of
1021
 
                    // only device) is that some people (hi Malte!) have the
1022
 
                    // same device associated with two mountpoints
1023
 
                    // for different fstypes, like /dev/fd0 /mnt/e2floppy and
1024
 
                    // /dev/fd0 /mnt/dosfloppy.
1025
 
                    // If the user has the same mountpoint associated with two
1026
 
                    // different devices, well they shouldn't specify the
1027
 
                    // mountpoint but just the device.
1028
 
                }
1029
 
                else
1030
 
                {
1031
 
                    error( KIO::ERR_COULD_NOT_MOUNT, err );
1032
 
                    return;
1033
 
                }
1034
 
            }
1035
 
        }
1036
 
    }
1037
 
#endif /* ! HAVE_VOLMGT */
1038
 
#else
1039
 
    QString err;
1040
 
    err = i18n("mounting is not supported by wince.");
1041
 
    error( KIO::ERR_COULD_NOT_MOUNT, err );
1042
 
#endif
1043
 
 
1044
 
}
1045
 
 
1046
 
 
1047
 
void FileProtocol::unmount( const QString& _point )
1048
 
{
1049
 
#ifndef _WIN32_WCE
1050
 
    QByteArray buffer;
1051
 
 
1052
 
    KTemporaryFile tmpFile;
1053
 
    tmpFile.setAutoRemove(false);
1054
 
    tmpFile.open();
1055
 
    QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
1056
 
    QString err;
1057
 
 
1058
 
#ifdef HAVE_VOLMGT
1059
 
        /*
1060
 
         *  support for Solaris volume management
1061
 
         */
1062
 
        char *devname;
1063
 
        char *ptr;
1064
 
        FILE *mnttab;
1065
 
        struct mnttab mnt;
1066
 
 
1067
 
        if( volmgt_running() ) {
1068
 
                kDebug(7101) << "VOLMGT: looking for "
1069
 
                        << _point.toLocal8Bit();
1070
 
 
1071
 
                if( (mnttab = KDE_fopen( MNTTAB, "r" )) == NULL ) {
1072
 
                        err = QLatin1String("could not open mnttab");
1073
 
                        kDebug(7101) << "VOLMGT: " << err;
1074
 
                        error( KIO::ERR_COULD_NOT_UNMOUNT, err );
1075
 
                        return;
1076
 
                }
1077
 
 
1078
 
                /*
1079
 
                 *  since there's no way to derive the device name from
1080
 
                 *  the mount point through the volmgt library (and
1081
 
                 *  media_findname() won't work in this case), we have to
1082
 
                 *  look ourselves...
1083
 
                 */
1084
 
                devname = NULL;
1085
 
                rewind( mnttab );
1086
 
                while( getmntent( mnttab, &mnt ) == 0 ) {
1087
 
                        if( strcmp( _point.toLocal8Bit(), mnt.mnt_mountp ) == 0 ){
1088
 
                                devname = mnt.mnt_special;
1089
 
                                break;
1090
 
                        }
1091
 
                }
1092
 
                fclose( mnttab );
1093
 
 
1094
 
                if( devname == NULL ) {
1095
 
                        err = QLatin1String("not in mnttab");
1096
 
                        kDebug(7101) << "VOLMGT: "
1097
 
                                << QFile::encodeName(_point).data()
1098
 
                                << ": " << err;
1099
 
                        error( KIO::ERR_COULD_NOT_UNMOUNT, err );
1100
 
                        return;
1101
 
                }
1102
 
 
1103
 
                /*
1104
 
                 *  strip off the directory name (volume name)
1105
 
                 *  the eject(1) command will handle unmounting and
1106
 
                 *  physically eject the media (if possible)
1107
 
                 */
1108
 
                ptr = strrchr( devname, '/' );
1109
 
                *ptr = '\0';
1110
 
                QByteArray qdevname(QFile::encodeName(KShell::quoteArg(QFile::decodeName(QByteArray(devname)))).data());
1111
 
                buffer = "/usr/bin/eject " + qdevname + " 2>" + tmpFileName;
1112
 
                kDebug(7101) << "VOLMGT: eject " << qdevname;
1113
 
 
1114
 
                /*
1115
 
                 *  from eject(1): exit status == 0 => need to manually eject
1116
 
                 *                 exit status == 4 => media was ejected
1117
 
                 */
1118
 
                if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
1119
 
                        /*
1120
 
                         *  this is not an error, so skip "testLogFile()"
1121
 
                         *  to avoid wrong/confusing error popup. The
1122
 
                         *  temporary file is removed by KTemporaryFile's
1123
 
                         *  destructor, so don't do that manually.
1124
 
                         */
1125
 
                        finished();
1126
 
                        return;
1127
 
                }
1128
 
        } else {
1129
 
                /*
1130
 
                 *  eject(1) should do its job without vold(1M) running,
1131
 
                 *  so we probably could call eject anyway, but since the
1132
 
                 *  media is mounted now, vold must've died for some reason
1133
 
                 *  during the user's session, so it should be restarted...
1134
 
                 */
1135
 
                err = i18n("\"vold\" is not running.");
1136
 
                kDebug(7101) << "VOLMGT: " << err;
1137
 
                error( KIO::ERR_COULD_NOT_UNMOUNT, err );
1138
 
                return;
1139
 
        }
1140
 
#else
1141
 
    QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
1142
 
    QString path = QLatin1String("/sbin:/bin");
1143
 
    if (!epath.isEmpty())
1144
 
       path += QLatin1Char(':') + epath;
1145
 
    QByteArray umountProg = KGlobal::dirs()->findExe(QLatin1String("umount"), path).toLocal8Bit();
1146
 
 
1147
 
    if (umountProg.isEmpty()) {
1148
 
        error( KIO::ERR_COULD_NOT_UNMOUNT, i18n("Could not find program \"umount\""));
1149
 
        return;
1150
 
    }
1151
 
    buffer = umountProg + ' ' + QFile::encodeName(KShell::quoteArg(_point)) + " 2>" + tmpFileName;
1152
 
    system( buffer.constData() );
1153
 
#endif /* HAVE_VOLMGT */
1154
 
 
1155
 
    err = testLogFile( tmpFileName );
1156
 
    if ( err.isEmpty() )
1157
 
        finished();
1158
 
    else
1159
 
        error( KIO::ERR_COULD_NOT_UNMOUNT, err );
1160
 
#else
1161
 
    QString err;
1162
 
    err = i18n("unmounting is not supported by wince.");
1163
 
    error( KIO::ERR_COULD_NOT_MOUNT, err );
1164
 
#endif
1165
 
}
1166
 
 
1167
 
/*************************************
1168
 
 *
1169
 
 * pmount handling
1170
 
 *
1171
 
 *************************************/
1172
 
 
1173
 
bool FileProtocol::pmount(const QString &dev)
1174
 
{
1175
 
#ifndef _WIN32_WCE
1176
 
    QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
1177
 
    QString path = QLatin1String("/sbin:/bin");
1178
 
    if (!epath.isEmpty())
1179
 
        path += QLatin1Char(':') + epath;
1180
 
    QString pmountProg = KGlobal::dirs()->findExe(QLatin1String("pmount"), path);
1181
 
 
1182
 
    if (pmountProg.isEmpty())
1183
 
        return false;
1184
 
 
1185
 
    QByteArray buffer = QFile::encodeName(pmountProg) + ' ' +
1186
 
                        QFile::encodeName(KShell::quoteArg(dev));
1187
 
 
1188
 
    int res = system( buffer.constData() );
1189
 
 
1190
 
    return res==0;
1191
 
#else
1192
 
    return false;
1193
 
#endif
1194
 
}
1195
 
 
1196
 
bool FileProtocol::pumount(const QString &point)
1197
 
{
1198
 
#ifndef _WIN32_WCE
1199
 
    KMountPoint::Ptr mp = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName).findByPath(point);
1200
 
    if (!mp)
1201
 
        return false;
1202
 
    QString dev = mp->realDeviceName();
1203
 
    if (dev.isEmpty()) return false;
1204
 
 
1205
 
    QString epath = QString::fromLocal8Bit(qgetenv("PATH"));
1206
 
    QString path = QLatin1String("/sbin:/bin");
1207
 
    if (!epath.isEmpty())
1208
 
        path += QLatin1Char(':') + epath;
1209
 
    QString pumountProg = KGlobal::dirs()->findExe(QLatin1String("pumount"), path);
1210
 
 
1211
 
    if (pumountProg.isEmpty())
1212
 
        return false;
1213
 
 
1214
 
    QByteArray buffer = QFile::encodeName(pumountProg);
1215
 
    buffer += ' ';
1216
 
    buffer += QFile::encodeName(KShell::quoteArg(dev));
1217
 
 
1218
 
    int res = system( buffer.data() );
1219
 
 
1220
 
    return res==0;
1221
 
#else
1222
 
    return false;
1223
 
#endif
1224
 
}
1225
 
 
1226
 
/*************************************
1227
 
 *
1228
 
 * Utilities
1229
 
 *
1230
 
 *************************************/
1231
 
 
1232
 
static QString testLogFile( const QByteArray& _filename )
1233
 
{
1234
 
    char buffer[ 1024 ];
1235
 
    KDE_struct_stat buff;
1236
 
 
1237
 
    QString result;
1238
 
 
1239
 
    KDE_stat( _filename, &buff );
1240
 
    int size = buff.st_size;
1241
 
    if ( size == 0 ) {
1242
 
        unlink( _filename );
1243
 
        return result;
1244
 
    }
1245
 
 
1246
 
    FILE * f = KDE_fopen( _filename, "rb" );
1247
 
    if ( f == 0L ) {
1248
 
        unlink( _filename );
1249
 
        result = i18n("Could not read %1", QFile::decodeName(_filename));
1250
 
        return result;
1251
 
    }
1252
 
 
1253
 
    result.clear();
1254
 
    const char *p = "";
1255
 
    while ( p != 0L ) {
1256
 
        p = fgets( buffer, sizeof(buffer)-1, f );
1257
 
        if ( p != 0L )
1258
 
            result += QString::fromLocal8Bit(buffer);
1259
 
    }
1260
 
 
1261
 
    fclose( f );
1262
 
 
1263
 
    unlink( _filename );
1264
 
 
1265
 
    return result;
1266
 
}
1267
 
 
1268
 
/*************************************
1269
 
 *
1270
 
 * ACL handling helpers
1271
 
 *
1272
 
 *************************************/
1273
 
#ifdef HAVE_POSIX_ACL
1274
 
 
1275
 
static bool isExtendedACL( acl_t acl )
1276
 
{
1277
 
    return ( acl_equiv_mode( acl, 0 ) != 0 );
1278
 
}
1279
 
 
1280
 
static void appendACLAtoms( const QByteArray & path, UDSEntry& entry, mode_t type, bool withACL )
1281
 
{
1282
 
    // first check for a noop
1283
 
    if ( acl_extended_file( path.data() ) == 0 ) return;
1284
 
 
1285
 
    acl_t acl = 0;
1286
 
    acl_t defaultAcl = 0;
1287
 
    bool isDir = S_ISDIR( type );
1288
 
    // do we have an acl for the file, and/or a default acl for the dir, if it is one?
1289
 
    acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
1290
 
    /* Sadly libacl does not provided a means of checking for extended ACL and default
1291
 
     * ACL separately. Since a directory can have both, we need to check again. */
1292
 
    if ( isDir ) {
1293
 
        if ( acl ) {
1294
 
            if ( !isExtendedACL( acl ) ) {
1295
 
                acl_free( acl );
1296
 
                acl = 0;
1297
 
            }
1298
 
        }
1299
 
        defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
1300
 
    }
1301
 
    if ( acl || defaultAcl ) {
1302
 
      kDebug(7101) << path.constData() << "has extended ACL entries";
1303
 
      entry.insert( KIO::UDSEntry::UDS_EXTENDED_ACL, 1 );
1304
 
    }
1305
 
    if ( withACL ) {
1306
 
        if ( acl ) {
1307
 
            const QString str = aclToText(acl);
1308
 
            entry.insert( KIO::UDSEntry::UDS_ACL_STRING, str );
1309
 
            kDebug(7101) << path.constData() << "ACL:" << str;
1310
 
        }
1311
 
        if ( defaultAcl ) {
1312
 
            const QString str = aclToText(defaultAcl);
1313
 
            entry.insert( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, str );
1314
 
            kDebug(7101) << path.constData() << "DEFAULT ACL:" << str;
1315
 
        }
1316
 
    }
1317
 
    if ( acl ) acl_free( acl );
1318
 
    if ( defaultAcl ) acl_free( defaultAcl );
1319
 
}
1320
 
#endif
1321
 
 
1322
 
// We could port this to KTempDir::removeDir but then we wouldn't be able to tell the user
1323
 
// where exactly the deletion failed, in case of errors.
1324
 
bool FileProtocol::deleteRecursive(const QString& path)
1325
 
{
1326
 
    //kDebug() << path;
1327
 
    QDirIterator it(path, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden,
1328
 
                    QDirIterator::Subdirectories);
1329
 
    QStringList dirsToDelete;
1330
 
    while ( it.hasNext() ) {
1331
 
        const QString itemPath = it.next();
1332
 
        //kDebug() << "itemPath=" << itemPath;
1333
 
        const QFileInfo info = it.fileInfo();
1334
 
        if (info.isDir() && !info.isSymLink())
1335
 
            dirsToDelete.prepend(itemPath);
1336
 
        else {
1337
 
            //kDebug() << "QFile::remove" << itemPath;
1338
 
            if (!QFile::remove(itemPath)) {
1339
 
                error(KIO::ERR_CANNOT_DELETE, itemPath);
1340
 
                return false;
1341
 
            }
1342
 
        }
1343
 
    }
1344
 
    QDir dir;
1345
 
    Q_FOREACH(const QString& itemPath, dirsToDelete) {
1346
 
        //kDebug() << "QDir::rmdir" << itemPath;
1347
 
        if (!dir.rmdir(itemPath)) {
1348
 
            error(KIO::ERR_CANNOT_DELETE, itemPath);
1349
 
            return false;
1350
 
        }
1351
 
    }
1352
 
    return true;
1353
 
}
1354
 
 
1355
 
#include "file.moc"