1 /*****************************************************************************
2 * Copyright (C) 2003 Rafi Yanai <krusader@users.sf.net> *
3 * Copyright (C) 2003 Shie Erlich <krusader@users.sf.net> *
4 * Copyright (C) 2004-2019 Krusader Krew [https://krusader.org] *
5 * *
6 * This file is part of Krusader [https://krusader.org]. *
7 * *
8 * Krusader is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * Krusader is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with Krusader. If not, see [http://www.gnu.org/licenses/]. *
20 *****************************************************************************/
21
22 #include "krarc.h"
23 #include "../krusader/defaults.h"
24
25 // QtCore
26 #include <QByteArray>
27 #include <QDebug>
28 #include <QDir>
29 #include <QFile>
30 #include <QFileInfo>
31 #include <QMimeDatabase>
32 #include <QMimeType>
33 #include <QRegExp>
34 #include <QTemporaryFile>
35 #include <QTextCodec>
36 #include <qplatformdefs.h>
37
38 #include <KArchive/KTar>
39 #include <KCoreAddons/KProcess>
40 #include <KI18n/KLocalizedString>
41 #include <KIO/Job>
42 #include <KIOCore/KFileItem>
43
44 #include <kio_version.h>
45
46 #include <errno.h>
47 #include "../krusader/compat.h"
48
49 #define MAX_IPC_SIZE (1024*32)
50 #define TRIES_WITH_PASSWORDS 3
51
52 using namespace KIO;
53 extern "C"
54 {
55
56 #ifdef KRARC_ENABLED
57 /* This codec is for being able to handle files which encoding differs from the current locale.
58 *
59 * Unfortunately QProcess requires QString parameters for arguments which are encoded to Local8Bit
60 * If we want to use unzip with ISO-8852-2 when the current locale is UTF-8, it will cause problems.
61 *
62 * Workaround:
63 * 1. encode the QString to QByteArray ( according to the selected remote encoding, ISO-8852-2 )
64 * 2. encode QByteArray to QString again
65 * unicode 0xE000-0xF7FF is for private use
66 * the byte array is mapped to 0xE000-0xE0FF unicodes
67 * 3. KrArcCodec maps 0xE000-0xE0FF to 0x0000-0x00FF, while calls the default encoding routine
68 * for other unicodes.
69 */
70
71 class KrArcCodec : public QTextCodec
72 {
73 public:
KrArcCodec(QTextCodec * codec)74 KrArcCodec(QTextCodec * codec) : originalCodec(codec) {}
~KrArcCodec()75 virtual ~KrArcCodec() {}
76
name() const77 virtual QByteArray name() const Q_DECL_OVERRIDE {
78 return originalCodec->name();
79 }
aliases() const80 virtual QList<QByteArray> aliases() const Q_DECL_OVERRIDE {
81 return originalCodec->aliases();
82 }
mibEnum() const83 virtual int mibEnum() const Q_DECL_OVERRIDE {
84 return originalCodec->mibEnum();
85 }
86
87 protected:
convertToUnicode(const char * in,int length,ConverterState * state) const88 virtual QString convertToUnicode(const char *in, int length, ConverterState *state) const Q_DECL_OVERRIDE {
89 return originalCodec->toUnicode(in, length, state);
90 }
convertFromUnicode(const QChar * in,int length,ConverterState * state) const91 virtual QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const Q_DECL_OVERRIDE {
92 // the QByteArray is embedded into the unicode charset (QProcess hell)
93 QByteArray result;
94 for (int i = 0; i != length; i++) {
95 if (((in[ i ].unicode()) & 0xFF00) == 0xE000) // map 0xE000-0xE0FF to 0x0000-0x00FF
96 result.append((char)(in[ i ].unicode() & 0xFF));
97 else
98 result.append(originalCodec->fromUnicode(in + i, 1, state));
99 }
100 return result;
101 }
102
103 private:
104 QTextCodec * originalCodec;
105 } *krArcCodec;
106
107 #define SET_KRCODEC QTextCodec *origCodec = QTextCodec::codecForLocale(); \
108 QTextCodec::setCodecForLocale( krArcCodec );
109 #define RESET_KRCODEC QTextCodec::setCodecForLocale( origCodec );
110
111 #endif // KRARC_ENABLED
112
113 class DummySlave : public KIO::SlaveBase
114 {
115 public:
DummySlave(const QByteArray & pool_socket,const QByteArray & app_socket)116 DummySlave(const QByteArray &pool_socket, const QByteArray &app_socket) :
117 SlaveBase("kio_krarc", pool_socket, app_socket) {
118 error((int)ERR_SLAVE_DEFINED, QString("krarc is disabled."));
119 }
120 };
121
kdemain(int argc,char ** argv)122 int Q_DECL_EXPORT kdemain(int argc, char **argv) {
123 if (argc != 4) {
124 qWarning() << "Usage: kio_krarc protocol domain-socket1 domain-socket2" << endl;
125 exit(-1);
126 }
127
128 #ifdef KRARC_ENABLED
129 kio_krarcProtocol slave(argv[2], argv[3]);
130 #else
131 DummySlave slave(argv[2], argv[3]);
132 #endif
133
134 slave.dispatchLoop();
135
136 return 0;
137 }
138
139 } // extern "C"
140
141 #ifdef KRARC_ENABLED
kio_krarcProtocol(const QByteArray & pool_socket,const QByteArray & app_socket)142 kio_krarcProtocol::kio_krarcProtocol(const QByteArray &pool_socket, const QByteArray &app_socket)
143 : SlaveBase("kio_krarc", pool_socket, app_socket), archiveChanged(true), arcFile(0L), extArcReady(false),
144 password(QString()), krConf("krusaderrc"), codec(0)
145 {
146 KRFUNC;
147 confGrp = KConfigGroup(&krConf, "Dependencies");
148
149 KConfigGroup group(&krConf, "General");
150 QString tmpDirPath = group.readEntry("Temp Directory", _TempDirectory);
151 QDir tmpDir(tmpDirPath);
152 if(!tmpDir.exists()) {
153 for (int i = 1 ; i != -1 ; i = tmpDirPath.indexOf('/', i + 1))
154 QDir().mkdir(tmpDirPath.left(i));
155 QDir().mkdir(tmpDirPath);
156 }
157
158 arcTempDir = tmpDirPath + DIR_SEPARATOR;
159 QString dirName = "krArc" + QDateTime::currentDateTime().toString(Qt::ISODate);
160 dirName.replace(QRegExp(":"), "_");
161 tmpDir.mkdir(dirName);
162 arcTempDir = arcTempDir + dirName + DIR_SEPARATOR;
163
164 krArcCodec = new KrArcCodec(QTextCodec::codecForLocale());
165 }
166
167 /* ---------------------------------------------------------------------------------- */
~kio_krarcProtocol()168 kio_krarcProtocol::~kio_krarcProtocol()
169 {
170 KRFUNC;
171 // delete the temp directory
172 KProcess proc;
173 proc << fullPathName("rm") << "-rf" << arcTempDir;
174 proc.start();
175 proc.waitForFinished();
176 }
177
178 /* ---------------------------------------------------------------------------------- */
179
checkWriteSupport()180 bool kio_krarcProtocol::checkWriteSupport()
181 {
182 KRFUNC;
183 krConf.reparseConfiguration();
184 if (KConfigGroup(&krConf, "kio_krarc").readEntry("EnableWrite", false))
185 return true;
186 else {
187 error(ERR_UNSUPPORTED_ACTION,
188 i18n("krarc: write support is disabled.\n"
189 "You can enable it on the 'Archives' page in Konfigurator."));
190 return false;
191 }
192 }
193
receivedData(KProcess *,QByteArray & d)194 void kio_krarcProtocol::receivedData(KProcess *, QByteArray &d)
195 {
196 KRFUNC;
197 QByteArray buf(d);
198 data(buf);
199 processedSize(d.length());
200 decompressedLen += d.length();
201 }
202
mkdir(const QUrl & url,int permissions)203 void kio_krarcProtocol::mkdir(const QUrl &url, int permissions)
204 {
205 KRFUNC;
206 const QString path = getPath(url);
207 KRDEBUG(path);
208
209 if (!checkWriteSupport())
210 return;
211
212 // In case of KIO::mkpath call there is a mkdir call for every path element.
213 // Therefore the path all the way up to our archive needs to be checked for existence
214 // and reported as success.
215 if (QDir().exists(path)) {
216 finished();
217 return;
218 }
219
220 if (!setArcFile(url)) {
221 error(ERR_CANNOT_ENTER_DIRECTORY, path);
222 return;
223 }
224
225 if (newArchiveURL && !initDirDict(url)) {
226 error(ERR_CANNOT_ENTER_DIRECTORY, path);
227 return;
228 }
229
230 if (putCmd.isEmpty()) {
231 error(ERR_UNSUPPORTED_ACTION,
232 i18n("Creating directories is not supported with %1 archives", arcType));
233 return;
234 }
235
236 const QString arcFilePath = getPath(arcFile->url());
237
238 if (arcType == "arj" || arcType == "lha") {
239 QString arcDir = path.mid(arcFilePath.length());
240 if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR;
241
242 if (dirDict.find(arcDir) == dirDict.end())
243 addNewDir(arcDir);
244 finished();
245 return;
246 }
247
248 QString arcDir = findArcDirectory(url);
249 QString tempDir = arcDir.mid(1) + path.mid(path.lastIndexOf(DIR_SEPARATOR) + 1);
250 if (tempDir.right(1) != DIR_SEPARATOR) tempDir = tempDir + DIR_SEPARATOR;
251
252 if (permissions == -1) permissions = 0777; //set default permissions
253
254 QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit();
255 for (int i = 0;i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) {
256 QByteArray newDirs = encodeString(tempDir.left(i));
257 newDirs.prepend(arcTempDirEnc);
258 QT_MKDIR(newDirs, permissions);
259 }
260
261 if (tempDir.endsWith(DIR_SEPARATOR))
262 tempDir.truncate(tempDir.length() - 1);
263
264 // pack the directory
265 KrLinecountingProcess proc;
266 proc << putCmd << arcFilePath << localeEncodedString(tempDir);
267 infoMessage(i18n("Creating %1...", url.fileName()));
268 QDir::setCurrent(arcTempDir);
269
270 SET_KRCODEC
271 proc.start();
272 RESET_KRCODEC
273
274 proc.waitForFinished();
275
276 // delete the temp directory
277 QDir().rmdir(arcTempDir);
278
279 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) {
280 error(ERR_COULD_NOT_WRITE, path + "\n\n" + proc.getErrorMsg());
281 return;
282 }
283
284 // force a refresh of archive information
285 initDirDict(url, true);
286 finished();
287 }
288
put(const QUrl & url,int permissions,KIO::JobFlags flags)289 void kio_krarcProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags)
290 {
291 KRFUNC;
292 KRDEBUG(getPath(url));
293
294 if (!checkWriteSupport())
295 return;
296
297 bool overwrite = !!(flags & KIO::Overwrite);
298 bool resume = !!(flags & KIO::Resume);
299
300 if (!setArcFile(url)) {
301 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
302 return;
303 }
304 if (newArchiveURL && !initDirDict(url)) {
305 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
306 return;
307 }
308
309 if (putCmd.isEmpty()) {
310 error(ERR_UNSUPPORTED_ACTION,
311 i18n("Writing to %1 archives is not supported", arcType));
312 return;
313 }
314 if (!overwrite && findFileEntry(url)) {
315 error(ERR_FILE_ALREADY_EXIST, getPath(url));
316 return;
317 }
318
319 QString arcDir = findArcDirectory(url);
320 if (arcDir.isEmpty())
321 KRDEBUG("arcDir is empty.");
322
323 QString tempFile = arcDir.mid(1) + getPath(url).mid(getPath(url).lastIndexOf(DIR_SEPARATOR) + 1);
324 QString tempDir = arcDir.mid(1);
325 if (tempDir.right(1) != DIR_SEPARATOR) tempDir = tempDir + DIR_SEPARATOR;
326
327 if (permissions == -1) permissions = 0777; //set default permissions
328
329 QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit();
330 for (int i = 0;i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) {
331 QByteArray newDirs = encodeString(tempDir.left(i));
332 newDirs.prepend(arcTempDirEnc);
333 QT_MKDIR(newDirs, 0755);
334 }
335
336 int fd;
337 if (resume) {
338 QByteArray ba = encodeString(tempFile);
339 ba.prepend(arcTempDirEnc);
340 fd = QT_OPEN(ba, O_RDWR); // append if resuming
341 QT_LSEEK(fd, 0, SEEK_END); // Seek to end
342 } else {
343 // WABA: Make sure that we keep writing permissions ourselves,
344 // otherwise we can be in for a surprise on NFS.
345 mode_t initialMode;
346 if (permissions != -1)
347 initialMode = permissions | S_IWUSR | S_IRUSR;
348 else
349 initialMode = 0666;
350
351 QByteArray ba = encodeString(tempFile);
352 ba.prepend(arcTempDirEnc);
353 fd = QT_OPEN(ba, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
354 }
355
356 QByteArray buffer;
357 int readResult;
358 bool isIncomplete = false;
359 do {
360 dataReq();
361 readResult = readData(buffer);
362 auto bytesWritten = ::write(fd, buffer.data(), buffer.size());
363 if (bytesWritten < buffer.size()) {
364 isIncomplete = true;
365 break;
366 }
367 } while (readResult > 0);
368 ::close(fd);
369
370 if (isIncomplete) {
371 error(ERR_COULD_NOT_WRITE, getPath(url));
372 return;
373 }
374
375 // pack the file
376 KrLinecountingProcess proc;
377 proc << putCmd << getPath(arcFile->url()) << localeEncodedString(tempFile);
378 infoMessage(i18n("Packing %1...", url.fileName()));
379 QDir::setCurrent(arcTempDir);
380
381 SET_KRCODEC
382 proc.start();
383 RESET_KRCODEC
384
385 proc.waitForFinished();
386
387 // remove the files
388 QDir().rmdir(arcTempDir);
389
390 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) {
391 error(ERR_COULD_NOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg());
392 return;
393 }
394 // force a refresh of archive information
395 initDirDict(url, true);
396 finished();
397 }
398
get(const QUrl & url)399 void kio_krarcProtocol::get(const QUrl &url)
400 {
401 KRFUNC;
402 get(url, TRIES_WITH_PASSWORDS);
403 }
404
get(const QUrl & url,int tries)405 void kio_krarcProtocol::get(const QUrl &url, int tries)
406 {
407 KRFUNC;
408 KRDEBUG(getPath(url));
409 bool decompressToFile = false;
410
411 if (!setArcFile(url)) {
412 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
413 return;
414 }
415 if (newArchiveURL && !initDirDict(url)) {
416 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
417 return;
418 }
419
420 if (getCmd.isEmpty()) {
421 error(ERR_UNSUPPORTED_ACTION,
422 i18n("Retrieving data from %1 archives is not supported", arcType));
423 return;
424 }
425 UDSEntry* entry = findFileEntry(url);
426 if (!entry) {
427 error(KIO::ERR_DOES_NOT_EXIST, getPath(url));
428 return;
429 }
430 if (KFileItem(*entry, url).isDir()) {
431 error(KIO::ERR_IS_DIRECTORY, getPath(url));
432 return;
433 }
434 KIO::filesize_t expectedSize = KFileItem(*entry, url).size();
435 // for RPM files extract the cpio file first
436 if (!extArcReady && arcType == "rpm") {
437 KrLinecountingProcess cpio;
438 cpio << "rpm2cpio" << getPath(arcFile->url(), QUrl::StripTrailingSlash);
439 cpio.setStandardOutputFile(arcTempDir + "contents.cpio");
440
441 cpio.start();
442 cpio.waitForFinished();
443
444 if (cpio.exitStatus() != QProcess::NormalExit || !checkStatus(cpio.exitCode())) {
445 error(ERR_COULD_NOT_READ, getPath(url) + "\n\n" + cpio.getErrorMsg());
446 return;
447 }
448 extArcReady = true;
449 }
450 // for DEB files extract the tar file first
451 if (!extArcReady && arcType == "deb") {
452 KrLinecountingProcess dpkg;
453 dpkg << cmd << "--fsys-tarfile" << getPath(arcFile->url(), QUrl::StripTrailingSlash);
454 dpkg.setStandardOutputFile(arcTempDir + "contents.cpio");
455
456 dpkg.start();
457 dpkg.waitForFinished();
458
459 if (dpkg.exitStatus() != QProcess::NormalExit || !checkStatus(dpkg.exitCode())) {
460 error(ERR_COULD_NOT_READ, getPath(url) + "\n\n" + dpkg.getErrorMsg());
461 return;
462 }
463 extArcReady = true;
464 }
465
466 // Use the external unpacker to unpack the file
467 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1);
468 KrLinecountingProcess proc;
469 if (extArcReady) {
470 proc << getCmd << arcTempDir + "contents.cpio" << '*' + localeEncodedString(file);
471 } else if (arcType == "arj" || arcType == "ace" || arcType == "7z") {
472 proc << getCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << localeEncodedString(file);
473 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!!
474 proc.setStandardInputFile("/dev/ptmx");
475 file = url.fileName();
476 decompressToFile = true;
477 } else {
478 decompressedLen = 0;
479 // Determine the mimetype of the file to be retrieved, and emit it.
480 // This is mandatory in all slaves (for KRun/BrowserRun to work).
481 QMimeDatabase db;
482 QMimeType mt = db.mimeTypeForFile(arcTempDir + file);
483 if (mt.isValid())
484 emit mimeType(mt.name());
485
486 QString escapedFilename = file;
487 if(arcType == "zip") // left bracket needs to be escaped
488 escapedFilename.replace('[', "[[]");
489 proc << getCmd << getPath(arcFile->url());
490 if (arcType != "gzip" && arcType != "bzip2" && arcType != "lzma" && arcType != "xz") proc << localeEncodedString(escapedFilename);
491 connect(&proc, SIGNAL(newOutputData(KProcess *, QByteArray &)),
492 this, SLOT(receivedData(KProcess *, QByteArray &)));
493 proc.setMerge(false);
494 }
495 infoMessage(i18n("Unpacking %1...", url.fileName()));
496 // change the working directory to our arcTempDir
497 QDir::setCurrent(arcTempDir);
498
499 SET_KRCODEC
500 proc.setTextModeEnabled(false);
501 proc.start();
502 RESET_KRCODEC
503
504 proc.waitForFinished();
505
506 if (!extArcReady && !decompressToFile) {
507 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) || (arcType != "bzip2" && arcType != "lzma" && arcType != "xz" && expectedSize != decompressedLen)) {
508 if (encrypted && tries) {
509 invalidatePassword();
510 get(url, tries - 1);
511 return;
512 }
513 error(KIO::ERR_ACCESS_DENIED, getPath(url) + "\n\n" + proc.getErrorMsg());
514 return;
515 }
516 } else {
517 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) || !QFileInfo(arcTempDir + file).exists()) {
518 if (decompressToFile)
519 QFile(arcTempDir + file).remove();
520 if (encrypted && tries) {
521 invalidatePassword();
522 get(url, tries - 1);
523 return;
524 }
525 error(KIO::ERR_ACCESS_DENIED, getPath(url));
526 return;
527 }
528 // the following block is ripped from KDE file KIO::Slave
529 // $Id: krarc.cpp,v 1.43 2007/01/13 13:39:51 ckarai Exp $
530 QByteArray _path(QFile::encodeName(arcTempDir + file));
531 QT_STATBUF buff;
532 if (QT_LSTAT(_path.data(), &buff) == -1) {
533 if (errno == EACCES)
534 error(KIO::ERR_ACCESS_DENIED, getPath(url));
535 else
536 error(KIO::ERR_DOES_NOT_EXIST, getPath(url));
537 return;
538 }
539 if (S_ISDIR(buff.st_mode)) {
540 error(KIO::ERR_IS_DIRECTORY, getPath(url));
541 return;
542 }
543 if (!S_ISREG(buff.st_mode)) {
544 error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url));
545 return;
546 }
547 int fd = QT_OPEN(_path.data(), O_RDONLY);
548 if (fd < 0) {
549 error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url));
550 return;
551 }
552 // Determine the mimetype of the file to be retrieved, and emit it.
553 // This is mandatory in all slaves (for KRun/BrowserRun to work).
554 QMimeDatabase db;
555 QMimeType mt = db.mimeTypeForFile(arcTempDir + file);
556 if (mt.isValid())
557 emit mimeType(mt.name());
558
559 KIO::filesize_t processed_size = 0;
560
561 QString resumeOffset = metaData("resume");
562 if (!resumeOffset.isEmpty()) {
563 bool ok;
564 KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
565 if (ok && (offset > 0) && (offset < buff.st_size)) {
566 if (QT_LSEEK(fd, offset, SEEK_SET) == offset) {
567 canResume();
568 processed_size = offset;
569 }
570 }
571 }
572
573 totalSize(buff.st_size);
574
575 char buffer[ MAX_IPC_SIZE ];
576 while (1) {
577 int n = ::read(fd, buffer, MAX_IPC_SIZE);
578 if (n == -1) {
579 if (errno == EINTR)
580 continue;
581 error(KIO::ERR_COULD_NOT_READ, getPath(url));
582 ::close(fd);
583 return;
584 }
585 if (n == 0)
586 break; // Finished
587
588 {
589 QByteArray array = QByteArray::fromRawData(buffer, n);
590 data(array);
591 }
592
593 processed_size += n;
594 }
595
596 data(QByteArray());
597 ::close(fd);
598 processedSize(buff.st_size);
599 finished();
600
601 if (decompressToFile)
602 QFile(arcTempDir + file).remove();
603 return;
604 }
605 // send empty buffer to mark EOF
606 data(QByteArray());
607 finished();
608 }
609
del(QUrl const & url,bool isFile)610 void kio_krarcProtocol::del(QUrl const & url, bool isFile)
611 {
612 KRFUNC;
613 KRDEBUG(getPath(url));
614
615 if (!checkWriteSupport())
616 return;
617
618 if (!setArcFile(url)) {
619 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
620 return;
621 }
622 if (newArchiveURL && !initDirDict(url)) {
623 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
624 return;
625 }
626
627 if (delCmd.isEmpty()) {
628 error(ERR_UNSUPPORTED_ACTION,
629 i18n("Deleting files from %1 archives is not supported", arcType));
630 return;
631 }
632 if (!findFileEntry(url)) {
633 if ((arcType != "arj" && arcType != "lha") || isFile) {
634 error(KIO::ERR_DOES_NOT_EXIST, getPath(url));
635 return;
636 }
637 }
638
639 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1);
640 if (!isFile && file.right(1) != DIR_SEPARATOR) {
641 if (arcType == "zip") file = file + DIR_SEPARATOR;
642 }
643 KrLinecountingProcess proc;
644 proc << delCmd << getPath(arcFile->url()) << localeEncodedString(file);
645 infoMessage(i18n("Deleting %1...", url.fileName()));
646
647 SET_KRCODEC
648 proc.start();
649 RESET_KRCODEC
650
651 proc.waitForFinished();
652 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) {
653 error(ERR_COULD_NOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg());
654 return;
655 }
656 // force a refresh of archive information
657 initDirDict(url, true);
658 finished();
659 }
660
stat(const QUrl & url)661 void kio_krarcProtocol::stat(const QUrl &url)
662 {
663 KRFUNC;
664 KRDEBUG(getPath(url));
665 if (!setArcFile(url)) {
666 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
667 return;
668 }
669 if (newArchiveURL && !initDirDict(url)) {
670 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
671 return;
672 }
673
674 if (listCmd.isEmpty()) {
675 error(ERR_UNSUPPORTED_ACTION,
676 i18n("Accessing files is not supported with %1 archives", arcType));
677 return;
678 }
679 QString path = getPath(url, QUrl::StripTrailingSlash);
680 QUrl newUrl = url;
681
682 // but treat the archive itself as the archive root
683 if (path == getPath(arcFile->url(), QUrl::StripTrailingSlash)) {
684 newUrl.setPath(path + DIR_SEPARATOR);
685 path = getPath(newUrl);
686 }
687 // we might be stating a real file
688 if (QFileInfo(path).exists()) {
689 QT_STATBUF buff;
690 QT_STAT(path.toLocal8Bit(), &buff);
691 QString mime;
692 QMimeDatabase db;
693 QMimeType result = db.mimeTypeForFile(path);
694 if (result.isValid())
695 mime = result.name();
696 statEntry(KFileItem(QUrl::fromLocalFile(path), mime, buff.st_mode).entry());
697 finished();
698 return;
699 }
700 UDSEntry* entry = findFileEntry(newUrl);
701 if (entry) {
702 statEntry(*entry);
703 finished();
704 } else error(KIO::ERR_DOES_NOT_EXIST, path);
705 }
706
copy(const QUrl & url,const QUrl & dest,int,KIO::JobFlags flags)707 void kio_krarcProtocol::copy(const QUrl &url, const QUrl &dest, int, KIO::JobFlags flags)
708 {
709 KRDEBUG("source: " << url.path() << " dest: " << dest.path());
710
711 if (!checkWriteSupport())
712 return;
713
714 bool overwrite = !!(flags & KIO::Overwrite);
715
716 // KDE HACK: opening the password dlg in copy causes error for the COPY, and further problems
717 // that's why encrypted files are not allowed to copy
718 if (!encrypted && dest.isLocalFile())
719 do {
720 if (url.fileName() != dest.fileName())
721 break;
722
723 if (QTextCodec::codecForLocale()->name() != codec->name())
724 break;
725
726 //the file exists and we don't want to overwrite
727 if ((!overwrite) && (QFile(getPath(dest)).exists())) {
728 error((int)ERR_FILE_ALREADY_EXIST, QString(QFile::encodeName(getPath(dest))));
729 return;
730 };
731
732 if (!setArcFile(url)) {
733 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
734 return;
735 }
736 if (newArchiveURL && !initDirDict(url)) {
737 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
738 return;
739 }
740
741 UDSEntry* entry = findFileEntry(url);
742 if (copyCmd.isEmpty() || !entry)
743 break;
744
745 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1);
746
747 QString destDir = getPath(dest, QUrl::StripTrailingSlash);
748 if (!QDir(destDir).exists()) {
749 int ndx = destDir.lastIndexOf(DIR_SEPARATOR_CHAR);
750 if (ndx != -1)
751 destDir.truncate(ndx + 1);
752 }
753
754 QDir::setCurrent(destDir);
755
756 QString escapedFilename = file;
757 if(arcType == "zip") {
758 // left bracket needs to be escaped
759 escapedFilename.replace('[', "[[]");
760 }
761
762 KrLinecountingProcess proc;
763 proc << copyCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << escapedFilename;
764 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!!
765 proc.setStandardInputFile("/dev/ptmx");
766 proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect
767
768 infoMessage(i18n("Unpacking %1...", url.fileName()));
769 proc.start();
770 proc.waitForFinished();
771 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) {
772 error(KIO::ERR_COULD_NOT_WRITE, getPath(dest, QUrl::StripTrailingSlash) + "\n\n" + proc.getErrorMsg());
773 return;
774 }
775 if (!QFileInfo(getPath(dest, QUrl::StripTrailingSlash)).exists()) {
776 error(KIO::ERR_COULD_NOT_WRITE, getPath(dest, QUrl::StripTrailingSlash));
777 return;
778 }
779
780 processedSize(KFileItem(*entry, url).size());
781 finished();
782 QDir::setCurrent(QDir::rootPath()); /* for being able to umount devices after copying*/
783 return;
784 } while (0);
785
786 if (encrypted)
787 KRDEBUG("ERROR: " << url.path() << " is encrypted.");
788 if (!dest.isLocalFile())
789 KRDEBUG("ERROR: " << url.path() << " is not a local file.");
790
791 // CMD_COPY is no more in KF5 - replaced with 74 value (as stated in kio/src/core/commands_p.h, which could be found in cgit.kde.org/kio.git/tree)
792 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, 74));
793 }
794
rename(const QUrl & src,const QUrl & dest,KIO::JobFlags flags)795 void kio_krarcProtocol::rename(const QUrl& src, const QUrl& dest, KIO::JobFlags flags)
796 {
797 Q_UNUSED(flags);
798
799 KRDEBUG("renaming from: " << src.path() << " to: " << dest.path());
800 KRDEBUG("command: " << arcPath);
801
802 if (!checkWriteSupport()) {
803 return;
804 }
805
806 if (renCmd.isEmpty()) {
807 error(KIO::ERR_CANNOT_RENAME, src.fileName());
808 return;
809 }
810
811 if (src.fileName() == dest.fileName()) {
812 return;
813 }
814
815 KrLinecountingProcess proc;
816 proc << renCmd << arcPath << src.path().replace(arcPath + '/', "") << dest.path().replace(arcPath + '/', "");
817 proc.start();
818 proc.waitForFinished();
819
820 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) {
821 error(KIO::ERR_CANNOT_RENAME, src.fileName());
822 return;
823 }
824
825 finished();
826 }
827
listDir(const QUrl & url)828 void kio_krarcProtocol::listDir(const QUrl &url)
829 {
830 KRFUNC;
831 KRDEBUG(getPath(url));
832 if (!setArcFile(url)) {
833 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
834 return;
835 }
836 if (listCmd.isEmpty()) {
837 error(ERR_UNSUPPORTED_ACTION,
838 i18n("Listing directories is not supported for %1 archives", arcType));
839 return;
840 }
841 QString path = getPath(url);
842 if (path.right(1) != DIR_SEPARATOR) path = path + DIR_SEPARATOR;
843
844 // it might be a real dir !
845 if (QFileInfo(path).exists()) {
846 if (QFileInfo(path).isDir()) {
847 QUrl redir;
848 redir.setPath(getPath(url));
849 redirection(redir);
850 finished();
851 } else { // maybe it's an archive !
852 error(ERR_IS_FILE, path);
853 }
854 return;
855 }
856 if (!initDirDict(url)) {
857 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
858 return;
859 }
860 QString arcDir = path.mid(getPath(arcFile->url()).length());
861 arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR));
862 if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR;
863
864 if (dirDict.find(arcDir) == dirDict.end()) {
865 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url));
866 return;
867 }
868 UDSEntryList* dirList = dirDict[ arcDir ];
869 totalSize(dirList->size());
870 listEntries(*dirList);
871 finished();
872 }
873
setArcFile(const QUrl & url)874 bool kio_krarcProtocol::setArcFile(const QUrl &url)
875 {
876 KRFUNC;
877 KRDEBUG(url.fileName());
878 QString path = getPath(url);
879 time_t currTime = time(0);
880 archiveChanged = true;
881 newArchiveURL = true;
882 // is the file already set ?
883 if (arcFile && getPath(arcFile->url(), QUrl::StripTrailingSlash) == path.left(getPath(arcFile->url(), QUrl::StripTrailingSlash).length())) {
884 newArchiveURL = false;
885 // Has it changed ?
886 KFileItem* newArcFile = new KFileItem(arcFile->url(), QString(), arcFile->mode());
887 if (metaData("Charset") != currentCharset || !newArcFile->cmp(*arcFile)) {
888 currentCharset = metaData("Charset");
889
890 codec = QTextCodec::codecForName(currentCharset.toLatin1());
891 if (codec == 0)
892 codec = QTextCodec::codecForMib(4 /* latin-1 */);
893
894 delete arcFile;
895 password.clear();
896 extArcReady = false;
897 arcFile = newArcFile;
898 } else { // same old file
899 delete newArcFile;
900 archiveChanged = false;
901 if (encrypted && password.isNull())
902 initArcParameters();
903 }
904 } else { // it's a new file...
905 extArcReady = false;
906
907 // new archive file means new dirDict, too
908 dirDict.clear();
909
910 if (arcFile) {
911 delete arcFile;
912 password.clear();
913 arcFile = 0L;
914 }
915 QString newPath = path;
916 if (newPath.right(1) != DIR_SEPARATOR) newPath = newPath + DIR_SEPARATOR;
917 for (int pos = 0; pos >= 0; pos = newPath.indexOf(DIR_SEPARATOR, pos + 1)) {
918 QFileInfo qfi(newPath.left(pos));
919 if (qfi.exists() && !qfi.isDir()) {
920 QT_STATBUF stat_p;
921 QT_LSTAT(newPath.left(pos).toLocal8Bit(), &stat_p);
922 arcFile = new KFileItem(QUrl::fromLocalFile(newPath.left(pos)), QString(), stat_p.st_mode);
923 break;
924 }
925 }
926 if (!arcFile) {
927 // KRDEBUG("ERROR: " << path << " does not exist.");
928 error(ERR_DOES_NOT_EXIST, path);
929 return false; // file not found
930 }
931 currentCharset = metaData("Charset");
932
933 codec = QTextCodec::codecForName(currentCharset.toLatin1());
934 if (codec == 0)
935 codec = QTextCodec::codecForMib(4 /* latin-1 */);
936 }
937
938 /* FIX: file change can only be detected if the timestamp between the two consequent
939 changes is more than 1s. If the archive is continuously changing (check: move files
940 inside the archive), krarc may erronously think, that the archive file is unchanged,
941 because the timestamp is the same as the previous one. This situation can only occur
942 if the modification time equals with the current time. While this condition is true,
943 we can say, that the archive is changing, so content reread is always necessary
944 during that period. */
945 if (archiveChanging)
946 archiveChanged = true;
947 archiveChanging = (currTime == (time_t)arcFile->time(KFileItem::ModificationTime).toTime_t());
948
949 arcPath = getPath(arcFile->url(), QUrl::StripTrailingSlash);
950 arcType = detectArchive(encrypted, arcPath);
951
952 if (arcType == "tbz")
953 arcType = "bzip2";
954 else if (arcType == "tgz")
955 arcType = "gzip";
956 else if (arcType == "tlz")
957 arcType = "lzma";
958 else if (arcType == "txz")
959 arcType = "xz";
960
961 if (arcType.isEmpty()) {
962 arcType = arcFile->mimetype();
963 arcType = getShortTypeFromMime(arcType);
964 if (arcType == "jar")
965 arcType = "zip";
966 }
967
968 return initArcParameters();
969 }
970
initDirDict(const QUrl & url,bool forced)971 bool kio_krarcProtocol::initDirDict(const QUrl &url, bool forced)
972 {
973 KRFUNC;
974 KRDEBUG(getPath(url));
975 // set the archive location
976 //if( !setArcFile(getPath(url)) ) return false;
977 // no need to rescan the archive if it's not changed
978 // KRDEBUG("achiveChanged: " << archiveChanged << " forced: " << forced);
979 if (!archiveChanged && !forced) {
980 // KRDEBUG("doing nothing.");
981 return true;
982 }
983
984 extArcReady = false;
985
986 if (!setArcFile(url))
987 return false; /* if the archive was changed refresh the file information */
988
989 // write the temp file
990 KrLinecountingProcess proc;
991 QTemporaryFile temp;
992
993 // parse the temp file
994 if (!temp.open()) {
995 error(ERR_COULD_NOT_READ, temp.fileName());
996 return false;
997 }
998
999 if (arcType != "bzip2" && arcType != "lzma" && arcType != "xz") {
1000 if (arcType == "rpm") {
1001 proc << listCmd << arcPath;
1002 proc.setStandardOutputFile(temp.fileName());
1003 } else {
1004 proc << listCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash);
1005 proc.setStandardOutputFile(temp.fileName());
1006 }
1007 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!!
1008 proc.setStandardInputFile("/dev/ptmx");
1009
1010 proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect
1011 proc.start();
1012 proc.waitForFinished();
1013 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) return false;
1014 }
1015 // clear the dir dictionary
1016
1017 QHashIterator< QString, KIO::UDSEntryList *> lit(dirDict);
1018 while (lit.hasNext())
1019 delete lit.next().value();
1020 dirDict.clear();
1021
1022 // add the "/" directory
1023 UDSEntryList* root = new UDSEntryList();
1024 dirDict.insert(DIR_SEPARATOR, root);
1025 // and the "/" UDSEntry
1026 UDSEntry entry;
1027 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_NAME, ".");
1028 mode_t mode = parsePermString("drwxr-xr-x");
1029 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only
1030 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only
1031
1032 root->append(entry);
1033
1034 if (arcType == "bzip2" || arcType == "lzma" || arcType == "xz")
1035 abort();
1036
1037 char buf[1000];
1038 QString line;
1039
1040 int lineNo = 0;
1041 bool invalidLine = false;
1042 // the rar list is started with a ------ line.
1043 if (arcType == "rar" || arcType == "arj" || arcType == "lha" || arcType == "7z") {
1044 while (temp.readLine(buf, 1000) != -1) {
1045 line = decodeString(buf);
1046 if (line.startsWith(QLatin1String("----------"))) break;
1047 }
1048 }
1049 while (temp.readLine(buf, 1000) != -1) {
1050 line = decodeString(buf);
1051 if (arcType == "rar") {
1052 // the rar list is ended with a ------ line.
1053 if (line.startsWith(QLatin1String("----------"))) {
1054 invalidLine = !invalidLine;
1055 break;
1056 }
1057 if (invalidLine)
1058 continue;
1059 else {
1060 if (line[0] == '*') // encrypted archives starts with '*'
1061 line[0] = ' ';
1062 }
1063 }
1064 if (arcType == "ace") {
1065 // the ace list begins with a number.
1066 if (!line[0].isDigit()) continue;
1067 }
1068 if (arcType == "arj") {
1069 // the arj list is ended with a ------ line.
1070 if (line.startsWith(QLatin1String("----------"))) {
1071 invalidLine = !invalidLine;
1072 continue;
1073 }
1074 if (invalidLine)
1075 continue;
1076 else {
1077 temp.readLine(buf, 1000);
1078 line = line + decodeString(buf);
1079 temp.readLine(buf, 1000);
1080 line = line + decodeString(buf);
1081 temp.readLine(buf, 1000);
1082 line = line + decodeString(buf);
1083 }
1084 }
1085 if (arcType == "lha" || arcType == "7z") {
1086 // the arj list is ended with a ------ line.
1087 if (line.startsWith(QLatin1String("----------"))) break;
1088 }
1089 parseLine(lineNo++, line.trimmed());
1090 }
1091 // close and delete our file
1092 temp.close();
1093
1094 archiveChanged = false;
1095 // KRDEBUG("done.");
1096 return true;
1097 }
1098
findArcDirectory(const QUrl & url)1099 QString kio_krarcProtocol::findArcDirectory(const QUrl &url)
1100 {
1101 KRFUNC;
1102 KRDEBUG(url.fileName());
1103
1104 QString path = getPath(url);
1105 if (path.right(1) == DIR_SEPARATOR) path.truncate(path.length() - 1);
1106
1107 if (!initDirDict(url)) {
1108 return QString();
1109 }
1110 QString arcDir = path.mid(getPath(arcFile->url()).length());
1111 arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR));
1112 if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR;
1113
1114 return arcDir;
1115 }
1116
findFileEntry(const QUrl & url)1117 UDSEntry* kio_krarcProtocol::findFileEntry(const QUrl &url)
1118 {
1119 KRFUNC;
1120 QString arcDir = findArcDirectory(url);
1121 if (arcDir.isEmpty()) return 0;
1122
1123 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(arcDir);
1124 if (itef == dirDict.end())
1125 return 0;
1126 UDSEntryList* dirList = itef.value();
1127
1128 QString name = getPath(url);
1129 if (getPath(arcFile->url(), QUrl::StripTrailingSlash) == getPath(url, QUrl::StripTrailingSlash)) name = '.'; // the '/' case
1130 else {
1131 if (name.right(1) == DIR_SEPARATOR) name.truncate(name.length() - 1);
1132 name = name.mid(name.lastIndexOf(DIR_SEPARATOR) + 1);
1133 }
1134
1135 UDSEntryList::iterator entry;
1136
1137 for (entry = dirList->begin(); entry != dirList->end(); ++entry) {
1138 if ((entry->contains(KIO::UDSEntry::UDS_NAME)) &&
1139 (entry->stringValue(KIO::UDSEntry::UDS_NAME) == name))
1140 return &(*entry);
1141 }
1142 return 0;
1143 }
1144
nextWord(QString & s,char d)1145 QString kio_krarcProtocol::nextWord(QString &s, char d)
1146 {
1147 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1148 s = s.trimmed();
1149 int j = s.indexOf(d, 0);
1150 QString temp = s.left(j); // find the leftmost word.
1151 s.remove(0, j);
1152 return temp;
1153 }
1154
parsePermString(QString perm)1155 mode_t kio_krarcProtocol::parsePermString(QString perm)
1156 {
1157 KRFUNC;
1158 mode_t mode = 0;
1159 // file type
1160 if (perm[0] == 'd') mode |= S_IFDIR;
1161 #ifndef Q_WS_WIN
1162 if (perm[0] == 'l') mode |= S_IFLNK;
1163 #endif
1164 if (perm[0] == '-') mode |= S_IFREG;
1165 // owner permissions
1166 if (perm[1] != '-') mode |= S_IRUSR;
1167 if (perm[2] != '-') mode |= S_IWUSR;
1168 if (perm[3] != '-') mode |= S_IXUSR;
1169 #ifndef Q_WS_WIN
1170 // group permissions
1171 if (perm[4] != '-') mode |= S_IRGRP;
1172 if (perm[5] != '-') mode |= S_IWGRP;
1173 if (perm[6] != '-') mode |= S_IXGRP;
1174 // other permissions
1175 if (perm[7] != '-') mode |= S_IROTH;
1176 if (perm[8] != '-') mode |= S_IWOTH;
1177 if (perm[9] != '-') mode |= S_IXOTH;
1178 #endif
1179 return mode;
1180 }
1181
addNewDir(QString path)1182 UDSEntryList* kio_krarcProtocol::addNewDir(QString path)
1183 {
1184 KRFUNC;
1185 UDSEntryList* dir;
1186
1187 // check if the current dir exists
1188 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(path);
1189 if (itef != dirDict.end())
1190 return itef.value();
1191
1192 // set dir to the parent dir
1193 dir = addNewDir(path.left(path.lastIndexOf(DIR_SEPARATOR, -2) + 1));
1194
1195 // add a new entry in the parent dir
1196 QString name = path.mid(path.lastIndexOf(DIR_SEPARATOR, -2) + 1);
1197 name = name.left(name.length() - 1);
1198
1199 if (name == "." || name == "..") { // entries with these names wouldn't be displayed
1200 // don't translate since this is an internal error
1201 QString err = QString("Cannot handle path: ") + path;
1202 // KRDEBUG("ERROR: " << err);
1203 error(KIO::ERR_INTERNAL, err);
1204 exit();
1205 }
1206
1207 UDSEntry entry;
1208 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_NAME, name);
1209 mode_t mode = parsePermString("drwxr-xr-x");
1210 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only
1211 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only
1212 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_SIZE, 0);
1213 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_MODIFICATION_TIME, arcFile->time(KFileItem::ModificationTime).toTime_t());
1214
1215 dir->append(entry);
1216
1217 // create a new directory entry and add it..
1218 dir = new UDSEntryList();
1219 dirDict.insert(path, dir);
1220
1221 return dir;
1222 }
1223
parseLine(int lineNo,QString line)1224 void kio_krarcProtocol::parseLine(int lineNo, QString line)
1225 {
1226 KRFUNC;
1227 UDSEntryList* dir;
1228 UDSEntry entry;
1229
1230 QString owner;
1231 QString group;
1232 QString symlinkDest;
1233 QString perm;
1234 mode_t mode = 0666;
1235 size_t size = 0;
1236 time_t time = ::time(0);
1237 QString fullName;
1238
1239 if (arcType == "zip") {
1240 // permissions
1241 perm = nextWord(line);
1242 // ignore the next 2 fields
1243 nextWord(line); nextWord(line);
1244 // size
1245 size = nextWord(line).toLong();
1246 // ignore the next 2 fields
1247 nextWord(line);nextWord(line);
1248 // date & time
1249 QString d = nextWord(line);
1250 QDate qdate(d.mid(0, 4).toInt(), d.mid(4, 2).toInt(), d.mid(6, 2).toInt());
1251 QTime qtime(d.mid(9, 2).toInt(), d.mid(11, 2).toInt(), d.mid(13, 2).toInt());
1252 time = QDateTime(qdate, qtime).toTime_t();
1253 // full name
1254 fullName = nextWord(line, '\n');
1255
1256 if (perm.length() != 10)
1257 perm = (perm.at(0) == 'd' || fullName.endsWith(DIR_SEPARATOR)) ? "drwxr-xr-x" : "-rw-r--r--" ;
1258 mode = parsePermString(perm);
1259 }
1260 if (arcType == "rar") {
1261 // permissions
1262 perm = nextWord(line);
1263 // size
1264 size = nextWord(line).toLong();
1265 // ignore the next 2 fields : packed size and compression ration
1266 nextWord(line); nextWord(line);
1267 // date & time
1268 QString d = nextWord(line);
1269 int year = 1900 + d.mid(6, 2).toInt();
1270 if (year < 1930)
1271 year += 100;
1272 QDate qdate(year, d.mid(3, 2).toInt(), d.mid(0, 2).toInt());
1273 QString t = nextWord(line);
1274 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0);
1275 time = QDateTime(qdate, qtime).toTime_t();
1276 // checksum : ignored
1277 nextWord(line);
1278 // full name
1279 fullName = nextWord(line, '\n');
1280
1281 if (perm.length() == 7) { // windows rar permission format
1282 bool isDir = (perm.at(1).toLower() == 'd');
1283 bool isReadOnly = (perm.at(2).toLower() == 'r');
1284
1285 perm = isDir ? "drwxr-xr-x" : "-rw-r--r--";
1286
1287 if (isReadOnly)
1288 perm[ 2 ] = '-';
1289 }
1290
1291 if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ;
1292 mode = parsePermString(perm);
1293 }
1294 if (arcType == "arj") {
1295 nextWord(line);
1296 // full name
1297 fullName = nextWord(line, '\n');
1298 // ignore the next 2 fields
1299 nextWord(line); nextWord(line);
1300 // size
1301 size = nextWord(line).toLong();
1302 // ignore the next 2 fields
1303 nextWord(line); nextWord(line);
1304 // date & time
1305 QString d = nextWord(line);
1306 int year = 1900 + d.mid(0, 2).toInt();
1307 if (year < 1930) year += 100;
1308 QDate qdate(year, d.mid(3, 2).toInt(), d.mid(6, 2).toInt());
1309 QString t = nextWord(line);
1310 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0);
1311 time = QDateTime(qdate, qtime).toTime_t();
1312 // permissions
1313 perm = nextWord(line);
1314 if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ;
1315 mode = parsePermString(perm);
1316 }
1317 if (arcType == "rpm") {
1318 // full name
1319 fullName = nextWord(line);
1320 // size
1321 size = nextWord(line).toULong();
1322 // date & time
1323 time = nextWord(line).toULong();
1324 // next field is md5sum, ignore it
1325 nextWord(line);
1326 // permissions
1327 mode = nextWord(line).toULong(0, 8);
1328 // Owner & Group
1329 owner = nextWord(line);
1330 group = nextWord(line);
1331 // symlink destination
1332 #ifndef Q_WS_WIN
1333 if (S_ISLNK(mode)) {
1334 // ignore the next 3 fields
1335 nextWord(line); nextWord(line); nextWord(line);
1336 symlinkDest = nextWord(line);
1337 }
1338 #endif
1339 }
1340 if (arcType == "gzip") {
1341 if (!lineNo) return; //ignore the first line
1342 // first field is uncompressed size - ignore it
1343 nextWord(line);
1344 // size
1345 size = nextWord(line).toULong();
1346 // ignore the next field
1347 nextWord(line);
1348 // full name
1349 fullName = nextWord(line);
1350 fullName = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1);
1351 }
1352 if (arcType == "lzma") {
1353 fullName = arcFile->name();
1354 if (fullName.endsWith(QLatin1String("lzma"))) {
1355 fullName.truncate(fullName.length() - 5);
1356 }
1357 mode = arcFile->mode();
1358 size = arcFile->size();
1359 }
1360 if (arcType == "xz") {
1361 fullName = arcFile->name();
1362 if (fullName.endsWith(QLatin1String("xz"))) {
1363 fullName.truncate(fullName.length() - 3);
1364 }
1365 mode = arcFile->mode();
1366 size = arcFile->size();
1367 }
1368 if (arcType == "bzip2") {
1369 // There is no way to list bzip2 files, so we take our information from
1370 // the archive itself...
1371 fullName = arcFile->name();
1372 if (fullName.endsWith(QLatin1String("bz2"))) {
1373 fullName.truncate(fullName.length() - 4);
1374 }
1375 mode = arcFile->mode();
1376 size = arcFile->size();
1377 }
1378 if (arcType == "lha") {
1379 // permissions
1380 perm = nextWord(line);
1381 if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ;
1382 mode = parsePermString(perm);
1383 // ignore the next field
1384 nextWord(line);
1385 // size
1386 size = nextWord(line).toLong();
1387 // ignore the next field
1388 nextWord(line);
1389 // date & time
1390 int month = (QString("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec").split(',')).indexOf(nextWord(line)) + 1;
1391 int day = nextWord(line).toInt();
1392 int year = QDate::currentDate().year();
1393 QString third = nextWord(line);
1394 QTime qtime;
1395
1396 if (third.contains(":"))
1397 qtime = QTime::fromString(third);
1398 else
1399 year = third.toInt();
1400
1401 QDate qdate(year, month, day);
1402
1403 time = QDateTime(qdate, qtime).toTime_t();
1404 // full name
1405 fullName = nextWord(line, '\n');
1406 }
1407 if (arcType == "ace") {
1408 // date & time
1409 QString d = nextWord(line);
1410 int year = 1900 + d.mid(6, 2).toInt();
1411 if (year < 1930) year += 100;
1412 QDate qdate(year, d.mid(3, 2).toInt(), d.mid(0, 2).toInt());
1413 QString t = nextWord(line);
1414 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0);
1415 time = QDateTime(qdate, qtime).toTime_t();
1416 // ignore the next field
1417 nextWord(line);
1418 // size
1419 size = nextWord(line).toLong();
1420 // ignore the next field
1421 nextWord(line);
1422 // full name
1423 fullName = nextWord(line, '\n');
1424 if (fullName[ 0 ] == '*') // encrypted archives starts with '*'
1425 fullName = fullName.mid(1);
1426 }
1427 if (arcType == "deb") {
1428 // permissions
1429 perm = nextWord(line);
1430 mode = parsePermString(perm);
1431 // Owner & Group
1432 owner = nextWord(line, DIR_SEPARATOR_CHAR);
1433 group = nextWord(line).mid(1);
1434 // size
1435 size = nextWord(line).toLong();
1436 // date & time
1437 QString d = nextWord(line);
1438 QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt());
1439 QString t = nextWord(line);
1440 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0);
1441 time = QDateTime(qdate, qtime).toTime_t();
1442 // full name
1443 fullName = nextWord(line, '\n').mid(1);
1444 //if ( fullName.right( 1 ) == "/" ) return;
1445 if (fullName.contains("->")) {
1446 symlinkDest = fullName.mid(fullName.indexOf("->") + 2);
1447 fullName = fullName.left(fullName.indexOf("->") - 1);
1448 }
1449 }
1450 if (arcType == "7z") {
1451 // date & time
1452 QString d = nextWord(line);
1453 QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt());
1454 QString t = nextWord(line);
1455 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), t.mid(6, 2).toInt());
1456 time = QDateTime(qdate, qtime).toTime_t();
1457
1458 // permissions
1459 perm = nextWord(line);
1460 bool isDir = (perm.at(0).toLower() == 'd');
1461 bool isReadOnly = (perm.at(1).toLower() == 'r');
1462 perm = isDir ? "drwxr-xr-x" : "-rw-r--r--";
1463 if (isReadOnly)
1464 perm[ 2 ] = '-';
1465
1466 mode = parsePermString(perm);
1467
1468 // size
1469 size = nextWord(line).toLong();
1470
1471 // ignore the next 15 characters
1472 line = line.mid(15);
1473
1474 // full name
1475 fullName = nextWord(line, '\n');
1476 }
1477
1478 if (fullName.right(1) == DIR_SEPARATOR) fullName = fullName.left(fullName.length() - 1);
1479 if (!fullName.startsWith(DIR_SEPARATOR)) fullName = DIR_SEPARATOR + fullName;
1480 QString path = fullName.left(fullName.lastIndexOf(DIR_SEPARATOR) + 1);
1481 // set/create the directory UDSEntryList
1482 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(path);
1483 if (itef == dirDict.end())
1484 dir = addNewDir(path);
1485 else
1486 dir = itef.value();
1487
1488 QString name = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1);
1489 // file name
1490 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_NAME, name);
1491 // file type
1492 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only
1493 // file permissions
1494 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only
1495 // file size
1496 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_SIZE, size);
1497 // modification time
1498 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_MODIFICATION_TIME, time);
1499 // link destination
1500 if (!symlinkDest.isEmpty()) {
1501 entry.UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_LINK_DEST, symlinkDest);
1502 }
1503 if (S_ISDIR(mode)) {
1504 fullName = fullName + DIR_SEPARATOR;
1505 if (dirDict.find(fullName) == dirDict.end())
1506 dirDict.insert(fullName, new UDSEntryList());
1507 else {
1508 // try to overwrite an existing entry
1509 UDSEntryList::iterator entryIt;
1510
1511 for (entryIt = dir->begin(); entryIt != dir->end(); ++entryIt) {
1512 if (entryIt->contains(KIO::UDSEntry::UDS_NAME) &&
1513 entryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name) {
1514 entryIt->UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_MODIFICATION_TIME, time);
1515 entryIt->UDS_ENTRY_INSERT(KIO::UDSEntry::UDS_ACCESS, mode);
1516 return;
1517 }
1518 }
1519 return; // there is already an entry for this directory
1520 }
1521 }
1522
1523 // multi volume archives can add a file twice, use only one
1524 UDSEntryList::iterator dirEntryIt;
1525
1526 for (dirEntryIt = dir->begin(); dirEntryIt != dir->end(); ++dirEntryIt)
1527 if (dirEntryIt->contains(KIO::UDSEntry::UDS_NAME) &&
1528 dirEntryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name)
1529 return;
1530
1531 dir->append(entry);
1532 }
1533
initArcParameters()1534 bool kio_krarcProtocol::initArcParameters()
1535 {
1536 KRFUNC;
1537 KRDEBUG("arcType: " << arcType);
1538
1539 noencoding = false;
1540
1541 cmd.clear();
1542 listCmd = QStringList();
1543 getCmd = QStringList();
1544 copyCmd = QStringList();
1545 delCmd = QStringList();
1546 putCmd = QStringList();
1547 renCmd = QStringList();
1548
1549 if (arcType == "zip") {
1550 noencoding = true;
1551 cmd = fullPathName("unzip");
1552 listCmd << fullPathName("unzip") << "-ZTs-z-t-h";
1553 getCmd << fullPathName("unzip") << "-p";
1554 copyCmd << fullPathName("unzip") << "-jo";
1555
1556 if (QStandardPaths::findExecutable(QStringLiteral("zip")).isEmpty()) {
1557 delCmd = QStringList();
1558 putCmd = QStringList();
1559 } else {
1560 delCmd << fullPathName("zip") << "-d";
1561 putCmd << fullPathName("zip") << "-ry";
1562 }
1563
1564 if (!QStandardPaths::findExecutable(QStringLiteral("7za")).isEmpty()) {
1565 renCmd << fullPathName("7za") << "rn";
1566 }
1567
1568 if (!getPassword().isEmpty()) {
1569 getCmd << "-P" << password;
1570 copyCmd << "-P" << password;
1571 putCmd << "-P" << password;
1572 }
1573 } else if (arcType == "rar") {
1574 noencoding = true;
1575 if (QStandardPaths::findExecutable(QStringLiteral("rar")).isEmpty()) {
1576 cmd = fullPathName("unrar");
1577 listCmd << fullPathName("unrar") << "-c-" << "-v" << "v";
1578 getCmd << fullPathName("unrar") << "p" << "-ierr" << "-idp" << "-c-" << "-y";
1579 copyCmd << fullPathName("unrar") << "e" << "-y";
1580 delCmd = QStringList();
1581 putCmd = QStringList();
1582 } else {
1583 cmd = fullPathName("rar");
1584 listCmd << fullPathName("rar") << "-c-" << "-v" << "v";
1585 getCmd << fullPathName("rar") << "p" << "-ierr" << "-idp" << "-c-" << "-y";
1586 copyCmd << fullPathName("rar") << "e" << "-y";
1587 delCmd << fullPathName("rar") << "d";
1588 putCmd << fullPathName("rar") << "-r" << "a";
1589 }
1590 if (!getPassword().isEmpty()) {
1591 getCmd << QString("-p%1").arg(password);
1592 listCmd << QString("-p%1").arg(password);
1593 copyCmd << QString("-p%1").arg(password);
1594 if (!putCmd.isEmpty()) {
1595 putCmd << QString("-p%1").arg(password);
1596 delCmd << QString("-p%1").arg(password);
1597 }
1598 }
1599 } else if (arcType == "rpm") {
1600 cmd = fullPathName("rpm");
1601 listCmd << fullPathName("rpm") << "--dump" << "-lpq";
1602 getCmd << fullPathName("cpio") << "--force-local" << "--no-absolute-filenames" << "-iuvdF";
1603 delCmd = QStringList();
1604 putCmd = QStringList();
1605 copyCmd = QStringList();
1606 } else if (arcType == "gzip") {
1607 cmd = fullPathName("gzip");
1608 listCmd << fullPathName("gzip") << "-l";
1609 getCmd << fullPathName("gzip") << "-dc";
1610 copyCmd = QStringList();
1611 delCmd = QStringList();
1612 putCmd = QStringList();
1613 } else if (arcType == "bzip2") {
1614 cmd = fullPathName("bzip2");
1615 listCmd << fullPathName("bzip2");
1616 getCmd << fullPathName("bzip2") << "-dc";
1617 copyCmd = QStringList();
1618 delCmd = QStringList();
1619 putCmd = QStringList();
1620 } else if (arcType == "lzma") {
1621 cmd = fullPathName("lzma");
1622 listCmd << fullPathName("lzma");
1623 getCmd << fullPathName("lzma") << "-dc";
1624 copyCmd = QStringList();
1625 delCmd = QStringList();
1626 putCmd = QStringList();
1627 } else if (arcType == "xz") {
1628 cmd = fullPathName("xz");
1629 listCmd << fullPathName("xz");
1630 getCmd << fullPathName("xz") << "-dc";
1631 copyCmd = QStringList();
1632 delCmd = QStringList();
1633 putCmd = QStringList();
1634 } else if (arcType == "arj") {
1635 cmd = fullPathName("arj");
1636 listCmd << fullPathName("arj") << "v" << "-y" << "-v";
1637 getCmd << fullPathName("arj") << "-jyov" << "-v" << "e";
1638 copyCmd << fullPathName("arj") << "-jyov" << "-v" << "e";
1639 delCmd << fullPathName("arj") << "d";
1640 putCmd << fullPathName("arj") << "-r" << "a";
1641 if (!getPassword().isEmpty()) {
1642 getCmd << QString("-g%1").arg(password);
1643 copyCmd << QString("-g%1").arg(password);
1644 putCmd << QString("-g%1").arg(password);
1645 }
1646 } else if (arcType == "lha") {
1647 cmd = fullPathName("lha");
1648 listCmd << fullPathName("lha") << "l";
1649 getCmd << fullPathName("lha") << "pq";
1650 copyCmd << fullPathName("lha") << "eif";
1651 delCmd << fullPathName("lha") << "d";
1652 putCmd << fullPathName("lha") << "a";
1653 } else if (arcType == "ace") {
1654 cmd = fullPathName("unace");
1655 listCmd << fullPathName("unace") << "v";
1656 getCmd << fullPathName("unace") << "e" << "-o";
1657 copyCmd << fullPathName("unace") << "e" << "-o";
1658 delCmd = QStringList();
1659 putCmd = QStringList();
1660 if (!getPassword().isEmpty()) {
1661 getCmd << QString("-p%1").arg(password);
1662 copyCmd << QString("-p%1").arg(password);
1663 }
1664 } else if (arcType == "deb") {
1665 cmd = fullPathName("dpkg");
1666 listCmd << fullPathName("dpkg") << "-c";
1667 getCmd << fullPathName("tar") << "xvf";
1668 copyCmd = QStringList();
1669 delCmd = QStringList();
1670 putCmd = QStringList();
1671 } else if (arcType == "7z") {
1672 noencoding = true;
1673 cmd = fullPathName("7z");
1674 if (QStandardPaths::findExecutable(cmd).isEmpty())
1675 cmd = fullPathName("7za");
1676
1677 listCmd << cmd << "l" << "-y";
1678 getCmd << cmd << "e" << "-y";
1679 copyCmd << cmd << "e" << "-y";
1680 delCmd << cmd << "d" << "-y";
1681 putCmd << cmd << "a" << "-y";
1682 renCmd << cmd << "rn";
1683 if (!getPassword().isEmpty()) {
1684 getCmd << QString("-p%1").arg(password);
1685 listCmd << QString("-p%1").arg(password);
1686 copyCmd << QString("-p%1").arg(password);
1687 if (!putCmd.isEmpty()) {
1688 putCmd << QString("-p%1").arg(password);
1689 delCmd << QString("-p%1").arg(password);
1690 }
1691 }
1692 }
1693 // checking if it's an absolute path
1694 #ifdef Q_WS_WIN
1695 if (cmd.length() > 2 && cmd[ 0 ].isLetter() && cmd[ 1 ] == ':')
1696 return true;
1697 #else
1698 if (cmd.startsWith(DIR_SEPARATOR))
1699 return true;
1700 #endif
1701 if (QStandardPaths::findExecutable(cmd).isEmpty()) {
1702 error(KIO::ERR_CANNOT_LAUNCH_PROCESS,
1703 cmd +
1704 i18n("\nMake sure that the %1 binary is installed properly on your system.", cmd));
1705 KRDEBUG("Failed to find cmd: " << cmd);
1706 return false;
1707 }
1708 return true;
1709 }
1710
checkStatus(int exitCode)1711 bool kio_krarcProtocol::checkStatus(int exitCode)
1712 {
1713 KRFUNC;
1714 KRDEBUG(exitCode);
1715 return KrArcBaseManager::checkStatus(arcType, exitCode);
1716 }
1717
checkIf7zIsEncrypted(bool & encrypted,QString fileName)1718 void kio_krarcProtocol::checkIf7zIsEncrypted(bool &encrypted, QString fileName)
1719 {
1720 KRFUNC;
1721 if (encryptedArchPath == fileName)
1722 encrypted = true;
1723 else { // we try to find whether the 7z archive is encrypted
1724 // this is hard as the headers are also compressed
1725 QString tester = fullPathName("7z");
1726 if (QStandardPaths::findExecutable(tester).isEmpty()) {
1727 KRDEBUG("A 7z program was not found");
1728 tester = fullPathName("7za");
1729 if (QStandardPaths::findExecutable(tester).isEmpty()) {
1730 KRDEBUG("A 7za program was not found");
1731 return;
1732 }
1733 }
1734
1735 QString testCmd = tester + " t -y ";
1736 lastData = encryptedArchPath = "";
1737
1738 KrLinecountingProcess proc;
1739 proc << testCmd << fileName;
1740 connect(&proc, SIGNAL(newOutputData(KProcess *, QByteArray &)),
1741 this, SLOT(checkOutputForPassword(KProcess *, QByteArray &)));
1742 proc.start();
1743 proc.waitForFinished();
1744 encrypted = this->encrypted;
1745
1746 if (encrypted)
1747 encryptedArchPath = fileName;
1748 }
1749 }
1750
checkOutputForPassword(KProcess * proc,QByteArray & buf)1751 void kio_krarcProtocol::checkOutputForPassword(KProcess * proc, QByteArray & buf)
1752 {
1753 KRFUNC;
1754 QString data = QString(buf);
1755
1756 QString checkable = lastData + data;
1757
1758 QStringList lines = checkable.split('\n');
1759 lastData = lines[ lines.count() - 1 ];
1760 for (int i = 0; i != lines.count(); i++) {
1761 QString line = lines[ i ].trimmed().toLower();
1762 int ndx = line.indexOf("testing");
1763 if (ndx >= 0)
1764 line.truncate(ndx);
1765 if (line.isEmpty())
1766 continue;
1767
1768 if (line.contains("password") && line.contains("enter")) {
1769 KRDEBUG("Encrypted 7z archive found!");
1770 encrypted = true;
1771 proc->kill();
1772 return;
1773 }
1774 }
1775 }
1776
invalidatePassword()1777 void kio_krarcProtocol::invalidatePassword()
1778 {
1779 KRFUNC;
1780 KRDEBUG(getPath(arcFile->url(), QUrl::StripTrailingSlash) + DIR_SEPARATOR);
1781
1782 if (!encrypted)
1783 return;
1784
1785 KIO::AuthInfo authInfo;
1786 authInfo.caption = i18n("Krarc Password Dialog");
1787 authInfo.username = "archive";
1788 authInfo.readOnly = true;
1789 authInfo.keepPassword = true;
1790 authInfo.verifyPath = true;
1791 QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash);
1792 authInfo.url = QUrl::fromLocalFile(ROOT_DIR);
1793 authInfo.url.setHost(fileName /*.replace('/','_')*/);
1794 authInfo.url.setScheme("krarc");
1795
1796 password.clear();
1797
1798 cacheAuthentication(authInfo);
1799 }
1800
getPassword()1801 QString kio_krarcProtocol::getPassword()
1802 {
1803 KRFUNC;
1804 KRDEBUG("Encrypted: " << encrypted);
1805
1806 if (!password.isNull())
1807 return password;
1808 if (!encrypted)
1809 return (password = "");
1810
1811 KIO::AuthInfo authInfo;
1812 authInfo.caption = i18n("Krarc Password Dialog");
1813 authInfo.username = "archive";
1814 authInfo.readOnly = true;
1815 authInfo.keepPassword = true;
1816 authInfo.verifyPath = true;
1817 QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash);
1818 authInfo.url = QUrl::fromLocalFile(ROOT_DIR);
1819 authInfo.url.setHost(fileName /*.replace('/','_')*/);
1820 authInfo.url.setScheme("krarc");
1821
1822 if (checkCachedAuthentication(authInfo) && !authInfo.password.isNull()) {
1823 KRDEBUG(authInfo.password);
1824 return (password = authInfo.password);
1825 }
1826
1827 authInfo.password.clear();
1828
1829 #if KIO_VERSION_MINOR >= 24
1830 int errCode = openPasswordDialogV2(authInfo, i18n("Accessing the file requires a password."));
1831 if (!errCode && !authInfo.password.isNull()) {
1832 #else
1833 if (openPasswordDialog(authInfo, i18n("Accessing the file requires a password.")) && !authInfo.password.isNull()) {
1834 #endif
1835 KRDEBUG(authInfo.password);
1836 return (password = authInfo.password);
1837 #if KIO_VERSION_MINOR >= 24
1838 } else {
1839 error(errCode, QString());
1840 #endif
1841 }
1842
1843 KRDEBUG(password);
1844 return password;
1845 }
1846
1847 QString kio_krarcProtocol::detectFullPathName(QString name)
1848 {
1849 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1850 KRDEBUG(name);
1851
1852 name = name + EXEC_SUFFIX;
1853 QStringList path = QString::fromLocal8Bit(qgetenv("PATH")).split(':');
1854
1855 for (QStringList::Iterator it = path.begin(); it != path.end(); ++it) {
1856 if (QDir(*it).exists(name)) {
1857 QString dir = *it;
1858 if (!dir.endsWith(DIR_SEPARATOR))
1859 dir += DIR_SEPARATOR;
1860
1861 return dir + name;
1862 }
1863 }
1864 return name;
1865 }
1866
1867 QString kio_krarcProtocol::fullPathName(QString name)
1868 {
1869 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1870 KRDEBUG(name);
1871
1872 QString supposedName = confGrp.readEntry(name, QString());
1873 if (supposedName.isEmpty())
1874 supposedName = detectFullPathName(name);
1875 return supposedName;
1876 }
1877
1878 QString kio_krarcProtocol::localeEncodedString(QString str)
1879 {
1880 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1881 if (noencoding)
1882 return str;
1883
1884 QByteArray array = codec->fromUnicode(str);
1885
1886 // encoding the byte array to QString, mapping 0x0000-0x00FF to 0xE000-0xE0FF
1887 // see KrArcCodec for more explanation
1888 int size = array.size();
1889 QString result;
1890
1891 const char *data = array.data();
1892 for (int i = 0; i != size; i++) {
1893 unsigned short ch = (((int)data[ i ]) & 0xFF) + 0xE000; // user defined character
1894 result.append(QChar(ch));
1895 }
1896 return result;
1897 }
1898
1899 QByteArray kio_krarcProtocol::encodeString(QString str)
1900 {
1901 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1902 if (noencoding)
1903 return QTextCodec::codecForLocale()->fromUnicode(str);
1904 return codec->fromUnicode(str);
1905 }
1906
1907 QString kio_krarcProtocol::decodeString(char * buf)
1908 {
1909 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1910 if (noencoding)
1911 return QTextCodec::codecForLocale()->toUnicode(buf);
1912 return codec->toUnicode(buf);
1913 }
1914
1915 QString kio_krarcProtocol::getPath(const QUrl &url, QUrl::FormattingOptions options)
1916 {
1917 // Note: KRFUNC was not used here in order to avoid filling the log with too much information
1918 QString path = url.adjusted(options).path();
1919 REPLACE_DIR_SEP2(path);
1920
1921 #ifdef Q_WS_WIN
1922 if (path.startsWith(DIR_SEPARATOR)) {
1923 int p = 1;
1924 while (p < path.length() && path[ p ] == DIR_SEPARATOR_CHAR)
1925 p++;
1926 /* /C:/Folder */
1927 if (p + 2 <= path.length() && path[ p ].isLetter() && path[ p + 1 ] == ':') {
1928 path = path.mid(p);
1929 }
1930 }
1931 #endif
1932 return path;
1933 }
1934
1935 #endif // KRARC_ENABLED
1936